示例#1
0
static HRESULT drawButtonPart(HRESULT hr, struct drawState *s)
{
	uiTableValue *value;
	WCHAR *wstr;
	bool enabled;
	HTHEME theme;
	RECT r;
	TEXTMETRICW tm;

	if (hr != S_OK)
		return hr;
	if (s->p->buttonModelColumn == -1)
		return S_OK;

	value = uiprivTableModelCellValue(s->model, s->iItem, s->p->buttonModelColumn);
	wstr = toUTF16(uiTableValueString(value));
	uiFreeTableValue(value);
	enabled = uiprivTableModelCellEditable(s->model, s->iItem, s->p->buttonClickableModelColumn);

	theme = OpenThemeData(s->t->hwnd, L"button");

	if (GetTextMetricsW(s->dc, &tm) == 0) {
		logLastError(L"GetTextMetricsW()");
		hr = E_FAIL;
		goto fail;
	}
	r = s->m->subitemBounds;

	if (theme != NULL) {
		int state;

		state = PBS_NORMAL;
		if (!enabled)
			state = PBS_DISABLED;
		hr = DrawThemeBackground(theme, s->dc,
			BP_PUSHBUTTON, state,
			&r, NULL);
		if (hr != S_OK) {
			logHRESULT(L"DrawThemeBackground()", hr);
			goto fail;
		}
		// TODO DT_EDITCONTROL?
		// TODO DT_PATH_ELLIPSIS DT_WORD_ELLIPSIS instead of DT_END_ELLIPSIS? a middle-ellipsis option would be ideal here
		// TODO is there a theme property we can get instead of hardcoding these flags? if not, make these flags a macro
		hr = DrawThemeText(theme, s->dc,
			BP_PUSHBUTTON, state,
			wstr, -1,
			DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX, 0,
			&r);
		if (hr != S_OK) {
			logHRESULT(L"DrawThemeText()", hr);
			goto fail;
		}
	} else {
		UINT state;
		HBRUSH color, prevColor;
		int prevBkMode;

		// TODO check errors
		// TODO explain why we're not doing this in the themed case (it has to do with extra transparent pixels)
		InflateRect(&r, -1, -1);
		state = DFCS_BUTTONPUSH;
		if (!enabled)
			state |= DFCS_INACTIVE;
		if (DrawFrameControl(s->dc, &r, DFC_BUTTON, state) == 0) {
			logLastError(L"DrawFrameControl()");
			hr = E_FAIL;
			goto fail;
		}
		color = GetSysColorBrush(COLOR_BTNTEXT);
		// TODO check errors for these two
		prevColor = (HBRUSH) SelectObject(s->dc, color);
		prevBkMode = SetBkMode(s->dc, TRANSPARENT);
		// TODO DT_EDITCONTROL?
		// TODO DT_PATH_ELLIPSIS DT_WORD_ELLIPSIS instead of DT_END_ELLIPSIS? a middle-ellipsis option would be ideal here
		if (DrawTextW(s->dc, wstr, -1, &r, DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX) == 0) {
			logLastError(L"DrawTextW()");
			hr = E_FAIL;
			goto fail;
		}
		// TODO check errors for these two
		SetBkMode(s->dc, prevBkMode);
		SelectObject(s->dc, prevColor);
	}

	hr = S_OK;
fail:
	// TODO check errors
	if (theme != NULL)
		CloseThemeData(theme);
	uiprivFree(wstr);
	return hr;
}
示例#2
0
/* 
 * @implemented
 *
 * Synced with wine 1.1.32
 */
INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count,
                        LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp )
{
    SIZE size;
    const WCHAR *strPtr;
    WCHAR *retstr, *p_retstr;
    size_t size_retstr;
    WCHAR line[MAX_BUFFER];
    int len, lh, count=i_count;
    TEXTMETRICW tm;
    int lmargin = 0, rmargin = 0;
    int x = rect->left, y = rect->top;
    int width = rect->right - rect->left;
    int max_width = 0;
    int last_line;
    int tabwidth /* to keep gcc happy */ = 0;
    int prefix_offset;
    ellipsis_data ellip;
    int invert_y=0;

    TRACE("%s, %d, [%s] %08x\n", debugstr_wn (str, count), count,
        wine_dbgstr_rect(rect), flags);

   if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
          dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin);

    if (!str) return 0;

    strPtr = str;

    if (flags & DT_SINGLELINE)
        flags &= ~DT_WORDBREAK;

    GetTextMetricsW(hdc, &tm);
    if (flags & DT_EXTERNALLEADING)
	lh = tm.tmHeight + tm.tmExternalLeading;
    else
	lh = tm.tmHeight;

    if (str[0] && count == 0)
        return lh;

    if (dtp && dtp->cbSize != sizeof(DRAWTEXTPARAMS))
        return 0;

    if (count == -1)
    {
        count = strlenW(str);
        if (count == 0)
        {
            if( flags & DT_CALCRECT)
            {
                rect->right = rect->left;
                if( flags & DT_SINGLELINE)
                    rect->bottom = rect->top + lh;
                else
                    rect->bottom = rect->top;
            }
            return lh;
        }
    }

    if (GetGraphicsMode(hdc) == GM_COMPATIBLE)
    {
        SIZE window_ext, viewport_ext;
        GetWindowExtEx(hdc, &window_ext);
        GetViewportExtEx(hdc, &viewport_ext);
        if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
            invert_y = 1;
    }

    if (dtp)
    {
        lmargin = dtp->iLeftMargin;
        rmargin = dtp->iRightMargin;
        if (!(flags & (DT_CENTER | DT_RIGHT)))
            x += lmargin;
        dtp->uiLengthDrawn = 0;     /* This param RECEIVES number of chars processed */
    }

    if (flags & DT_EXPANDTABS)
    {
        int tabstop = ((flags & DT_TABSTOP) && dtp) ? dtp->iTabLength : 8;
	tabwidth = tm.tmAveCharWidth * tabstop;
    }

    if (flags & DT_CALCRECT) flags |= DT_NOCLIP;

    if (flags & DT_MODIFYSTRING)
    {
        size_retstr = (count + 4) * sizeof (WCHAR);
        retstr = HeapAlloc(GetProcessHeap(), 0, size_retstr);
        if (!retstr) return 0;
        memcpy (retstr, str, size_retstr);
    }
    else
    {
        size_retstr = 0;
        retstr = NULL;
    }
    p_retstr = retstr;

    do
    {
	len = sizeof(line)/sizeof(line[0]);
	if (invert_y)
            last_line = !(flags & DT_NOCLIP) && y - ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) < rect->bottom;
	else
            last_line = !(flags & DT_NOCLIP) && y + ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) > rect->bottom;
	strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, &p_retstr, tabwidth, &prefix_offset, &ellip);

	if (flags & DT_CENTER) x = (rect->left + rect->right -
				    size.cx) / 2;
	else if (flags & DT_RIGHT) x = rect->right - size.cx;

	if (flags & DT_SINGLELINE)
	{
	    if (flags & DT_VCENTER) y = rect->top +
	    	(rect->bottom - rect->top) / 2 - size.cy / 2;
	    else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
        }

	if (!(flags & DT_CALCRECT))
	{
            const WCHAR *str = line;
            int xseg = x;
            while (len)
            {
                int len_seg;
                SIZE size;
                if ((flags & DT_EXPANDTABS))
                {
                    const WCHAR *p;
                    p = str; while (p < str+len && *p != TAB) p++;
                    len_seg = p - str;
                    if (len_seg != len && !GetTextExtentPointW(hdc, str, len_seg, &size))
                        return 0;
                }
                else
                    len_seg = len;

                if (!ExtTextOutW( hdc, xseg, y,
                                 ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
                                 ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
                                 rect, str, len_seg, NULL ))  return 0;
                if (prefix_offset != -1 && prefix_offset < len_seg)
                {
                    TEXT_DrawUnderscore (hdc, xseg, y + tm.tmAscent + 1, str, prefix_offset, (flags & DT_NOCLIP) ? NULL : rect);
                }
                len -= len_seg;
                str += len_seg;
                if (len)
                {
                    assert ((flags & DT_EXPANDTABS) && *str == TAB);
                    len--; str++;
                    xseg += ((size.cx/tabwidth)+1)*tabwidth;
                    if (prefix_offset != -1)
                    {
                        if (prefix_offset < len_seg)
                        {
                            /* We have just drawn an underscore; we ought to
                             * figure out where the next one is.  I am going
                             * to leave it for now until I have a better model
                             * for the line, which will make reprefixing easier.
                             * This is where ellip would be used.
                             */
                            prefix_offset = -1;
                        }
                        else
                            prefix_offset -= len_seg;
                    }
                }
            }
    }
    else if (size.cx > max_width)
        max_width = size.cx;

        if (invert_y)
	    y -= lh;
        else
	    y += lh;
        if (dtp)
            dtp->uiLengthDrawn += len;
    }
    while (strPtr && !last_line);

    if (flags & DT_CALCRECT)
    {
	rect->right = rect->left + max_width;
	rect->bottom = y;
        if (dtp)
            rect->right += lmargin + rmargin;
    }
    if (retstr)
    {
        memcpy (str, retstr, size_retstr);
        HeapFree (GetProcessHeap(), 0, retstr);
    }
    return y - rect->top;
}
示例#3
0
static HRESULT drawProgressBarPart(HRESULT hr, struct drawState *s)
{
	int progress;
	LONG indeterminatePos;
	HTHEME theme;
	RECT r;
	RECT rBorder, rFill[2];
	int i, nFill;
	TEXTMETRICW tm;
	int sysColor;

	if (hr != S_OK)
		return hr;
	if (s->p->progressBarModelColumn == -1)
		return S_OK;

	progress = uiprivTableProgress(s->t, s->iItem, s->iSubItem, s->p->progressBarModelColumn, &indeterminatePos);

	theme = OpenThemeData(s->t->hwnd, L"PROGRESS");

	if (GetTextMetricsW(s->dc, &tm) == 0) {
		logLastError(L"GetTextMetricsW()");
		hr = E_FAIL;
		goto fail;
	}
	r = s->m->subitemBounds;
	// this sets the height of the progressbar and vertically centers it in one fell swoop
	r.top += (r.bottom - tm.tmHeight - r.top) / 2;
	r.bottom = r.top + tm.tmHeight;

	// TODO check errors
	rBorder = r;
	InflateRect(&rBorder, -1, -1);
	if (theme != NULL) {
		RECT crect;

		hr = GetThemeBackgroundContentRect(theme, s->dc,
			PP_TRANSPARENTBAR, PBBS_NORMAL,
			&rBorder, &crect);
		if (hr != S_OK) {
			logHRESULT(L"GetThemeBackgroundContentRect()", hr);
			goto fail;
		}
		hr = DrawThemeBackground(theme, s->dc,
			PP_TRANSPARENTBAR, PBBS_NORMAL,
			&crect, NULL);
		if (hr != S_OK) {
			logHRESULT(L"DrawThemeBackground() border", hr);
			goto fail;
		}
	} else {
		HPEN pen, prevPen;
		HBRUSH brush, prevBrush;

		sysColor = COLOR_HIGHLIGHT;
		if (s->m->selected)
			sysColor = COLOR_HIGHLIGHTTEXT;

		// TODO check errors everywhere
		pen = CreatePen(PS_SOLID, 1, GetSysColor(sysColor));
		prevPen = (HPEN) SelectObject(s->dc, pen);
		brush = (HBRUSH) GetStockObject(NULL_BRUSH);
		prevBrush = (HBRUSH) SelectObject(s->dc, brush);
		Rectangle(s->dc, rBorder.left, rBorder.top, rBorder.right, rBorder.bottom);
		SelectObject(s->dc, prevBrush);
		SelectObject(s->dc, prevPen);
		DeleteObject(pen);
	}

	nFill = 1;
	rFill[0] = r;
	// TODO check error
	InflateRect(&rFill[0], -1, -1);
	if (progress != -1)
		rFill[0].right -= (rFill[0].right - rFill[0].left) * (100 - progress) / 100;
	else {
		LONG barWidth;
		LONG pieceWidth;

		// TODO explain all this
		// TODO this should really start the progressbar scrolling into view instead of already on screen when first set
		rFill[1] = rFill[0];		// save in case we need it
		barWidth = rFill[0].right - rFill[0].left;
		pieceWidth = barWidth / indeterminateSegments;
		rFill[0].left += indeterminatePos % barWidth;
		if ((rFill[0].left + pieceWidth) >= rFill[0].right) {
			// make this piece wrap back around
			nFill++;
			rFill[1].right = rFill[1].left + (pieceWidth - (rFill[0].right - rFill[0].left));
		} else
			rFill[0].right = rFill[0].left + pieceWidth;
	}
	for (i = 0; i < nFill; i++)
		if (theme != NULL) {
			hr = DrawThemeBackground(theme, s->dc,
				PP_FILL, PBFS_NORMAL,
				&rFill[i], NULL);
			if (hr != S_OK) {
				logHRESULT(L"DrawThemeBackground() fill", hr);
				goto fail;
			}
		} else
			// TODO check errors
			FillRect(s->dc, &rFill[i], GetSysColorBrush(sysColor));

	hr = S_OK;
fail:
	// TODO check errors
	if (theme != NULL)
		CloseThemeData(theme);
	return hr;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;

	unsigned char fail_type = 0;

	// Initialize GDI+.
	Gdiplus::GdiplusStartup( &gdiplusToken, &gdiplusStartupInput, NULL );

	// Blocks our reading thread and various GUI operations.
	InitializeCriticalSection( &pe_cs );

	// Get the default message system font.
	NONCLIENTMETRICS ncm = { NULL };
	ncm.cbSize = sizeof( NONCLIENTMETRICS );
	SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof( NONCLIENTMETRICS ), &ncm, 0 );

	// Set our global font to the LOGFONT value obtained from the system.
	hFont = CreateFontIndirect( &ncm.lfMessageFont );

	// Get the row height for our listview control.
	TEXTMETRIC tm;
	HDC hDC = GetDC( NULL );
	HFONT ohf = ( HFONT )SelectObject( hDC, hFont );
	GetTextMetricsW( hDC, &tm );
	SelectObject( hDC, ohf );	// Reset old font.
	ReleaseDC( NULL, hDC );

	row_height = tm.tmHeight + tm.tmExternalLeading + 5;

	int icon_height = GetSystemMetrics( SM_CYSMICON ) + 2;
	if ( row_height < icon_height )
	{
		row_height = icon_height;
	}

	// Get the system icon for each of the three file types.
	SHFILEINFOA shfi = { NULL }; 
	SHGetFileInfoA( ".bmp", FILE_ATTRIBUTE_NORMAL, &shfi, sizeof( shfi ), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES );
	hIcon_bmp = shfi.hIcon;
	SHGetFileInfoA( ".png", FILE_ATTRIBUTE_NORMAL, &shfi, sizeof( shfi ), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES );
	hIcon_png = shfi.hIcon;
	SHGetFileInfoA( ".jpg", FILE_ATTRIBUTE_NORMAL, &shfi, sizeof( shfi ), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES );
	hIcon_jpg = shfi.hIcon;

	// Initialize our window class.
	WNDCLASSEX wcex;
	wcex.cbSize			= sizeof( WNDCLASSEX );
	wcex.style          = CS_VREDRAW | CS_HREDRAW;
	wcex.lpfnWndProc    = MainWndProc;
	wcex.cbClsExtra     = 0;
	wcex.cbWndExtra     = 0;
	wcex.hInstance      = hInstance;
	wcex.hIcon          = LoadIcon( hInstance, MAKEINTRESOURCE( IDI_ICON ) );
	wcex.hCursor        = LoadCursor( NULL, IDC_ARROW );
	wcex.hbrBackground  = ( HBRUSH )( COLOR_WINDOW );
	wcex.lpszMenuName   = NULL;
	wcex.lpszClassName  = L"thumbcache";
	wcex.hIconSm        = LoadIcon( wcex.hInstance, MAKEINTRESOURCE( IDI_APPLICATION ) );

	if ( !RegisterClassEx( &wcex ) )
	{
		fail_type = 1;
		goto CLEANUP;
	}

	wcex.lpfnWndProc    = ImageWndProc;
	wcex.lpszClassName  = L"image";

	if ( !RegisterClassEx( &wcex ) )
	{
		fail_type = 1;
		goto CLEANUP;
	}

	wcex.lpfnWndProc    = ScanWndProc;
	wcex.lpszClassName  = L"scan";

	if ( !RegisterClassEx( &wcex ) )
	{
		fail_type = 1;
		goto CLEANUP;
	}

	wcex.lpfnWndProc    = InfoWndProc;
	wcex.lpszClassName  = L"info";

	if ( !RegisterClassEx( &wcex ) )
	{
		fail_type = 1;
		goto CLEANUP;
	}

	wcex.lpfnWndProc    = PropertyWndProc;
	wcex.lpszClassName  = L"property";

	if ( !RegisterClassEx( &wcex ) )
	{
		fail_type = 1;
		goto CLEANUP;
	}

	g_hWnd_main = CreateWindow( L"thumbcache", PROGRAM_CAPTION, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, ( ( GetSystemMetrics( SM_CXSCREEN ) - MIN_WIDTH ) / 2 ), ( ( GetSystemMetrics( SM_CYSCREEN ) - MIN_HEIGHT ) / 2 ), MIN_WIDTH, MIN_HEIGHT, NULL, NULL, NULL, NULL );

	if ( !g_hWnd_main )
	{
		fail_type = 2;
		goto CLEANUP;
	}

	g_hWnd_image = CreateWindow( L"image", PROGRAM_CAPTION, WS_OVERLAPPEDWINDOW, ( ( GetSystemMetrics( SM_CXSCREEN ) - MIN_WIDTH ) / 2 ), ( ( GetSystemMetrics( SM_CYSCREEN ) - MIN_HEIGHT ) / 2 ), MIN_HEIGHT, MIN_HEIGHT, NULL, NULL, NULL, NULL );

	if ( !g_hWnd_image )
	{
		fail_type = 2;
		goto CLEANUP;
	}

	g_hWnd_scan = CreateWindow( L"scan", L"Map File Paths to Cache Entry Hashes", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_CLIPCHILDREN, ( ( GetSystemMetrics( SM_CXSCREEN ) - MIN_WIDTH ) / 2 ), ( ( GetSystemMetrics( SM_CYSCREEN ) - ( MIN_HEIGHT - 115 ) ) / 2 ), MIN_WIDTH, ( MIN_HEIGHT - 115 ), g_hWnd_main, NULL, NULL, NULL );

	if ( !g_hWnd_scan )
	{
		fail_type = 2;
		goto CLEANUP;
	}

	g_hWnd_info = CreateWindow( L"info", L"Extended Information", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, ( ( GetSystemMetrics( SM_CXSCREEN ) - MIN_WIDTH ) / 2 ), ( ( GetSystemMetrics( SM_CYSCREEN ) - MIN_WIDTH ) / 2 ), MIN_WIDTH, MIN_WIDTH, NULL, NULL, NULL, NULL );

	if ( !g_hWnd_info )
	{
		fail_type = 2;
		goto CLEANUP;
	}

	g_hWnd_property = CreateWindow( L"property", L"Property Value", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, ( ( GetSystemMetrics( SM_CXSCREEN ) - MIN_HEIGHT ) / 2 ), ( ( GetSystemMetrics( SM_CYSCREEN ) - MIN_HEIGHT ) / 2 ), MIN_HEIGHT, MIN_HEIGHT, NULL, NULL, NULL, NULL );

	if ( !g_hWnd_property )
	{
		fail_type = 2;
		goto CLEANUP;
	}

	// See if we have any command-line parameters
	if ( lpCmdLine != NULL && lpCmdLine[ 0 ] != NULL )
	{
		// Count the number of parameters and split them into an array.
		int argCount = 0;
		LPWSTR *szArgList = CommandLineToArgvW( GetCommandLine(), &argCount );
		if ( szArgList != NULL )
		{
			// The first parameter is the path to the executable. Ignore it.
			if ( argCount > 1 )
			{
				// Allocate enough space to hold each parameter. They should all be full paths.
				pathinfo *pi = ( pathinfo * )malloc( sizeof( pathinfo ) );
				pi->type = 0;
				pi->offset = 0;
				pi->output_path = NULL;
				pi->filepath = ( wchar_t * )malloc( sizeof( wchar_t ) * ( ( MAX_PATH * ( argCount - 1 ) ) + 1 ) );
				wmemset( pi->filepath, 0, ( ( MAX_PATH * ( argCount - 1 ) ) + 1 ) );

				cmd_line = 1;	// Open the database(s) from the command-line.

				int filepath_offset = 0;
				for ( int i = 1; i < argCount; ++i )
				{
					int filepath_length = wcslen( szArgList[ i ] );

					// See if it's an output parameter.
					if ( filepath_length > 1 && szArgList[ i ][ 0 ] == L'-' && ( szArgList[ i ][ 1 ] == L'o' || szArgList[ i ][ 1 ] == L'O' ) )
					{
						// See if the next parameter exists. We'll assume it's the output directory.
						if ( i + 1 < argCount )
						{
							if ( pi->output_path != NULL )
							{
								free( pi->output_path );
							}

							pi->output_path = _wcsdup( szArgList[ ++i ] );
							pi->type = 0;

							cmd_line = 2;	// Save the database(s) from the command-line. Do not display the main window or any prompts.
						}
					}
					else if ( filepath_length > 1 && szArgList[ i ][ 0 ] == L'-' && ( szArgList[ i ][ 1 ] == L'c' || szArgList[ i ][ 1 ] == L'C' ) )
					{
						// See if the next parameter exists. We'll assume it's the output directory.
						if ( i + 1 < argCount )
						{
							if ( pi->output_path != NULL )
							{
								free( pi->output_path );
							}

							pi->output_path = _wcsdup( szArgList[ ++i ] );
							pi->type = 1;

							cmd_line = 2;	// Save the database(s) from the command-line. Do not display the main window or any prompts.
						}
					}
					else if ( filepath_length > 1 && szArgList[ i ][ 0 ] == L'-' && ( szArgList[ i ][ 1 ] == L'z' || szArgList[ i ][ 1 ] == L'Z' ) )
					{
						hide_blank_entries = true;

						// Put a check next to the menu item. g_hMenu is created in g_hWnd_main.
						CheckMenuItem( g_hMenu, MENU_HIDE_BLANK, MF_CHECKED );
					}
					else	// Copy the paths into the NULL separated filepath.
					{
						// If the user typed a relative path, get the full path.
						wchar_t full_path[ MAX_PATH ] = { 0 };
						DWORD full_path_length = min( GetFullPathName( szArgList[ i ], MAX_PATH, full_path, NULL ), MAX_PATH );

						wmemcpy_s( pi->filepath + filepath_offset, ( ( MAX_PATH * ( argCount - 1 ) ) + 1 ) - filepath_offset, full_path, full_path_length + 1 );
						filepath_offset += ( full_path_length + 1 );
					}
				}

				// Only read the database if there's a file to open.
				if ( pi->filepath[ 0 ] != NULL )
				{
					// filepath will be freed in the thread.
					CloseHandle( ( HANDLE )_beginthreadex( NULL, 0, &read_thumbcache, ( void * )pi, 0, NULL ) );
				}
				else
				{
					// Cleanup our parameters structure and exit the program.
					free( pi->output_path );
					free( pi->filepath );
					free( pi );

					cmd_line = -1;

					SendMessage( g_hWnd_main, WM_DESTROY_ALT, 0, 0 );
				}
			}

			// Free the parameter list.
			LocalFree( szArgList );
		}
	}

	if ( cmd_line == 0 || cmd_line == 1 )
	{
		ShowWindow( g_hWnd_main, SW_SHOW );
	}

	// Main message loop:
	MSG msg;
	while ( GetMessage( &msg, NULL, 0, 0 ) > 0 )
	{
		if ( g_hWnd_active == NULL || !IsDialogMessage( g_hWnd_active, &msg ) )	// Checks tab stops.
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
	}

