Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > alexcon314

Оценить эту запись

Пишем свою оболочку для FP под Windows. Шаг 4.

Запись от alexcon314 размещена 18.05.2011 в 11:08
Обновил(-а) alexcon314 18.05.2011 в 12:49

Без окон, без дверей....

Прозрачный (transparent) режим работы плеера по другому еще называется windowless («без-оконный»). В обычном «оконном» режиме плеер создает себе окошко и рисует себе.. уютно так, по-домашнему. В без-оконном режиме плеер пытается рисовать на всем, что ему дадут. Разницу улавливаете? Т.е. Нам самим придется позаботиться о том, чтобы предоставить плееру окно для отрисовки графики.
Это может быть обычное окно. Давайте попробуем, что выйдет, прямо в проекте с предыдущего шага:
Код AS3:
//  MyFlash.cpp 
void MyFlash::init()
{
	WCHAR ver[16]={0};
	GetInstallVersion(ver);	
	CreateHostWindow();
	SetWindowSize(550,600);
	CenterWindow();
	SetWindowText(ver);
	CreateInstance(ID_OCX,L"BIN");
	SetWMODE(WMODE_TRANSPARENT);
	AttachControl();
	LoadMovie(ID_SWF2,L"BIN");
}
Опа.. фон исчез! Кнопки, текстфилды — все на черном. Так-так.. Размышляем логически:
WMODE_TRANSPARENT исключает из отрисовки фон мувика, каким бы он ни был, стало быть, нам нужно дать плееру такое окно для рисования, которое само по-себе не обладает фоном, т.е. является прозрачным. На прозрачном окне плеер отрисует контент без фона..и получим то что надо! Только где его взять, такое окно?

Слоеное тесто: Layered Window

Начиная с XP ( могу ошибиться, но в 2000 вроде не было еще этого) Windows заимела особую часть графической подсистемы, благодаря которой стало возможно рисовать не просто окна, а полупрозрачные окна. Эта фича была задумана для такой, вобщем-то, не самой ходовой операции, как перетаскивание иконок файлов и папок. Помните? Да, при драге иконка “полурастворяется”. Красота! Но раз иконку можно “растворить”, то можно то же самое сделать и с обычным окном. Это пол-дела. MS пошел дальше. Был сделан специальный тип окна, не имеющий собственного фона, рамки, но на нем можно рисовать, накладывая один слой графики на другой, и при этом еще используется pixel-blending с учетом альфы. И все это делает сама ось, без дополнительного программинга!
Слоенеое окно действительно отличается от обычных окон. Ко всему прочему, оно не получает от системы сообщения WM_PAINT, которое “заставляет” обычные окна немедленно отрисовывать свой контент. Стало быть, отрисовкой в слоеном окне придется заниматься вручную, например – по таймеру. Теперь об алгоритме отрисовки.
Windows GDI (Graphical Device Interface) зиждется на таком фундаментальном понятии как контекст устройства (Device Context, DC). Условно говоря, под DC можно понимать все, на чем можно рисовать – экран монитора, принтер... э...что там еще? Ну, вы поняли.
Для работы с DC в WinAPI есть рад функций, которые, собственно, и составляют основу GDI, это так называемые “могучие” BLT-функции (они правда могучие, это не сарказм).
Например, BitBlt(). Она позволяет скопировать графику из одного контекста в другой.
Понимаете к чему я клоню? Да! В Windows GDI можно рисовать не только на “реальных” DC, но и на виртуальных. Представьте, мы спокойно отрисовываем в память все что надо, слой за слоем, а потом, когда все будет готово, отправляем рисунок на экран монитора. Здорово!
Для работы с Layered Window существует специальная функция UpdateLayeredWindow()
Она-то и сделает за нас всю работу-отрисует виртуальный контекст в реальный на монитор. Итак, вот что выходит. Создаем слоеное окно, заводим таймер и на каждом его тике делаем следующее:
- создаем виртуальный контекст
- даем плееру в него отрисоваться
- переносим все на контекст окна
- зачищаемся (удаляем виртуальный контекст)
Хм.. а почему не дать плееру рисовать прямо в окно? Хорошо-бы.. но технически это невозможно. Системе надо потом еще контент окна как-то на десктопе расположить с учетом прозрачности. Плееру этого не потянуть. Потому отрисовка идет через буфер.
Постойте, а как мы получим графику от плеера? Все опять же несложно. У плеера есть свой графический интерфейс – IViewObjectEx. Заполучив его, мы сможем как раз заставит плеер рисовать там, где нам надо!

