James Zhou 2000
Tuesday, November 26, 2013
a complete example of using DirectWrite to draw text. the procedure is to create a customized brush, set text format, and then call the DrawTextLayout()
CComPtr<ID2D1SolidColorBrush> m_pSolidColorBrush;
CComPtr<IDWriteTextLayout>
m_pTextLayout_;
CComPtr<IDWriteFactory>
m_pDWriteFactory_;
CComPtr<IDWriteTextFormat>
m_pTextFormat_;
const wchar_t* m_wszText_;
UINT32 m_cTextLength_;
D2D1_POINT_2F m_origin;
// the following init are used for text drawing -
// create a customized brush
m_hWndTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Purple, 1.0f),
&m_pSolidColorBrush
);
D2D1_SIZE_F rtSize =
m_hWndTarget->GetSize();
int width = static_cast<int>(rtSize.width);
int height = static_cast<int>(rtSize.height);
// draw text now
m_origin =
D2D1::Point2F(
static_cast<FLOAT>(rect.left / 4),
static_cast<FLOAT>(rect.top / 4)
);
m_wszText_ = L"Hello World using
DirectWrite!";
m_cTextLength_
= (UINT32)wcslen(m_wszText_);
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&m_pDWriteFactory_)
);
//create a customized text format
m_pDWriteFactory_->CreateTextFormat(
L"Gabriola", //
Font family name.
NULL, // Font collection (NULL sets it to use the system font
collection).
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
32.0f, //72.0f, // font
size
L"en-us",
&m_pTextFormat_
);
//create text layout
m_pDWriteFactory_->CreateTextLayout(
m_wszText_, // The
string to be laid out and formatted.
m_cTextLength_, // The
length of the string.
m_pTextFormat_, // The
text format to apply to the string (contains font information, etc).
width, // The
width of the layout box.
height, // The
height of the layout box.
&m_pTextLayout_ // The
IDWriteTextLayout interface pointer.
);
//jamesz: actual text drawing function here, can call this
once per frames
if (1)
{
m_hWndTarget->DrawTextLayout(
m_origin,
m_pTextLayout_,
m_pSolidColorBrush
);
}
How to create WCHAR string
const wchar_t* wszText_;
UINT32 cTextLength_;
wszText_ = L"Hello
World using DirectWrite!";
cTextLength_ = (UINT32)wcslen(wszText_);
How to create drawing brush and draw a colored block in windows
http://msdn.microsoft.com/en-us/library/windows/desktop/dd756651(v=vs.85).aspx
m_hWndTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black));
m_hWndTarget->DrawBitmap(m_bitmap,
rectangle);
//this
function needs to be called between BegeinDraw() and EndDraw()
if (1)
{
ID2D1SolidColorBrush* m_pSolidColorBrush;
m_hWndTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Purple, 1.0f),
&m_pSolidColorBrush
);
D2D1_SIZE_F rtSize =
m_hWndTarget->GetSize();
// Draw a grid background.
int width = static_cast<int>(rtSize.width);
int height = static_cast<int>(rtSize.height);
// Draw two rectangles.
D2D1_RECT_F rectangle1 =
D2D1::RectF(
rtSize.width / 2 - 50.0f,
rtSize.height / 2 - 50.0f,
rtSize.width / 2 + 50.0f,
rtSize.height / 2 + 50.0f
);
m_hWndTarget->FillRectangle(&rectangle1,
m_pSolidColorBrush);
}
HRESULT hr =
m_hWndTarget->EndDraw();
How to draw text in Windows (simple API)
HDC hdc;
hdc =
GetDC(m_hWnd);
RECT r;
GetClientRect(m_hWnd,
&r);
ExtTextOut(hdc, 500, 500, ETO_CLIPPED, &r, L"test", 4, NULL);
old fashion open/write file in c code
Just a note to remind myself ...
char buffer[50];
sprintf(buffer, "james:
%dms passed ...\r\n", g_tick2 - g_tick1);
FILE *fp;
fp = fopen("c:\\temp\\log.txt", "a");
fputs(buffer,fp);
fclose(fp);
Monday, November 25, 2013
Windows Timer Resolution problem
http://download.microsoft.com/download/3/0/2/3027D574-C433-412A-A8B6-5E0A75D5B237/Timer-Resolution.docx
"The default timer resolution on Windows 7 is 15.6 milliseconds (ms). Some applications reduce this to 1 ms, which reduces the battery run time on mobile systems by as much as 25 percent."
This is a crazy setup. I understand Windows is not a realtime system but still limiting the timer resolution to 15.6ms is a big limitation for application developers.
"The default timer resolution on Windows 7 is 15.6 milliseconds (ms). Some applications reduce this to 1 ms, which reduces the battery run time on mobile systems by as much as 25 percent."
This is a crazy setup. I understand Windows is not a realtime system but still limiting the timer resolution to 15.6ms is a big limitation for application developers.
How to use Windows Timer API
To create a timer:
SetTimer(g_AppWindow, //
handle to main window
IDT_TIMER1, // timer
identifier
//1000/60,
// 1/60-second interval
41,//1000/24,
// 1/24-second interval
(TIMERPROC)NULL); // no
timer callback
To use the timer to do sth:
case WM_TIMER:
switch (LOWORD(wParam))
{
case IDT_TIMER1:
// do sth here
// time your code
g_tick2
= g_pfnGetTickCount();
if (1)
{
WCHAR buffer[50];
swprintf_s(buffer,
50, L"Debug: %d ms passed ...\n\0",
(g_tick2
- g_tick1));
OutputDebugStringW(buffer);
}
g_tick1 = g_tick2;
How to create fullscreen window without title bar
How to create fullscreen window without title bar
The use of WS_POPUP | WS_MAXIMIZEBOX sets the
window properties and allowing us to create fullscreen window without title
bar.
Note that GetSystemMetrics() with SM_CXSCREEN
returns the screen resolution of the primary monitor.
HWND CVideoWindow::InitInstance(LPCWSTR windowName, int width, int height)
{
int x = ::GetSystemMetrics(SM_CXSCREEN) / 2 - width / 2;
int y = ::GetSystemMetrics(SM_CYSCREEN) / 2 - height / 2;
m_hWnd = CreateWindow(L"MyWindow", windowName, WS_POPUP | WS_MAXIMIZEBOX, x, y, width, height, NULL, NULL, NULL, NULL);
return m_hWnd;
}
Friday, November 22, 2013
Output debug data to debug windows in Visual C++
//test
g_tick1 = g_tick2;
g_tick2 = g_pfnGetTickCount();
if (1)
{
WCHAR buffer[50];
swprintf_s(buffer, 50, L"james %d ms passed: --\n\0",
(g_tick2 - g_tick1));
OutputDebugStringW(buffer);
}
time the code, and send to the debug window
g_tick1 = g_tick2;
g_tick2 = g_pfnGetTickCount();
if (1)
{
WCHAR buffer[50];
swprintf_s(buffer, 50, L"james %d ms passed: --\n\0",
(g_tick2 - g_tick1));
OutputDebugStringW(buffer);
}
time the code, and send to the debug window
DirectShow filter, video renderer and filter graph manager
DirectShow video renderer and filter graph manager
The filter graph manager (FGM) may include several DirecthShow filters.
The FGM can be constructed, controlled and its event can be captured and
processed at application level.
IGraphBuilder* g_pGraphBuilder = NULL; // to access the FGM
IMediaControl* g_pMediaControl = NULL; // to control the media, run/stop
etc.
IMediaEventEx* g_pMediaEvent
= NULL; // to get event and notifications from FGM
IMediaPosition* g_pMediaPosition
= NULL;
//
to do seek function
// the following code does the init()
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)&g_pGraphBuilder);
if (FAILED(hr)) return -1;
g_pGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&g_pMediaControl);
g_pGraphBuilder->QueryInterface(IID_IMediaEvent, (void**)&g_pMediaEvent);
g_pGraphBuilder->QueryInterface(IID_IMediaPosition, (void**)&g_pMediaPosition);
g_pMediaEvent->SetNotifyWindow((OAHWND)g_AppWindow, WM_GRAPHEVENT, 0); //
set the current window to handle GFM events
g_pMediaEvent->SetNotifyFlags(0); // turn on
notifications
//in the following WindowProc() callfaback function,
#define WM_GRAPHEVENT WM_USER // define a custom window message for graph events
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
…
switch (uMsg)
{
case WM_COMMAND: // handles windows commands and messages
switch (LOWORD(wParam))
{
case ID_FILE_OPEN:
…
}
case WM_GRAPHEVENT: // handles user defined msg, here generated by FGM
OnGraphEvent();
break;
}
//in the OnGraphEvent() we handle all the filter graph events at
application level
void OnGraphEvent()
{
long EventCode, Param1, Param2;
g_pMediaEvent->CancelDefaultHandling(EC_REPAINT); // test
by james, to remove
while
(g_pMediaEvent->GetEvent(&EventCode, &Param1, &Param2, 0) != E_ABORT)
{
switch (EventCode)
{
case EC_COMPLETE:
if (!g_Looping)
g_pMediaControl->Stop();
g_pMediaPosition->put_CurrentPosition(0); // reset
to beginning
break;
case EC_PAUSED: // just notification only to app. FGM already paused the video
Break
case EC_CONTENTPROPERTY_CHANGED: // my user defined msg OutputDebugStringW(L"EC_CONTENTPROPERTY_CHANGED recieved - james.\n");
break;
default:
break;
}
g_pMediaEvent->FreeEventParams(EventCode,
Param1, Param2);
}
Note here I captured CONTENTPROPERTY_CHANGED event here at application level. This event by default is not supported in directshow, but we could use this as user defined message. The message-data-flow will be something like below.
DirectShow filters --> Filter Graph Manager --> Application
Directshow filter such as a video renderer can generate a notification by calling the function NotifyEvent(EC_CONTENTPROPERTY_CHANGED, S_OK, 0) inside the DirectShow filter; Then, this will send notification to filter graph manager. For most messages and notifications, normally FGM will process or hide some messages such as EC_REPAINT notifications to application layer since usually this is transparent to applications. But for event such as EC_COMPLETE, FGM will forward this notification to upper levels so that application layer can capture this event, as shown in the code above. Here I am using a special event code CONTENTPROPERTY_CHANGED to implement my own task, because I know FGM will not hide or do anything when my renderer filter send this notification to FGM. And then at application layer, I can capture this event. The reason I am doing this is because for every DoRenderSample() function call, I want to notify the application layer that a video frame has changed, and then I might want to do something for example doing backlight control per frame basis. The reason why I do not want to do backlight control inside the directshow video renderer filter is because the communication to my i2c device seems to stall the video playback and affect the playback performance. So I prefer to do this separate control using a different thread at application layer, not creating any impact on the video playback.
The cleanup code is shown below.
void CleanUpDirectShow()
{
HELPER_RELEASE(g_pMediaPosition);
HELPER_RELEASE(g_pMediaEvent);
HELPER_RELEASE(g_pMediaControl);
HELPER_RELEASE(g_pGraphBuilder);
}
