Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > разработка игр, графический дизайн и моделирование > Gamedev - cоздание игр: Unity, OpenGL, DirectX
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.05.2008, 11:21   #11
Da$aD
Пользователь
 
Регистрация: 04.04.2008
Сообщений: 15
По умолчанию

Извините, а на VB 6 так можно сделать (чтобы не мигали картинки при движении)?
Da$aD вне форума Ответить с цитированием
Старый 02.05.2008, 19:09   #12
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

"Мигание" возникает когда
а) перед прорисовкой по сообщению WM_PAINT "нужного" изображения перерисовывается фон окна по сообщению WM_ERASEBKGND, стандартная оконная процедура использует для это кисть класса окна,
б) когда дочернее окно движется по родительскому,
в) когда находящиеся на одном родительском окне несколько дочерних окон "залазят" друг на друга.

Двойная буферизация (она же стиль WS_EX_COMPOSITED) в данном случае не лучший выход, к тому же она поддерживается минимум в Windows XP. Выходов из положения, как всегда, несколько.
1. Убрать кисть окна. Либо при регистрации класса, либо через SetClassLong.
2. Обрабатывать должным образом WM_ERASEBKGND. Я, например, обычно в таких случаях делаю функцию, которая рисует содержимое окна в пределах нужного прямоугольника и беру его либо из структуры PAINTSTRUCT для WM_PAINT, либо из GetUpdateRect для WM_ERASEBKGND. Здесь, правда, речь идёт о WinAPI, о тонкостях реализации в рамках VCL никогда не думал.
3. Установить для главного окна стиль WS_CLIPCHILDREN, и/или для дочерних окон стиль WS_CLIPSIBLINGS.
Все эти способы работают во всех версиях Windows, и, если есть необходимость, могу продемонстрировать их исполнение на C в пределах Win API или MFC. Что касается других языков или библиотек классов, не думаю, что здесь должны возникнуть какие-то принципиальные сложности....
B_N вне форума Ответить с цитированием
Старый 02.05.2008, 21:32   #13
mutabor
Телепат с дипломом
Старожил
 
Аватар для mutabor
 
Регистрация: 10.06.2007
Сообщений: 4,929
По умолчанию

Другой способ (не касаясь WM_ERASEBKGND)
Общий принцип такой - не перерисовывать а рисовать. Создайте битмап-буфер и рисуйте в нем, и целиком его на экран выводите вместо события перерисовки.
The future is not a tablet with a 9" screen no more than the future was a 9" black & white screen in a box. It’s the paradigm that survives. (Kroc Camen)
Проверь себя! Онлайн тестирование | Мой блог
mutabor вне форума Ответить с цитированием
Старый 03.05.2008, 07:39   #14
Da$aD
Пользователь
 
Регистрация: 04.04.2008
Сообщений: 15
По умолчанию

А можно код? Просто на словах я не очень понял.
Da$aD вне форума Ответить с цитированием
Старый 03.05.2008, 16:44   #15
Beermonza
Инженер ИС
Старожил
 
Аватар для Beermonza
 
Регистрация: 13.12.2006
Сообщений: 2,671
По умолчанию Если позволите...

Самый простой способ такой. В качестве приемника можно использовать Image или PaintBox (пусть будет Image1).
Создаем битовый буфер:
Код:
var
  DrawBuf: TBitmap;

...

procedure TForm1.FormCreate(Sender: TObject);
begin
// создаем буфер
  DrawBuf:=TBitmap.Create;
// указываем глубину цвета (лучше это делать)
  DrawBuf.PixelFormat:=pf24bit; // (pf8bit, pf16bit, pf24bit, pf32bit)
// указываем размеры буфера
  DrawBuf.Width:=Image1.Width;
  DrawBuf.Height:=Image1.Height;
end;

...

// процедура рисования в буфере
procedure TForm1.DrawInBuf;
begin
  // по количеству объектов
  for i=0 to N-1 do
  // тут циклы и условия где должен быть очередной объект  
    begin
  // рисовать в буфере через канву
      DrawBuf.Canvas.Draw(x,y,{n-ый объект, картинка TBitmap});
    end;
end;

...

// вывод готового кадра в Image1
procedure TForm1.Timer1Timer(Sender: TObject);
begin
   DrawInBuf;
   Image1.Picture.Bitmap.Canvas.Draw(0,0,DrawBuf);
end;
Сменой интервала таймера можно регулировать количество кадров.
Данный метод достаточно медленный, есть и более быстрый с использованием битовых буферов и рисования в ОЗУ.
Руководитель проекта MMO 2D RPG: Настоящее имя Денис Стрижак (10.05.1981-6.02.2019) Мир духу его

Последний раз редактировалось Beermonza; 03.05.2008 в 16:46.
Beermonza вне форума Ответить с цитированием
Старый 04.05.2008, 20:49   #16
Da$aD
Пользователь
 
