CreateCompatibleDC для линий и т.п.

Тема в разделе "WASM.WIN32", создана пользователем The Svin, 30 мар 2006.

  1. The Svin

    The Svin New Member

    Публикаций:
    0
    Регистрация:
    6 июл 2003
    Сообщения:
    665
    Адрес:
    Russia
    Насколько оправдано (и возможно ли вообще) создать CreateCompatibleDC для hDC клиентской части окна.

    В нём порисовать с помощью LineTo, TextOut, FillRect а потом полученное через BtBlt в окно выдать?

    Два вопроса

    1. Возможно ли такое

    2. Будет ли это быстрее чем просто рисовать используя hDC окошка. (Нужно довольно много линий рисовать, скорость перерисовки не устраивает)
     
  2. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Вроде это есть классический путь ускорения вывода графики.

    Иметь в памяти некий готовый шаблон рисунка, к которому добавлять модификации перед выводом на экран.
     
  3. HitmaN85

    HitmaN85 New Member

    Публикаций:
    0
    Регистрация:
    6 окт 2005
    Сообщения:
    36
    Быстрее или нет, но вывод сначала в буфер, а потом копирование на экран избаляет от моргания изображения.

    Это вообще стандартный способ для анимации через GDI/



    Если часть картинки остается постоянной,то лучше сначала в отдельном DC её нарисовать, а потом копировать в основной буфер.
     
  4. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    У меня на сайте (www.codexxi.com) есть проект с исходниками (LinePad, С++), в котором используется такая технология. Там легко можно переключаться между обычным рисованием и Double Buffer. Посмотри разницу при выводе.
     
  5. Kola

    Kola New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2004
    Сообщения:
    69
    1. Возможно, более того - так и надо

    2. Значительно быстрее
     
  6. The Svin

    The Svin New Member

    Публикаций:
    0
    Регистрация:
    6 июл 2003
    Сообщения:
    665
    Адрес:
    Russia
    Не рисуется вообще :dntknw:

    Причём в дебагере посмотрел - все функции возвращают успешное завершение.

    Что я сделал. У меня была готовая функция рисования.

    Я просто добавил после BeginPain CreateCompatibleDC

    засунул значение в регистр который во всём дальнейшем коде

    использовался как hDC

    Перед EndPaint добавил

    invoke BitBlt,loc_ps.hdc,0,0,loc_rct.right,loc_rct.bottom,ebx,0,0,SRCCOPY

    invoke DeleteDC,ebx

    rct - RECT клиентской части окна

    ebx - полученный от CreateCompatibleDC hDC

    loc_ps.hdc - это то что заполнилось от BeginPaint

    Вобщем ни фига на экране не нарисовалось.

    При этом все функции возвращали успех.
     
  7. The Svin

    The Svin New Member

    Публикаций:
    0
    Регистрация:
    6 июл 2003
    Сообщения:
    665
    Адрес:
    Russia
    Посмотрел я LinePad. Не увидел как там в Memory LineTo рисуется.

    Вобщем вот тупой код который как мне хочется должен линию наискос нарисовать. Не рисуется. Что не так?

    @@PAINT:



    invoke BeginPaint,hWnd,addr loc_ps

    mov ebx,eax

    invoke CreateCompatibleDC,eax

    mov edi,eax

    invoke MoveToEx,edi,0,0,addr loc_pt

    invoke LineTo,edi,100,100

    invoke BitBlt,ebx,0,0,400,400,edi,0,0,SRCCOPY

    invoke DeleteDC,edi

    invoke EndPaint,hWnd,addr loc_ps

    jmp @r
     
  8. Kola

    Kola New Member

    Публикаций:
    0
    Регистрация:
    23 июн 2004
    Сообщения:
    69
    The Svin

    засада в том что сначала в memory DC надо заселектить битмапку с нужной тебе цветовой глубиной (равной экранной глубине)



    MSDN говорит:

    A memory DC exists only in memory. When the memory DC is created, its display surface is exactly one monochrome pixel wide and one monochrome pixel high. Before an application can use a memory DC for drawing operations, it must select a bitmap of the correct width and height into the DC. To select a bitmap into a DC, use the CreateCompatibleBitmap function, specifying the height, width, and color organization required.



    When a memory DC is created, all attributes are set to normal default values. The memory DC can be used as a normal DC. You can set the attributes; obtain the current settings of its attributes; and select pens, brushes, and regions.
     
  9. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    The Svin



    В аттаче пример заливки градиентом memory hdc, рисования в нем кучи линий и кривых, и вывод в hdc окна.



    P.S.

    Экспериментально обнаружил, что hDC получаемый при wm_paint по BeginPaint, отличается от hDC получаемого по GetDC. Поэтому пользуюсь только GetDC. Т.е. вызываю BeginPaint и тут же GetDC. hDC беру от второго.



    [​IMG] 101564767__Gradient.zip
     
  10. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Вот ещё пример с Memory hdc.



    Поресайзь окошко, посмотри, как перерисовывается текст.

    В этом примере видна разница между hDC, получаемым по BeginPaint и hDC от GetDC (закомментируй getDC/ReleaseDC и посмотри)



    [​IMG] 977441906__MemDC.zip
     
  11. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    cresta



    Естественно. BeginPaint не просто возвращает DC, а ещё и задаёт оптимальную область перерисовки (update rect). Зря Вы вызываете GetDC после BeginPaint!



    The Svin

    Как правильно заметил Kola, в memory DC сначала нужно поместить битмап 400x400. Этот битмап можно создать через CreateCompatibleBitmap, но параметр DC для этой функции должен быть экранный DC (который вернул BeginPaint), а не memory DC! Иначе картинка будет Ч/Б.
     
  12. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Quantum

    А почему бы самому не попробовать закомментировать GetDC в примере и посмотреть разницу?

    Если hdc получен от BeginPaint, то рисунок не перерисовывается. Да и рект здесь ни при чём.



    Так что не зря после BeginPaint вызывается GetDC :)
     
  13. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    cresta



    В том примере столько макросов, что нет особого желания даже пытаться его скомпилировать. Но пара багов всё-таки бросились в глаза:


    Код (Text):
    1. invoke DeleteObject,hBmp


    hBmp всё ещё находится в DC. Удалять можно только после освобождения из DC.


    Код (Text):
    1. invoke DeleteObject,hFont


    Аналогично


    Код (Text):
    1. mov hBrush,FUNC(GetStockObject,LTGRAY_BRUSH)
    2. invoke FillRect,memDC,ADDR mRct,hBrush
    3. invoke DeleteObject,hBrush


    То, что возвращает GetStockObject удалять не нужно.





    Из этого следует заключить, что в коде допущена ошибка. Дайте мне экзешник или листинг без HLA-ма и я скажу Вам где ошибка.



    Пардон! Не заметил, что экзешник в архиве. Сейчас посмотрим...



    Посмотрел. Без GetDC и ReleaseDC работает без проблем.





    Это к тому, что DC от BeginPaint имеет основания отличаться от GetDC.
     
  14. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Пардон! Не заметил, что экзешник в архиве. Сейчас посмотрим...

    Посмотрел. Без GetDC и ReleaseDC работает без проблем.




    Экзешник, который в примере - он как раз с GetDC и ReleaseDC. Именно поэтому и работает без проблем.

    :)))))))))))



    Если вы так внимательно смотрели код, что нашли удаление объекта от GetStockObject, то может найдёте, почему hDC полученные от BeginPaint и GetDC различаются. Уверяю, если внимательно посмотреть код (второго аттача), то причина станет ясна.

    А если BeginPaint'овый hDC вам не скомпилить никак, то вот его рисунок (с закомментированным GetDC):
     
  15. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Никак не цепляется рисунок :dntknw:





    [​IMG]
     
  16. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    cresta



    Да, я заметил этот факт в OllyDbg перед тем как забил нопами лишние вызовы GetDC и ReleaseDC. Как ни странно, после этого пример работал на моей XP SP2 также, как и до исправления. Странность заключается в том, что Вы должны возвращать 0 (zero) после обработки WM_PAINT, но возвращаете TRUE, а приложение всё равно работает. Очевидно, это и есть тот самый баг, о котором я упомянул в предыдущем сообщении.





    Это мелочь. Баги с hBmp и hFont гораздо серьёзнее.





    Я уже дважды объяснил почему они различаются (см. выше).
     
  17. The Svin

    The Svin New Member

    Публикаций:
    0
    Регистрация:
    6 июл 2003
    Сообщения:
    665
    Адрес:
    Russia


    Это я догадался.

    Мне что не нравится - при этой практике изменяется цвет окна.

    Мне хочется рисовать линии, заполнять прямоугольники, но то что я не зарисовал - хочется чтоб оставалось такого же цвета как и у окна. Т.е. работать через CompatibleDC но с тем же эффектом что и при обычном рисовании в контекст окна. Вот например рисую я, используя контекст окна, линию под каким то статиком. Линия она рисуется а окно помимо места где что то нарисовано, остаётся того же дефолтного цвета, что и было бы без рисования.

    Здесь же CompatibleBitmap когд селектится, фон получается у меня чёрного цвета. Причём попытка вернуть фон через SelectObject c цветом кисти какую хочу - не даёт никакого эффекта. Вот могу я как бы "сфотографировать" в эту саму CompatibleBitmap то что содержит окошко? Т.е. дефолтный вид окошка какой он был бы если бы в нём не рисовали?

    Может даже не это, что -то другой.

    Просто повторюсь - я хотел бы рисовать в память так же как в окно. Выбор битмапа полученного через CreateCompatibleBitmap отличается от желаемого тем, что меняется цвет фона.
     
  18. The Svin

    The Svin New Member

    Публикаций:
    0
    Регистрация:
    6 июл 2003
    Сообщения:
    665
    Адрес:
    Russia


    Это я догадался.

    Мне что не нравится - при этой практике изменяется цвет окна.

    Мне хочется рисовать линии, заполнять прямоугольники, но то что я не зарисовал - хочется чтоб оставалось такого же цвета как и у окна. Т.е. работать через CompatibleDC но с тем же эффектом что и при обычном рисовании в контекст окна. Вот например рисую я, используя контекст окна, линию под каким то статиком. Линия она рисуется а окно помимо места где что то нарисовано, остаётся того же дефолтного цвета, что и было бы без рисования.

    Здесь же CompatibleBitmap когд селектится, фон получается у меня чёрного цвета. Причём попытка вернуть фон через SelectObject c цветом кисти какую хочу - не даёт никакого эффекта. Вот могу я как бы "сфотографировать" в эту саму CompatibleBitmap то что содержит окошко? Т.е. дефолтный вид окошка какой он был бы если бы в нём не рисовали?

    Может даже не это, что -то другой.

    Просто повторюсь - я хотел бы рисовать в память так же как в окно. Выбор битмапа полученного через CreateCompatibleBitmap отличается от желаемого тем, что меняется цвет фона.
     
  19. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Quantum



    Это не правильное объяснение разницы в свойствах hDC.



    Собака зарыта вот где:

    Вызов GetDC позволяет избавиться от обработки WM_ERASEBKGND (необходимости работать с бэкграундом, например заливать его, рисовать и т.п.)

    Во втором аттаче код WM_ERASEBKGND закомментирован.

    Если снять комменты c WM_ERASEBKGND и закомментировать GetDC, то всё будет рисоваться нормально. Но это лишняя работа кода.

    Поэтому WM_ERASEBKGND был принесен в жертву. Побочный эффект - нужно получить hDC через GetDC. Я посчитал, что вызвать GetDC - меньшее зло, чем обрабатывать WM_ERASEBKGND



    The Svin



    Когда битмап только проселектирован в hDC, в нем нет рисунка, он пустой, поэтому фон черного цвета.

    Его нужно залить нужным цветом.

    Установить цвет фона compatibleDC можно так:

    CreateCompatibleDC

    CreateCompatibleBitmap

    SelectObject, memDC, hBmp

    ;тут сделать нужного цвета кисть

    ;например через GetClassLong,hwnd,GCL_HBRBACKGROUND

    ;или напрямую CreateSolidBrush

    ;и залить фон:

    FillRect,memDC,hBrush



    В аттаче так и устанавливается фон memDC.
     
  20. The Svin

    The Svin New Member

    Публикаций:
    0
    Регистрация:
    6 июл 2003
    Сообщения:
    665
    Адрес:
    Russia
    Нет рисуется всё нормально. А значит и FillRect работает.

    Но мне это не очень нравится. Прийдётся полность рисовать с помощью FillRect на всё (довольно большое) окно а потом поверх этого рисовать другие прямоугольные области опять же с FillRect. Т.е. получается лишние работы.

    Пока из того что я понял получается такая разница.

    Если бы мне нужно было рисовать в некой прямоугольной плоскости (прямоугольном участке окна не занятом другими элементами) то модель у меня вырисовывается. Я создаю контекст в памяти. Выделяю тут битмап. Рисую в нём что надо и показываю на нужном участке окна с помощью BitBlt.

    Тут всего лишь несколько строчек кода нужно было бы изменить в имеющемся.

    Но вот когда я рисую просто в контекст окна, я рисую те же линии,кружки, закрашиваю прямоугольники в уже как бы созданном битмапе, создающимся контекстом.

    В этом различие.

    Беда ещё в том, что графики рисуются в диалоге.

    В нормальном окне я бы установил OWN_DC и не парился каждый раз выбирая объекты в окно. Но с диалогами я наблюдал постоянно глюки (в каждой OS свои) когда переустанавливаешь на OWN_DC.

    Мне почему то кажется жутко не эргономичным, каждый раз при перерисовке селектить битмап, закрашивать его полностью, и потом только начинать рисовать.

    Когда это статичные изображения с несколькими красивыми рамочками, подписями и битмап-картинками - там это не принципиально. Но у меня сложные графики сигналов, рисуются тысячи линий, пересечений, меняются тексты и т.п.

    и это всё должно скролится (т.е. изменяться) довольно быстро. А мне для того чтоб изменять нужно ещё какую-то лишнюю закраску делать. Может я привередничаю конечно..