CLEANUP:

	// Destroy our icons.
	DestroyIcon( hIcon_jpg );
	DestroyIcon( hIcon_png );
	DestroyIcon( hIcon_bmp );

	// Delete our font.
	DeleteObject( hFont );

	// Delete our critical section.
	DeleteCriticalSection( &pe_cs );

	// Shutdown GDI+
	Gdiplus::GdiplusShutdown( gdiplusToken );

	// Unload the modules if they were initialized.
	UnInitializeMsSrch();
	UnInitializeMsSCB();

	if ( fail_type == 1 )
	{
		MessageBoxA( NULL, "Call to RegisterClassEx failed!", PROGRAM_CAPTION_A, MB_ICONWARNING );
	}
	else if ( fail_type == 2 )
	{
		MessageBoxA( NULL, "Call to CreateWindow failed!", PROGRAM_CAPTION_A, MB_ICONWARNING );
	}

	return ( int )msg.wParam;
}
示例#5
0
文件: font.c 项目: Moteesh/reactos
static BOOL WINAPI ID3DXFontImpl_GetTextMetricsW(ID3DXFont *iface, TEXTMETRICW *metrics)
{
    struct d3dx_font *This = impl_from_ID3DXFont(iface);
    TRACE("iface %p, metrics %p\n", iface, metrics);
    return GetTextMetricsW(This->hdc, metrics);
}
示例#6
0
文件: misc.c 项目: Gaikokujin/WinNT4
NTSTATUS
EnumerateFonts(
    DWORD Flags)
{
    TEXTMETRIC tmi;
    HDC hDC;
    PFACENODE pFN;
    ULONG ulOldEnumFilter;
    DWORD FontIndex;
    DWORD dwFontType = 0;

    DBGFONTS(("EnumerateFonts %lx\n", Flags));

    dwFontType = (EF_TTFONT|EF_OEMFONT|EF_DEFFACE) & Flags;

    if (FontInfo == NULL) {
        //
        // allocate memory for the font array
        //
        NumberOfFonts = 0;

        FontInfo = (PFONT_INFO)HeapAlloc(pConHeap,MAKE_TAG( FONT_TAG ),sizeof(FONT_INFO) * INITIAL_FONTS);
        if (FontInfo == NULL)
            return STATUS_NO_MEMORY;
        FontInfoLength = INITIAL_FONTS;
    }

    hDC = CreateDCW(L"DISPLAY",NULL,NULL,NULL);

    // Before enumeration, turn off font enumeration filters.
    ulOldEnumFilter = SetFontEnumeration(0);
    // restore all the other flags
    SetFontEnumeration(ulOldEnumFilter & ~FE_FILTER_TRUETYPE);

    if (Flags & EF_DEFFACE) {
        SelectObject(hDC,GetStockObject(OEM_FIXED_FONT));

        if (GetTextMetricsW(hDC, &tmi)) {
            DefaultFontSize.X = (SHORT)(tmi.tmMaxCharWidth);
            DefaultFontSize.Y = (SHORT)(tmi.tmHeight+tmi.tmExternalLeading);
            DefaultFontFamily = tmi.tmPitchAndFamily;
        }
        GetTextFaceW(hDC, LF_FACESIZE, DefaultFaceName);
        DBGFONTS(("Default (OEM) Font %ls (%d,%d)\n", DefaultFaceName,
                DefaultFontSize.X, DefaultFontSize.Y));

        // Make sure we are going to enumerate the OEM face.
        pFN = AddFaceNode(&gpFaceNames, DefaultFaceName);
        pFN->dwFlag |= EF_DEFFACE | EF_OEMFONT;
    }

    // Use DoFontEnum to get all fonts from the system.  Our FontEnum
    // proc puts just the ones we want into an array
    //
    for (pFN = gpFaceNames; pFN; pFN = pFN->pNext) {
        DBGFONTS(("\"%ls\" is %s%s%s%s%s%s\n", pFN->awch,
            pFN->dwFlag & EF_NEW        ? "NEW "        : " ",
            pFN->dwFlag & EF_OLD        ? "OLD "        : " ",
            pFN->dwFlag & EF_ENUMERATED ? "ENUMERATED " : " ",
            pFN->dwFlag & EF_OEMFONT    ? "OEMFONT "    : " ",
            pFN->dwFlag & EF_TTFONT     ? "TTFONT "     : " ",
            pFN->dwFlag & EF_DEFFACE    ? "DEFFACE "    : " "));

        if ((pFN->dwFlag & dwFontType) == 0) {
            // not the kind of face we want
            continue;
        }
        if (pFN->dwFlag & EF_ENUMERATED) {
            // we already enumerated this face
            continue;
        }

        DoFontEnum(hDC, pFN->awch, DefaultFontSize.Y);
        pFN->dwFlag |= EF_ENUMERATED;
    }


    // After enumerating fonts, restore the font enumeration filter.
    SetFontEnumeration(ulOldEnumFilter);

    DeleteDC(hDC);

    // Make sure the default font is set correctly
    if (NumberOfFonts > 0 && DefaultFontSize.X == 0 && DefaultFontSize.Y == 0) {
        DefaultFontSize.X = FontInfo[0].Size.X;
        DefaultFontSize.Y = FontInfo[0].Size.Y;
        DefaultFontFamily = FontInfo[0].Family;
    }

    for (FontIndex = 0; FontIndex < NumberOfFonts; FontIndex++) {
        if (FontInfo[FontIndex].Size.X == DefaultFontSize.X &&
            FontInfo[FontIndex].Size.Y == DefaultFontSize.Y &&
            FontInfo[FontIndex].Family == DefaultFontFamily) {
            break;
        }
    }
    ASSERT(FontIndex < NumberOfFonts);
    if (FontIndex < NumberOfFonts) {
        DefaultFontIndex = FontIndex;
    } else {
        DefaultFontIndex = 0;
    }
    DBGFONTS(("EnumerateFonts : DefaultFontIndex = %ld\n", DefaultFontIndex));

    return STATUS_SUCCESS;
}
示例#7
0
文件: misc.c 项目: Gaikokujin/WinNT4
/*
 * Returns bit combination
 *  FE_ABANDONFONT  - do not continue enumerating this font
 *  FE_FONTOK       - font was created and added to cache or already there
 */