Регистрация: 04.04.2008
Сообщений: 15
По умолчанию

Это явно не на VB. Но все равно спасибо.
Da$aD вне форума Ответить с цитированием
Старый 04.05.2008, 22:25   #17
mutabor
Телепат с дипломом
Старожил
 
Аватар для mutabor
 
Регистрация: 10.06.2007
Сообщений: 4,929
По умолчанию

Цитата:
Сообщение от Da$aD Посмотреть сообщение
Это явно не на VB. Но все равно спасибо.
Это на Delphi (а точнее на функциях VCL), ты главное принцип пойми, в конечном итоге все равно все сводится к WinAPI. Что VB, что Delphi, что VC++ все они юзают виндовые DLL, отрисовывает винда на экран.

Причина мерцания.
Представь себе одно событие перерисовки (их может происходить много раз в секунду)
Шаг 1. Все (что подлежит перерисовке) закрашивается цветом фона.
Шаг 2. Рисуется свежее изображение.
Когда это происходит много раз в секунду и появляется мерцание. Чтобы его не было, нужно исключить первый шаг.
The future is not a tablet with a 9" screen no more than the future was a 9" black & white screen in a box. It’s the paradigm that survives. (Kroc Camen)
Проверь себя! Онлайн тестирование | Мой блог
mutabor вне форума Ответить с цитированием
Старый 05.05.2008, 22:29   #18
Da$aD
Пользователь
 
Регистрация: 04.04.2008
Сообщений: 15
По умолчанию

Принцип я понял. А какая функция используется (в смысле, требуемая библиотека и имя функции)?
Da$aD вне форума Ответить с цитированием
Старый 05.05.2008, 23:22   #19
mutabor
Телепат с дипломом
Старожил
 
Аватар для mutabor
 
Регистрация: 10.06.2007
Сообщений: 4,929
По умолчанию

Цитата:
Сообщение от Da$aD Посмотреть сообщение
Принцип я понял. А какая функция используется (в смысле, требуемая библиотека и имя функции)?
Ты это о чем? О перерисовке? Если да, то все вроде сводится к Invalidate. В Delphi например вызываешь VCL функцию Repaint она вызывает Refresh та еще какую-то, все эти вызовы переходят в более низкий уровень пока не дойдет до Invalidate.
прим. Имена функций могли быть изменены для конспирации (ну не помню я их точно по памяти)

B_N немного выше предлагал отлавливать сообщение WM_ERASEBKGND, это все из той же оперы (WinAPI)

Я бы уже давно сказал бы как сделать, но я с VB не имел дела в таких вопросах. Там ведь тоже объекты графические есть, битмап например (в памяти сидит, на экран нужно куда-то вывести), или визуальный вроде TImage дельфового, к-рый на экране виден, и картинку в себе содержит.
Так вот в Дельфи, чтобы не мерцал TImage при таскании его по экрану, достаточно задать окну двойную буферизацию. Думаю то же есть и в Бэйсике, в крайнем случае напрямую через WinAPI обратится (B_N писал как).
The future is not a tablet with a 9" screen no more than the future was a 9" black & white screen in a box. It’s the paradigm that survives. (Kroc Camen)
Проверь себя! Онлайн тестирование | Мой блог
mutabor вне форума Ответить с цитированием
Старый 06.05.2008, 00:35   #20
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Как обещал, выкладываю простенький пример, правда, (как и обещал ) на C, но на WinAPI. Полный текст и экзешник в архиве, сюда, чтобы не занимать много места, выкладываю более существенную часть. В примере реализовано движение дочернего окна по главному, движение собственно одной части картинки по другой делать пока не стал в виду тривиальности задачи...
Код:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
	case WM_CREATE:
		{
			BITMAP		bmp;
			RECT		rcTmp;

			GetObject(hShuttleBmp, sizeof(BITMAP), &bmp);
			SetRect(&rcTmp, 0, 0, bmp.bmWidth, bmp.bmHeight);

			AdjustWindowRect(
					&rcTmp, 
					GetWindowLongPtr(hWnd, GWL_STYLE), 
					TRUE);

			SetWindowPos(
					hWnd, 
					NULL, 
					0, 
					0, 
					rcTmp.right - rcTmp.left, 
					rcTmp.bottom - rcTmp.top, 
					SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
		}
		break;
	case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
				case IDM_EXIT:
					DestroyWindow(hWnd);
					break;
				default:
					return DefWindowProc(hWnd, message, wParam, lParam);
			}
		}
		break;
	case WM_ERASEBKGND:
		{
			RECT rcUpdRect;

			GetUpdateRect(hWnd, &rcUpdRect, FALSE);
			DrawMainWindow(hWnd, (HDC)wParam, &rcUpdRect);
		}
		break;
	case WM_PAINT:
		{
			HDC hdc;
			PAINTSTRUCT ps;

			hdc = BeginPaint(hWnd, &ps);
			DrawMainWindow(hWnd, hdc, &ps.rcPaint);
			EndPaint(hWnd, &ps);
		}
		break;
	case WM_LBUTTONDOWN:
		CreateWindowEx(
				0, 
				szZoomWndClass, 
				NULL,
				WS_CHILD | WS_VISIBLE | WS_DLGFRAME, 
				0, 
				0, 
				200, 
				200, 
				hWnd, 
				(HMENU)100, 
				NULL, 
				NULL);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