Дополняем базовый класс.
Код AS3:
// создаем окно-хост с флагом dwExStyle = WS_EX_LAYERED (default)
HWND CFlashWnd::CreateHostWindowEx( LPCWSTR lpWindowName,
					DWORD dwStyle,
					DWORD dwExStyle,
					int nCmdShow,
					int X,
					int Y,
					int nWidth,
					int nHeight,
					HWND hWndParent,
					HMENU hMenu,
					LPVOID lpParam
					)
{
	if(hWndHost != NULL)
		return hWndHost;
 
	ATOM reg = RegisterHostWindowClass();
	if( reg == 0)
		return NULL;
 
	HMODULE hModule = ::LoadLibrary(L"atl");
	if(!hModule)
		return NULL;
 
	LPAtlAxWinInit pAtlAxWinInit    = (LPAtlAxWinInit)::GetProcAddress(hModule,"AtlAxWinInit");
	if(!pAtlAxWinInit)
	{
		::FreeLibrary(hModule);
		return NULL;
	}
 
	BOOL  res = pAtlAxWinInit();
	if(res == FALSE)
		return NULL;
 
	hWndHost = ::CreateWindowEx(dwExStyle,FLHOSTWINDOW_CLASS, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInst, lpParam);
	if(hWndHost == NULL)
		return NULL;
 
	::SetWindowLongPtr(hWndHost,GWL_USERDATA,(int)this);
	isTransparent = TRUE;
	::ShowWindow(hWndHost, nCmdShow);
	::UpdateWindow(hWndHost);
	return hWndHost;
}
Код AS3:
// устанавливаем параметры отрисовки
HRESULT CFlashWnd::SetTransparentModeParam(SIZE viewSize, POINT viewPoint, UINT rate)
{
	if(!isInit)
		return S_FALSE;
 
	if(!isTransparent)
		return S_FALSE;
 
	// получаем графический интерфейс плеера
	HRESULT hr =  flash->QueryInterface(__uuidof(IViewObjectEx), (void**)&view) ;
	if(hr != S_OK)
		return hr;
	// размер окна рисования
	drawingSize = viewSize;
	// позиция окна рисования
	drawingPoint = viewPoint;
	// заводим таймер с коллбэеком  DrawingTimerProc
	::SetTimer(hWndHost, FLDRAWTIMER_ID, rate, (TIMERPROC)DrawingTimerProc);
	return hr;
}
Код AS3:
// коллбэк таймера отрисовки (static)
VOID CALLBACK CFlashWnd::DrawingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
	if(idEvent == FLDRAWTIMER_ID)
	{
		// позиция области отрисовки в окне.
		POINT layerPt = {0,0};
		CFlashWnd* f=(CFlashWnd*)GetWindowLongPtr(hwnd, GWL_USERDATA);
		if(f != NULL && f->hWndHost == hwnd)
			f->DrawView(f->drawingSize, f->drawingPoint, layerPt);
	}
}
Код AS3:
// отрисовка
HRESULT CFlashWnd::DrawView(SIZE windowSize, POINT windowPos, POINT layerPos)
{
	if(view == NULL)
		return S_FALSE;
 
	HDC hdcWindow=GetDC(hWndHost);
    	// создаем виртуальный DC
	HDC hdcMemory = CreateCompatibleDC(hdcWindow);
	HBITMAP hBitmap = CreateCompatibleBitmap(hdcWindow, windowSize.cx, windowSize.cy);
	HBITMAP hOldObject = (HBITMAP)SelectObject(hdcMemory, hBitmap);	
	// даем плееру отрисоваться и переносим все в окно
	HRESULT hr = view->Draw(DVASPECT_TRANSPARENT, 0, 0, 0, 0, hdcMemory, 0, 0, 0, 0);
	BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
	UpdateLayeredWindow(hWndHost, hdcWindow, &windowPos, &windowSize, hdcMemory, &layerPos, 0, &bf, ULW_ALPHA);
	SetWindowPos(hWndHost, HWND_TOP, windowPos.x, windowPos.y, windowSize.cx, windowSize.cy, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
	// зачистка
	SelectObject(hdcMemory, hOldObject);
	DeleteObject(hBitmap);
	ReleaseDC(hWndHost, hdcMemory);
	DeleteDC(hdcMemory);
	ReleaseDC(hWndHost, hdcWindow);
 
	return hr;
}
Использование:
Код AS3:
void MyFlash::init()
{
	WCHAR ver[16]={0};
	GetInstallVersion(ver);	
	CreateHostWindowEx();
	SetWindowText(ver);	
	CreateInstance();
	//CreateInstance(L"C:\\Flash10a.ocx");
	//CreateInstance(ID_OCX,L"BIN");
	SetWMODE(WMODE_TRANSPARENT);
	POINT drwPt = {380,200};
	SIZE  drwSz = {500,600};
	SetTransparentModeParam(drwSz, drwPt, 20);
	SetWMODE(WMODE_TRANSPARENT);	
	AttachControl();
	LoadMovie(ID_SWF,L"BIN");
 
}
Третий параметр SetTransparentModeParam (rate) имеет прямое отношение к frameRate ролика. По сути, это частота обновления окна. Ее нужно согласовать с фреймрейтом ролика. Ну, чтобы отрисовка в окне не отставала от ролика, по карйней мере.

На следующем шаге попробуем взаимодействие ролика и оболочки через FSCommand и ExternalInterface.
Вложения
Тип файла: zip test4.zip (60.6 Кб, 240 просмотров)
Всего комментариев 2

Комментарии

Старый 21.10.2011 18:28 mik1133 вне форума
mik1133
Хорошие статьи получились. Автору спасибо!
Попробовал запустить проект в 64-битной версии. И что получилось. Начиная с первого примера, если поставить режим "transparent" или "opaque" (SetWMODE(WMODE_TRANSPARENT)) то происходит свал - "Access violation..."
Может быть кто-то знает в чем дело? Интересно проект собрать в 64-битном варианте.
Старый 08.12.2011 09:15 alexcon314 вне форума
alexcon314
Плеер 32-битный, следует иметь это в виду, если хотите делать на х64.
Впрочем, сейчас и 64-битный плеер доступен.
PS. давненько не заглядывал сюда, пропустил пост.
 

 


Часовой пояс GMT +4, время: 05:53.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.