int CALLBACK
FontEnum(
    LPENUMLOGFONTW lpLogFont,
    LPNEWTEXTMETRICW lpTextMetric,
    int nFontType,
    LPARAM lParam
    )

/*++

    Is called exactly once by GDI for each font in the system.  This
    routine is used to store the FONT_INFO structure.

--*/

{
    PFONTENUMDC pfed = (PFONTENUMDC)lParam;
    HDC hDC = pfed->hDC;
    BOOL bFindFaces = pfed->bFindFaces;
    HFONT hFont;
    TEXTMETRICW tmi;
    LONG nFont;
    LONG nFontNew;
    COORD SizeToShow;
    COORD SizeActual;
    COORD SizeWant;
    BYTE tmFamily;
    SIZE Size;
    LPWSTR pwszFace = lpLogFont->elfLogFont.lfFaceName;
    PFACENODE pFN;

    DBGFONTS(("  FontEnum \"%ls\" (%d,%d) weight 0x%lx(%d) -- %s\n",
            pwszFace,
            lpLogFont->elfLogFont.lfWidth, lpLogFont->elfLogFont.lfHeight,
            lpLogFont->elfLogFont.lfWeight, lpLogFont->elfLogFont.lfWeight,
            bFindFaces ? "Finding Faces" : "Creating Fonts"));

    //
    // reject variable width and italic fonts, also tt fonts with neg ac
    // also reject DBCS fonts because they are never really fixed pitch
    // they can be "binary" pitch meaning SBCS widths are the same as all
    // other SBCS widths and DBCS widhts the same as all DBCS widhts
    // (but DBCS widths won't be the same as SBCS widths)
    if
    (
      !(lpLogFont->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ||
      (lpLogFont->elfLogFont.lfItalic)                        ||
      !(((NTMW_INTERNAL *)lpTextMetric)->tmd.fl & TMD_NONNEGATIVE_AC) ||
      (IS_ANY_DBCS_CHARSET(lpLogFont->elfLogFont.lfCharSet))
    )
    {
        DBGFONTS(("    REJECT  face (variable pitch, italic, or neg a&c)\n"));
        return bFindFaces ? TRUE : FALSE;  // unsuitable font
    }

    if (nFontType == TRUETYPE_FONTTYPE) {
        lpLogFont->elfLogFont.lfHeight = pfed->TTPointSize;
        lpLogFont->elfLogFont.lfWidth  = 0;
        lpLogFont->elfLogFont.lfWeight = FW_NORMAL;
    }

    /*
     * reject TT fonts for whoom family is not modern, that is do not use
     * FF_DONTCARE    // may be surprised unpleasantly
     * FF_DECORATIVE  // likely to be symbol fonts
     * FF_SCRIPT      // cursive, inappropriate for console
     * FF_SWISS OR FF_ROMAN // variable pitch
     */

    if ((nFontType == TRUETYPE_FONTTYPE) &&
            ((lpLogFont->elfLogFont.lfPitchAndFamily & 0xf0) != FF_MODERN)) {
        DBGFONTS(("    REJECT  face (TT but not FF_MODERN)\n"));
        return bFindFaces ? TRUE : FALSE;  // unsuitable font
    }

    /*
     * reject non-TT fonts that aren't OEM
     */
    if ((nFontType != TRUETYPE_FONTTYPE) &&
            (lpLogFont->elfLogFont.lfCharSet != OEM_CHARSET)) {
        DBGFONTS(("    REJECT  face (not TT nor OEM)\n"));
        return bFindFaces ? TRUE : FALSE;  // unsuitable font
    }

    /*
     * Add or find the facename
     */
    pFN = AddFaceNode(&gpFaceNames, pwszFace);
    if (pFN == NULL) {
        return FALSE;
    }

    if (bFindFaces) {
        if (nFontType == TRUETYPE_FONTTYPE) {
            DBGFONTS(("NEW TT FACE %ls\n", pwszFace));
            pFN->dwFlag |= EF_TTFONT;
        } else if (nFontType == RASTER_FONTTYPE) {
            DBGFONTS(("NEW OEM FACE %ls\n",pwszFace));
            pFN->dwFlag |= EF_OEMFONT;
        }
        return 0;
    }


    if (IS_BOLD(lpLogFont->elfLogFont.lfWeight)) {
        DBGFONTS2(("    A bold font (weight %d)\n", lpLogFont->elfLogFont.lfWeight));
        // return 0;
    }

    /* get font info */
    SizeWant.Y = (SHORT)lpLogFont->elfLogFont.lfHeight;
    SizeWant.X = (SHORT)lpLogFont->elfLogFont.lfWidth;
CreateBoldFont:
    lpLogFont->elfLogFont.lfQuality = NONANTIALIASED_QUALITY;
    hFont = CreateFontIndirectW(&lpLogFont->elfLogFont);
    ASSERT(hFont);
    if (!hFont) {
        DBGFONTS(("    REJECT  font (can't create)\n"));
        return 0;  // same font in other sizes may still be suitable
    }

    DBGFONTS2(("    hFont = %lx\n", hFont));

    //
    // for reasons unbeknownst to me, removing this code causes GDI
    // to yack, claiming that the font is owned by another process.
    //

    SelectObject(hDC,hFont);
    if (!GetTextMetricsW(hDC, &tmi)) {
        tmi = *((LPTEXTMETRICW)lpTextMetric);
    }

    if (GetTextExtentPoint32W(hDC, L"0", 1, &Size)) {
        SizeActual.X = (SHORT)Size.cx;
    } else {
        SizeActual.X = (SHORT)(tmi.tmMaxCharWidth);
    }
    SizeActual.Y = (SHORT)(tmi.tmHeight + tmi.tmExternalLeading);
    DBGFONTS2(("    actual size %d,%d\n", SizeActual.X, SizeActual.Y));
    tmFamily = tmi.tmPitchAndFamily;
    if (TM_IS_TT_FONT(tmFamily) && (SizeWant.Y >= 0)) {
        SizeToShow = SizeWant;
        if (SizeWant.X == 0) {
            // Asking for zero width height gets a default aspect-ratio width
            // It's better to show that width rather than 0.
            SizeToShow.X = SizeActual.X;
        }
    } else {
        SizeToShow = SizeActual;
    }
    DBGFONTS2(("    SizeToShow = (%d,%d), SizeActual = (%d,%d)\n",
            SizeToShow.X, SizeToShow.Y, SizeActual.X, SizeActual.Y));

    // there's a GDI bug - this assert fails occasionally
    //ASSERT (tmi.tmw.tmMaxCharWidth == lpTextMetric->tmMaxCharWidth);

    /*
     * NOW, determine whether this font entry has already been cached
     * LATER : it may be possible to do this before creating the font, if
     * we can trust the dimensions & other info from lpTextMetric.
     * Sort by size:
     *  1) By pixelheight (negative Y values)
     *  2) By height (as shown)
     *  3) By width (as shown)
     */
    for (nFont = 0; nFont < (LONG)NumberOfFonts; ++nFont) {
        COORD SizeShown;

        if (FontInfo[nFont].hFont == NULL) {
            DBGFONTS(("!   Font %x has a NULL hFont\n", nFont));
            continue;
        }


        if (FontInfo[nFont].SizeWant.X > 0) {
            SizeShown.X = FontInfo[nFont].SizeWant.X;
        } else {
            SizeShown.X = FontInfo[nFont].Size.X;
        }

        if (FontInfo[nFont].SizeWant.Y > 0) {
            // This is a font specified by cell height.
            SizeShown.Y = FontInfo[nFont].SizeWant.Y;
        } else {
            SizeShown.Y = FontInfo[nFont].Size.Y;
            if (FontInfo[nFont].SizeWant.Y < 0) {
                // This is a TT font specified by character height.
                if (SizeWant.Y < 0 && SizeWant.Y > FontInfo[nFont].SizeWant.Y) {
                    // Requested pixelheight is smaller than this one.
                    DBGFONTS(("INSERT %d pt at %x, before %d pt\n",
                            -SizeWant.Y, nFont, -FontInfo[nFont].SizeWant.Y));
                    nFontNew = nFont;
                    goto InsertNewFont;
                }
            }
        }

        // DBGFONTS(("    SizeShown(%x) = (%d,%d)\n",nFont,SizeShown.X,SizeShown.Y));

        if (SIZE_EQUAL(SizeShown, SizeToShow) &&
                FontInfo[nFont].Family == tmFamily &&
                FontInfo[nFont].Weight == tmi.tmWeight &&
                wcscmp(FontInfo[nFont].FaceName, pwszFace) == 0) {
            /*
             * Already have this font
             */
            DBGFONTS2(("    Already have the font\n"));
            DeleteObject(hFont);
            pfed->ulFE |= FE_FONTOK;
            return TRUE;
        }


        if ((SizeToShow.Y < SizeShown.Y) ||
                (SizeToShow.Y == SizeShown.Y && SizeToShow.X < SizeShown.X)) {
            /*
             * This new font is smaller than nFont
             */
            DBGFONTS(("INSERT at %x, SizeToShow = (%d,%d)\n", nFont,
                    SizeToShow.X,SizeToShow.Y));
            nFontNew = nFont;
            goto InsertNewFont;
        }
    }

    /*
     * The font we are adding should be appended to the list,
     * since it is bigger (or equal) to the last one.
     */
    nFontNew = (LONG)NumberOfFonts;

InsertNewFont: // at nFontNew

//  ASSERT ((lpTextMetric->tmPitchAndFamily & 1) == 0);
    /* If we have to grow our font table, do it */

    if (NumberOfFonts == FontInfoLength) {
        PFONT_INFO Temp;

        FontInfoLength += FONT_INCREMENT;
        Temp = (PFONT_INFO)HeapReAlloc(pConHeap,MAKE_TAG( FONT_TAG ),FontInfo,sizeof(FONT_INFO) * FontInfoLength);
        ASSERT(Temp);
        if (Temp == NULL) {
            FontInfoLength -= FONT_INCREMENT;
            return FALSE;
        }
        FontInfo = Temp;
    }

    if (nFontNew < (LONG)NumberOfFonts) {
        RtlMoveMemory(&FontInfo[nFontNew+1],
                &FontInfo[nFontNew],
                sizeof(FONT_INFO)*(NumberOfFonts - nFontNew));
    }

    /*
     * Store the font info
     */
    FontInfo[nFontNew].hFont = hFont;
    FontInfo[nFontNew].Family = tmFamily;
    FontInfo[nFontNew].Size = SizeActual;
    if (TM_IS_TT_FONT(tmFamily)) {
        FontInfo[nFontNew].SizeWant = SizeWant;
    } else {
        FontInfo[nFontNew].SizeWant.X = 0;
        FontInfo[nFontNew].SizeWant.Y = 0;
    }
    FontInfo[nFontNew].Weight = tmi.tmWeight;
    FontInfo[nFont].FaceName = pFN->awch;

    ++NumberOfFonts;

    if (nFontType == TRUETYPE_FONTTYPE && !IS_BOLD(FontInfo[nFontNew].Weight)) {
          lpLogFont->elfLogFont.lfWeight = FW_BOLD;
          goto CreateBoldFont;
    }

    pfed->ulFE |= FE_FONTOK;  // and continue enumeration
    return TRUE;
}
示例#8
0
int CD3DFont::Init()
{
	// Create vertex buffer for the letters
	HRESULT hr;

	// Prepare to create a bitmap
	unsigned int* pBitmapBits;
	BITMAPINFO bmi;
	ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
	bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biCompression = BI_RGB;
	bmi.bmiHeader.biBitCount = 32;

	// Create a DC and a bitmap for the font
	HDC hDC = CreateCompatibleDC(nullptr);
	HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, nullptr, 0);
	SetMapMode(hDC, MM_TEXT);

	// create a GDI font
	HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE,
		FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
		VARIABLE_PITCH, _T("Tahoma"));
	if (nullptr == hFont) return E_FAIL;

	HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap);
	HGDIOBJ hOldFont = SelectObject(hDC, hFont);

	// Set text properties
	SetTextColor(hDC, 0xFFFFFF);
	SetBkColor(hDC, 0);
	SetTextAlign(hDC, TA_TOP);

	TEXTMETRICW tm;
	GetTextMetricsW(hDC, &tm);
	m_LineHeight = tm.tmHeight;

	// Loop through all printable characters and output them to the bitmap
	// Meanwhile, keep track of the corresponding tex coords for each character.
	int x = 0, y = 0;
	char str[2] = "\0";
	for (int c = 0; c < 127 - 32; c++)
	{
		str[0] = c + 32;
		SIZE size;
		GetTextExtentPoint32A(hDC, str, 1, &size);
		if ((int)(x + size.cx + 1) > m_dwTexWidth)
		{
			x = 0;
			y += m_LineHeight;
		}

		ExtTextOutA(hDC, x + 1, y + 0, ETO_OPAQUE | ETO_CLIPPED, nullptr, str, 1, nullptr);
		m_fTexCoords[c][0] = ((float)(x + 0)) / m_dwTexWidth;
		m_fTexCoords[c][1] = ((float)(y + 0)) / m_dwTexHeight;
		m_fTexCoords[c][2] = ((float)(x + 0 + size.cx)) / m_dwTexWidth;
		m_fTexCoords[c][3] = ((float)(y + 0 + size.cy)) / m_dwTexHeight;

		x += size.cx + 3;  // 3 to work around annoying ij conflict (part of the j ends up with the i)
	}

	// Create a new texture for the font
	// possible optimization: store the converted data in a buffer and fill the texture on creation.
	//							That way, we can use a static texture
	ID3D11Texture2D* buftex;
	D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(D3D::GetBaseBufferFormat(), m_dwTexWidth, m_dwTexHeight,
		1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC,
		D3D11_CPU_ACCESS_WRITE);
	hr = device->CreateTexture2D(&texdesc, nullptr, &buftex);
	if (FAILED(hr))
	{
		PanicAlert("Failed to create font texture");
		return hr;
	}
	D3D::SetDebugObjectName(buftex, "texture of a CD3DFont object");

	// Lock the surface and write the alpha values for the set pixels
	D3D11_MAPPED_SUBRESOURCE texmap;
	hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap);
	if (FAILED(hr)) PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__);

	for (y = 0; y < m_dwTexHeight; y++)
	{
		u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch);
		for (x = 0; x < m_dwTexWidth; x++)
		{
			const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff);
			*pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF;
		}
	}

	// Done updating texture, so clean up used objects
	context->Unmap(buftex, 0);
	hr = D3D::device->CreateShaderResourceView(buftex, nullptr, ToAddr(m_pTexture));
	if (FAILED(hr)) PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__);
	SAFE_RELEASE(buftex);

	SelectObject(hDC, hOldbmBitmap);
	DeleteObject(hbmBitmap);

	SelectObject(hDC, hOldFont);
	DeleteObject(hFont);

	// setup device objects for drawing
	m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader);
	if (m_pshader == nullptr) PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__);
	D3D::SetDebugObjectName(m_pshader.get(), "pixel shader of a CD3DFont object");

	D3DBlob vsbytecode;
	D3D::CompileShader(DX11::D3D::ShaderType::Vertex, fontvertshader, vsbytecode);
	if (vsbytecode.Data() == nullptr) PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__);
	m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode);
	if (m_vshader.get() == nullptr) PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__);
	D3D::SetDebugObjectName(m_vshader.get(), "vertex shader of a CD3DFont object");

	const D3D11_INPUT_ELEMENT_DESC desc[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode.Data(), vsbytecode.Size(), ToAddr(m_InputLayout));
	if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);

	D3D11_BLEND_DESC blenddesc;
	blenddesc.AlphaToCoverageEnable = FALSE;
	blenddesc.IndependentBlendEnable = FALSE;
	blenddesc.RenderTarget[0].BlendEnable = TRUE;
	blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
	blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
	blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	hr = D3D::device->CreateBlendState(&blenddesc, ToAddr(m_blendstate));
	CHECK(hr == S_OK, "Create font blend state");
	D3D::SetDebugObjectName(m_blendstate.get(), "blend state of a CD3DFont object");

	D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false);
	hr = D3D::device->CreateRasterizerState(&rastdesc, ToAddr(m_raststate));
	CHECK(hr == S_OK, "Create font rasterizer state");
	D3D::SetDebugObjectName(m_raststate.get(), "rasterizer state of a CD3DFont object");

	D3D11_BUFFER_DESC vbdesc = CD3D11_BUFFER_DESC(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
	if (FAILED(hr = device->CreateBuffer(&vbdesc, nullptr, ToAddr(m_pVB))))
	{
		PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__);
		return hr;
	}
	D3D::SetDebugObjectName(m_pVB.get(), "vertex buffer of a CD3DFont object");
	return S_OK;
}