VOID DrawMainWindow(HWND hWnd, HDC hDC, LPRECT lprcUpdRect)
{
	HDC		hMemDC;
	HBITMAP	hTmpBmp;

	hMemDC = CreateCompatibleDC(hDC);
	hTmpBmp = (HBITMAP) SelectObject(hMemDC, hShuttleBmp);

	BitBlt(
		hDC,
		lprcUpdRect->left,
		lprcUpdRect->top,
		lprcUpdRect->right - lprcUpdRect->left,
		lprcUpdRect->bottom - lprcUpdRect->top,
		hMemDC,
		lprcUpdRect->left,
		lprcUpdRect->top,
		SRCCOPY);

	SelectObject(hMemDC, hTmpBmp);
	DeleteDC(hMemDC);
}


VOID MoveZoomWindow(HWND hWnd)
{
	RECT rcWnd;
	POINT pt;

	GetWindowRect(hWnd, &rcWnd);
	GetCursorPos(&pt);
	ScreenToClient(hMainWnd, &pt);

	SetWindowPos(
			hWnd, 
			0, 
			pt.x - ((rcWnd.right - rcWnd.left) >> 1), 
			pt.y - ((rcWnd.bottom - rcWnd.top) >> 1), 
			0, 
			0, 
			SWP_NOSIZE | SWP_NOACTIVATE |SWP_NOZORDER);
	DrawZoomWindow(hWnd);
}

VOID DrawZoomWindow(HWND hWnd)
{
	HDC			hMemDC, hdc;
	HBITMAP		hTmpBmp;
	POINT		pt;
	RECT		rcClient;
	SIZE		srcSize;
	SIZE		ClientSize;
	BITMAP		bmp;
	POINT		srcTopLeft;

	GetCursorPos(&pt);
	ScreenToClient(hMainWnd, &pt);
	GetClientRect(hWnd, &rcClient);
	
	ClientSize.cx = rcClient.right - rcClient.left;
	ClientSize.cy = rcClient.bottom - rcClient.top;

	GetObject(hShuttleBmp, sizeof(BITMAP), &bmp);
	
	srcSize.cx = ClientSize.cx / uScaleFactor;
	srcSize.cy = ClientSize.cy / uScaleFactor;

	srcTopLeft.x = pt.x - (srcSize.cx >> 1);
	srcTopLeft.y = pt.y - (srcSize.cy >> 1);

	if(srcTopLeft.x + srcSize.cx >= bmp.bmWidth) srcTopLeft.x = bmp.bmWidth - srcSize.cx;
	if(srcTopLeft.x < 0) srcTopLeft.x = 0;
	if(srcTopLeft.y + srcSize.cy >= bmp.bmHeight) srcTopLeft.y = bmp.bmHeight - srcSize.cy;
	if(srcTopLeft.y < 0) srcTopLeft.y = 0;

	hdc = GetDC(hWnd);
	hMemDC = CreateCompatibleDC(hdc);
	hTmpBmp = (HBITMAP) SelectObject(hMemDC, hShuttleBmp);
	
	StretchBlt(
		hdc,
		0,
		0,
		ClientSize.cx,
		ClientSize.cy,
		hMemDC,
		srcTopLeft.x,
		srcTopLeft.y,
		srcSize.cx,
		srcSize.cy,
		SRCCOPY);

	SelectObject(hMemDC, hTmpBmp);
	DeleteDC(hMemDC);
	ReleaseDC(hWnd, hdc);
}

LRESULT CALLBACK ZoomWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CREATE:
		PostMessage(hWnd, WM_LBUTTONDOWN, 0, 0);
		MoveZoomWindow(hWnd);
		return TRUE;
	case WM_LBUTTONDOWN:
		SetCapture(hWnd);
		break;
	case WM_LBUTTONUP:
		if(GetCapture() == hWnd) ReleaseCapture();
		break;
	case WM_CAPTURECHANGED:
		DestroyWindow(hWnd);
		break;
	case WM_MOUSEMOVE:
		MoveZoomWindow(hWnd);
		break;
	case WM_ERASEBKGND:
		return 1;
	case WM_PAINT:
		DrawZoomWindow(hWnd);
		break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}
Вложения
Тип файла: rar Magnifier.rar (615.8 Кб, 38 просмотров)
B_N вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц