Не работает двойная буферизация
От: khatsko  
Дата: 28.08.05 04:20
Оценка:
Здравствуйте. Надеюсь на помощь.
Третий день бьюсь с проблемой: не работает двойная буферизация. Думал что разбираюсь в этом аспекте. Необходимо на одном HBITMAP нарисовать другой HBITMAP и выкинуть на экран 1-ый. Особенность в том, что второй HBITMAP меняется со временем, поэтому делаю так: храню в отдельной переменной m_hBackground_src "фон", а на экран выкидываю m_hBackground_tmp. Заливаю m_hBackground_tmp начальным фоном m_hBackground_src, затем на m_hBackground_tmp рисую новый HBITMAP, и затем выкидываю m_hBackground_tmp на экран.

Проблема в том, что m_hBackground_src где-то "портится" и приобретает значение m_hBackground_tmp при каждой прорисовки m_hBackground_tmp. Т.е. получается, что фон m_hBackground_src — это уже не тот первоначальный фон, а "куча" всех наложений битмэпа который должен меняться, получается помойка. Как будто где-то стоит строка m_hBackground_src = m_hBackground_tmp. Но фон m_hBackground_src меняться нигде не должен.

Где ошибка — до сих пор не понял, перекопал каждую строчку. Вот код:

// готовим контекст: рисовать на m_hBackground_tmp

CDC dc;
dc.CreateCompatibleDC(NULL);
HBITMAP hbmMemOldBitmap = (HBITMAP) dc.SelectObject(m_hBackground_tmp);

/////////////////////////////////////////////////////////////////////////////

CRect rect;
GetClientRect(rect);

// готовим контекст: рисовать из других битмэпов

HDC hMemDC = ::CreateCompatibleDC(NULL);

// "заливаем" m_hBackground_tmp фоном m_hBackground_src

SelectObject(hMemDC, m_hBackground_src);
BitBlt(dc.m_hDC, 0, 0, -1, -1, hMemDC, -1, -1, SRCCOPY);

// здесь рисуем на m_hBackground_tmp битмэп который меняется со временем

SelectObject(hMemDC, hSecondHand_bitmap);
BitBlt(dc.m_hDC, 100, 100, -1, -1, hMemDC, -1, -1, SRCCOPY);

// вроде все отрисовали, сохраняем отрисованный битмэп в m_hBackground_tmp и восстанавливаем в контекст первоначальный битмэп hbmMemOldBitmap

m_hBackground_tmp = (HBITMAP) dc.SelectObject(hbmMemOldBitmap);
DeleteObject(hbmMemOldBitmap);
DeleteDC(hMemDC);

// сразу перерисовываем окно

RedrawWindow();

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

Отрисовка на экран:

void CMyProgDlg::OnPaint()
{
CPaintDC dc(this);

CRect rect;
GetClientRect(rect);

HDC hMemDC = ::CreateCompatibleDC(NULL);
SelectObject(hMemDC, m_hBackground_tmp);

::BitBlt(dc.m_hDC, 0, 0, rect.Width(), rect.Height(), hMemDC, 0, 0, SRCCOPY);

DeleteDC(hMemDC);
}

Как я уже писал: в итоге получается что фон m_hBackground_src где-то "перетирается" и он сохраняет все предыдущие наложения битмэпов.

Где ошибка в коде?
Re: Не работает двойная буферизация
От: goto Россия  
Дата: 30.08.05 01:32
Оценка:
Здравствуйте, khatsko, Вы писали:
...

Если память не изменяет, комбинация CreateCompatibleDC() и SelectObject(хдц, битмап) именно и приводит к тому, что вопреки ожиданиям в битмапе оказывается текущее содержимое экрана. Обойти можно 2-мя путями:

1. Src не заливать в Tmp ч-з битблит, т.е. не делать и SelectObject(src), а как-то перерисовыть src в tmp ручками. Попиксельно, переливая память и т.д.;

2. грубо хранить в памяти не битмап с чистым, незапятнанным фоном, а и контекст dcSrc и битмап bmSrc. В самом начале создать отдельный статический compatible dcSrc и статический же compatible bmSrc. В bmSrc при старте положить все, что хочешь, можно и экран битблитом (как Вы это скорее всего и делаете). И dcSrc и bmSrc хранить статически, не уничтожать, не делать с ними ничего, а покадрово или как у Вас там прямо из dcSrc плюхать в Tmp. Что-то вроде тройной буферизации. Да и побыстрее видимо будет.

Попробуйте. Я просто плохо воспринимаю Ваш код из-за смеси API и MFC (моя проблема) и форматирования здесь, в форуме (для ввода кода здесь есть внизу спецкнопки). Мог упустить что-то.

2-й способ врядли будет работать в win16 и не 100% надежно под win95 . А NT и дальше — ок.
Re[2]: Не работает двойная буферизация
От: Andrew S Россия http://alchemy-lab.com
Дата: 30.08.05 09:00
Оценка:
G>Если память не изменяет, комбинация CreateCompatibleDC() и SelectObject(хдц, битмап) именно и приводит к тому, что вопреки ожиданиям в битмапе оказывается текущее содержимое экрана. Обойти можно 2-мя путями:

Память вам изменяет.

G>1. Src не заливать в Tmp ч-з битблит, т.е. не делать и SelectObject(src), а как-то перерисовыть src в tmp ручками. Попиксельно, переливая память и т.д.;


В общем, все остальное тоже сомнительно
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: Не работает двойная буферизация
От: Кодёнок  
Дата: 30.08.05 10:08
Оценка:
Здравствуйте, khatsko, Вы писали:

K>Где ошибка — до сих пор не понял, перекопал каждую строчку. Вот код:


Хз, как-то мутно всё.

K> CDC dc;

K> dc.CreateCompatibleDC(NULL);
K> HBITMAP hbmMemOldBitmap = (HBITMAP) dc.SelectObject(m_hBackground_tmp);

K> CRect rect;

K> GetClientRect(rect);

K> HDC hMemDC = ::CreateCompatibleDC(NULL);

K> SelectObject(hMemDC, m_hBackground_src);

Вот тут — запомнить, HBITMAP hMemDCOldBitmap = SelectObject(hMemDC, m_hBackground_src);

K> BitBlt(dc.m_hDC, 0, 0, -1, -1, hMemDC, -1, -1, SRCCOPY);


K> SelectObject(hMemDC, hSecondHand_bitmap);

K> BitBlt(dc.m_hDC, 100, 100, -1, -1, hMemDC, -1, -1, SRCCOPY);

K>// вроде все отрисовали, сохраняем отрисованный битмэп в m_hBackground_tmp и восстанавливаем в контекст первоначальный битмэп hbmMemOldBitmap


K> m_hBackground_tmp = (HBITMAP) dc.SelectObject(hbmMemOldBitmap);


Вот это непонятно. Вместо этого должно быть просто dc.SelectObject(hbmMemOldBitmap), зачем ты присваиваешь m_hBackground_tmp опять?

K> DeleteObject(hbmMemOldBitmap);


Тут надо SelectObject(hMemDC, hMemDCOldBitmap)

K> DeleteDC(hMemDC);


K>// сразу перерисовываем окно


K> RedrawWindow();


Обычно либо Invalidate делают, либо рисуют напрямую на DC окна.

K>/////////////////////////////////////////////////////////////////////////////////////////////////////////////


K>Отрисовка на экран:


K>void CMyProgDlg::OnPaint()

K>{
K> CPaintDC dc(this);

K> CRect rect;

K> GetClientRect(rect);

K> HDC hMemDC = ::CreateCompatibleDC(NULL);

K> SelectObject(hMemDC, m_hBackground_tmp);

Тут надо запомнить old bitmap

K> ::BitBlt(dc.m_hDC, 0, 0, rect.Width(), rect.Height(), hMemDC, 0, 0, SRCCOPY);


Тут — SelectObject old bitmap обратно.

K> DeleteDC(hMemDC);

K>}

K>Как я уже писал: в итоге получается что фон m_hBackground_src где-то "перетирается" и он сохраняет все предыдущие наложения битмэпов.


K>Где ошибка в коде?
Re[3]: Не работает двойная буферизация
От: goto Россия  
Дата: 30.08.05 16:31
Оценка:
Здравствуйте, Andrew S, Вы писали:

G>>Если память не изменяет, комбинация CreateCompatibleDC() и SelectObject(хдц, битмап) именно и приводит к тому, что вопреки ожиданиям в битмапе оказывается текущее содержимое экрана. Обойти можно 2-мя путями:


AS>Память вам изменяет.


Да, память изменяет. Бывает. Хотя я бы проверил практически насчет SelectObject. Только ведь никто не проверит, а автор ветки куда-то делся.

G>>1. Src не заливать в Tmp ч-з битблит, т.е. не делать и SelectObject(src), а как-то перерисовыть src в tmp ручками. Попиксельно, переливая память и т.д.;


Да, я бы сам так скорее всего делать не стал (п.1), но п.2 со статическим DC будет прекрасно работать.

AS>В общем, все остальное тоже сомнительно
Re[4]: Не работает двойная буферизация
От: Andrew S Россия http://alchemy-lab.com
Дата: 30.08.05 18:50
Оценка:
G>>>Если память не изменяет, комбинация CreateCompatibleDC() и SelectObject(хдц, битмап) именно и приводит к тому, что вопреки ожиданиям в битмапе оказывается текущее содержимое экрана. Обойти можно 2-мя путями:

AS>>Память вам изменяет.


G>Да, память изменяет. Бывает. Хотя я бы проверил практически насчет SelectObject. Только ведь никто не проверит, а автор ветки куда-то делся.


Нет, не бывает, а изменяет, причем именно сейчас. И проверять там нечего, ваше утверждение неверно. Точка.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[5]: Не работает двойная буферизация
От: goto Россия  
Дата: 30.08.05 19:46
Оценка:
Здравствуйте, Andrew S, Вы писали:

G>>>>Если память не изменяет, комбинация CreateCompatibleDC() и SelectObject(хдц, битмап) именно и приводит к тому, что вопреки ожиданиям в битмапе оказывается текущее содержимое экрана. Обойти можно 2-мя путями:


AS>>>Память вам изменяет.


G>>Да, память изменяет. Бывает. Хотя я бы проверил практически насчет SelectObject. Только ведь никто не проверит, а автор ветки куда-то делся.


AS>Нет, не бывает, а изменяет, причем именно сейчас. И проверять там нечего, ваше утверждение неверно. Точка.


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