How to efficiently and correctly resize ID3DXFont - c++

I am looking to resize a DirectX font object in a for loop. See below for an example:
for ( int i = 1; i < 20; i++ ) {
// font size should be i
}
It would be inefficient to create a font for every single possible size so I was wondering if I could create some sort of wrapper or my own font renderer that allows me to do so with good performance?
If I don't make much sense, then see the another example below:
// DirectX9
// calling D3DXCreateFont every loop would be incredibly inefficient.
ID3DXFont *example_font;
D3DXCreateFont( device, 14 /* font size - we want this to change */, ..., &example_font );
How can I achieve this? I tried using scale/rotate/transform to simply change the size but the font becomes blurry so I'm looking for a more "correct" solution.
Thank you.

The problem you are encountering is a fundamental limitation of 'raster bitmap' fonts as opposed to 'vector' fonts like TrueType. D3DXFont is a 'raster bitmap' solution that captures a TrueType font into a bitmap at a specific size. This can be scaled/rotated somewhat and still holds up, but you get artifacts if you change the size a lot as you have seen.
It is extremely fast, however, because it's just drawing textures. You can also capture fonts at a few different sizes and pick one based on the resolution.
D3DXFont is part of D3DX9 which means it is deprecated. Of course Direct3D 9 is legacy too, so you should look at Direct3D 11 and SpriteFont/SpriteBatch in the DirectX Tool Kit for a modern 'raster bitmap' font solution.
The correct solution for high-quality, highly scalable text drawing is to use a 'vector font' drawing system like DirectWrite.

Related

Custom frame/decoration for specific X window

Is there any way to apply or have custom frames (images) around specific X windows?
For example, in xfwm4 and fvwm (window managers) it's possible to have a specific window decoration for a window with different images, one at the bottom, other at the top, etc. examples:
For xfwm4 and fvwm.
Obviously if it was that easy, I'd just use either of them, however, I do think that a singular program could handle it instead of needing to change the whole window manager.
I'm currently using dwm and there are ways to change the colour and thickness of border, and that's it. If I was better at C I could create a rule to draw images around specific X windows with specific WM_CLASS, but that's too much for me now, so any help is really appreciated.
An alternative solution would be to draw a single image (from a file) bigger than the X window behind it and make it to follow the X window position, and maybe the size as well (that's harder, so it's not really that necessary)
I started writing a C++ program to do that, but that may take too much time since C++ still a new tool to me and looking at how xfwm4 handles this.

Windows Imaging Component - Direct2D C++ - Drawing, Saving

Using Windows Image Component (WIC), I want to do the following for my windows desktop application (Direct2D/C++ with Windows 7 SP1 - Visual Studio 2013)
Choose any type of RenderTarget (Direct2D Hwnd/Bitmap/WICBitmap -
etc) for drawing
Create a empty bitmap (D2D1Bitmap or IWICBitmap -
whichever applicable)
Begin draw - Fill colour, draw some lines and ellipses -
End draw ==> (All in the Bitmap)
At some point of time, I need to
save the drawn content in the bitmap as an image in my computer
Place the bitmap in the x1,y1 (top left - xy coordinates) and x2,y2
(bottom right - xy coordinates) of the render target. Because the
rest of the space of the window would be used by toolbar.
How do I achieve this using C++/Direct2D?
GDI+ Code for my functionality:
Bitmap* pBmp = NULL; //create null or empty bitmap
Graphics* pGrBuf = NULL; //initialise graphics to null
pBmp = new Bitmap((INT)rectClient.Width, (INT)rectClient.Height);
pGrBuf = new Graphics(pBmp);
On this Graphics, I could always draw Lines, Rectangles, etc..
pGrBuf.DrawRectangle(....)
pGrBuf.DrawLine(...)
In the end, for achieving point number 5
//leave some space (30, 30 in xy co-ordinates) for putting the toolbox in the top
pGrBuf.DrawImage(m_pBmp, 30.0f, 30.0f);
The code for point 4 is intentionally omitted.
The question have a simple, unambiguous answer, but there are some details that you should (re)consider.
Direct2D is not a panacea framework that will easily outperform others. It's not very clear what are your drawings about and whats their purpose, but there are cases where Direct2D usage is not very appropriate. If you replace GDI(+) with D2D, some of your sufferings will be:
(officialy) limited OS support, according to the DirectX version and/or the functions you will use. You will have to forget about Windows XP, (very possibly) Windows Vista and (less possibly) Windows 7
the performance (compared to GDI+, GDI) is not always greater. Mainly depends from the way and the purpose you use D2D. There are cases where D2D has very poor performance (usually wrong usage or misunderstood concepts).
But also, the advantages that Direct2D could provide are countless.
Roughly said, Direct2D is nothing but a wrapper around Direct3D. It was introduced with the DirectX 10 and its usage was very similar to GDI(+). But with DirectX 11(1), the Direct2D "principles" were changed and now its more D3D-like. It adds another approaches and drops old ones. It could be a little bit confusing at first. Confusing, also because all the tutorials, articles and whatever D2D resources (including MSDN) in the web are mixed up between the D2D versions. Some of them are for the old version and recommend one thing (approach), other describe the new version.
Anyway, I recommend the new version - ie Direct2D 11.1.
To your question...
The "RenderTarget" is a concept from the "old" D2D. The new one is a DeviceContext
The DeviceContext has a target that could be a D2D1Bitmap(1) - offscreen one, a swap chain's back buffer.
The most typical drawing approach is to call drawing functions within a DeviceContext.BeginScene --- DeviceContext.EndScene block. The drawing functions are very similar to the GDI(+) ones.
There are several ways to do that. You can do it with the help of WIC. Also you can copy your D2D1Bitmap data to a DIBBitmap or you can even (re)draw it over a GDI context.
There is a function DeviceContext.DrawImage, but the way you will do it depends on many things. For example, you could have two bitmaps, that are drawn over two different HWnd (one for the toolbar, another one for the other drawing).
Here are some resources that could help you:
What is Direct2D for
Drawing a rectangle with Direct2D
Very well explained guide about migrating to Direct2D 1.1
Answer to another question here, related to Direct2D, but explains in short the way you should draw to a HWnd

How to implement zooming in GDI-drawn MFC's CScrollView

I'm drawing some graphics and text with GDI in my CScrollView. I need to implement the zooming functionality. I only need the zoom out functionality, no need to zoom in more than what is normally rendered.
Here are my best ideas:
Use MM_ANISOTROPIC mapping mode with SetWindowExt/SetViewportExt... The problem with this approach is that it does not scale text. Is there any way to force MFC to scale the text as well? Only thing I can think of is to set text font size according to the selected zoom value, but I'm not sure whether this will look well after all...
Draw to memory DC, and use StretchBlt to blit to the client area of appropriate size (set with SetScrollSizes...). This will solve the text scaling issue.
Also it is desirable to have antialiasing effect in the process. I think both methods above should accomplish this per se, but I don't know which will look better. Also I will have to implement printing/print-preview functionality later (using MFC's standard implementation from doc/view architecture), so I need the method to be compatible with that.
Need your advice please. Which way to go and why. Maybe other options exist too?..
You really don't want to mess with the mapping mode when you use MFC -- MFC itself already uses it for (at least) the print preview functionality.
I'd see if SetWorldTransform will work for you. At least with vector/TrueType fonts, it will scale the text along with everything else. Note that before SetWorldTransform will work, you need to call SetGraphicsMode with GM_ADVANCED.
I ended up using the second method I proposed in the question, but used DIBs instead of DDBs (and StretchDIBits() instead of StretchBlt()) because it proved to cause less problems, especially when using big bitmaps, and when printing.

Maximum Size of QPixmap/QImage Windows

I have a QGraphicsView for a very wide QGraphicsScene. I need to draw the background in drawBackground() and the background is a bit complicated (long loop) although it doesn't need to be repainted constantly. I store it in a static QPixmap (I tried QImage too) inside the function drawBackground() and that pixmap is what I draw onto the painter of the view. Only when needed is the QPixmap painted on again.
If I didn't use a static pixmap, the complicated background would be generated every time I scroll sideways for example. The problem is that apparently there is a maximum width for pixmaps on Windows, on my computer it's 32770. I could store a list of pixmaps and draw them side by side but it would make the code uglier and I also don't know what the maximum width of a pixmap is for every Windows machine. Since this might be a well-known problem I was wondering if anyone has a better solution.
Thanks.
You can probably avoid the windows limit by using unaccelerated raster paint device, but 32770*1024 is 100MiB of pixmap; you probably don't want to do that even if Windows would let you.
You've already thought of the usual answer (tile it in more reasonably-sized chunks and load/generate them on demand). The other piece of the usual solution is to use something like QPixmapCache to keep the recently-used tiles so you don't regenerate them too often (only when the user scrolls a long way).
You didn't say how complex your complex background is, but you might also want to look at the Mandelbrot set example for how to do piecewise rendering of an (infinitely) large background pixmap on-demand, without blocking the UI.
This is the common use case for the tiling pattern. Basically you split the background into small images.
I'm not sure why you think "it would make the code uglier". It is certainly not a one-liner. Depending whether you have fixed size background image or not, the tiling code is usually pretty straightforward.

how do I do print preview in win32 c++?

I have a drawing function that just takes an HDC.
But I need to show an EXACT scaled version of what will print.
So currently, I use
CreateCompatibleDC() with a printer HDC and
CreateCompatibleBitmap() with the printer's HDC.
I figure this way the DC will have the printer's exact width and height.
And when I select fonts into this HDC, the text will be scaled exactly as the printer would.
Unfortunately, I can't to a StretchBlt() to copy this HDC's pixels to the control's HDC since they're of different HDC types I guess.
If I create the "memory canvas" from a window HDC with same w,h as the printer's page,
the fonts come out WAY teeny since they're scaled for the screen, not page...
Should I CreateCompatibleDC() from the window's DC and
CreateCompatibleBitmap() from the printer's DC or something??
If somebody could explain the RIGHT way to do this.
(And still have something that looks EXACTLY as it would on printer)...
Well, I'd appreciate it !!
...Steve
Depending on how accurate you want to be, this can get difficult.
There are many approaches. It sounds like you're trying to draw to a printer-sized bitmap and then shrink it down. The steps to do that are:
Create a DC (or better yet, an IC--Information Context) for the printer.
Query the printer DC to find out the resolution, page size, physical offsets, etc.
Create a DC for the window/screen.
Create a compatible DC (the memory DC).
Create a compatible bitmap for the window/screen, but the size should be the pixel size of the printer page. (The problem with this approach is that this is a HUGE bitmap and it can fail.)
Select the compatible bitmap into the memory DC.
Draw to the memory DC, using the same coordinates you would use if drawing to the actual printer. (When you select fonts, make sure you scale them to the printer's logical inch, not the screen's logical inch.)
StretchBlt the memory DC to the window, which will scale down the entire image. You might want to experiment with the stretch mode to see what works best for the kind of image you're going to display.
Release all the resources.
But before you head in that direction, consider the alternatives. This approach involves allocating a HUGE off-screen bitmap. This can fail on resource-poor computers. Even if it doesn't, you might be starving other apps.
The metafile approach given in another answer is a good choice for many applications. I'd start with this.
Another approach is to figure out all the sizes in some fictional high-resolution unit. For example, assume everything is in 1000ths of an inch. Then your drawing routines would scale this imaginary unit to the actual dpi used by the target device.
The problem with this last approach (and possibly the metafile one) is that GDI fonts don't scale perfectly linearly. The widths of individual characters are tweaked depending on the target resolution. On a high-resolution device (like a 300+ dpi laser printer), this tweaking is minimal. But on a 96-dpi screen, the tweaks can add up to a significant error over the length of a line. So text in your preview window might appear out-of-proportion (typically wider) than it does on the printed page.
Thus the hardcore approach is to measure text in the printer context, and measure again in the screen context, and adjust for the discrepancy. For example (using made-up numbers), you might measure the width of some text in the printer context, and it comes out to 900 printer pixels. Suppose the ratio of printer pixels to screen pixels is 3:1. You'd expect the same text on the screen to be 300 screen pixels wide. But you measure in the screen context and you get a value like 325 screen pixels. When you draw to the screen, you'll have to somehow make the text 25 pixels narrower. You can ram the characters closer together, or choose a slightly smaller font and then stretch them out.
The hardcore approach involves more complexity. You might, for example, try to detect font substitutions made by the printer driver and match them as closely as you can with the available screen fonts.
I've had good luck with a hybrid of the big-bitmap and the hardcore approaches. Instead of making a giant bitmap for the whole page, I make one large enough for a line of text. Then I draw at printer size to the offscreen bitmap and StretchBlt it down to screen size. This eliminates dealing with the size discrepancy at a slight degradation of font quality. It's suitable for actual print preview, but you wouldn't want to build a WYSIWYG editor like that. The one-line bitmap is small enough to make this practical.
The good news is only text is hard. All other drawing is a simple scaling of coordinates and sizes.
I've not used GDI+ much, but I think it did away with non-linear font scaling. So if you're using GDI+, you should just have to scale your coordinates. The drawback is that I don't think the font quality on GDI+ is as good.
And finally, if you're a native app on Vista or later, make sure you've marked your process as "DPI-aware" . Otherwise, if the user is on a high-DPI screen, Windows will lie to you and claim that the resolution is only 96 dpi and then do a fuzzy up-scaling of whatever you draw. This degrades the visual quality and can make debugging your print preview even more complicated. Since so many programs don't adapt well to higher DPI screens, Microsoft added "high DPI scaling" by default starting in Vista.
Edited to Add
Another caveat: If you select an HFONT into the memory DC with the printer-sized bitmap, it's possible that you get a different font than what would get when selecting that same HFONT into the actual printer DC. That's because some printer drivers will substitute common fonts with in memory ones. For example, some PostScript printers will substitute an internal PostScript font for certain common TrueType fonts.
You can first select the HFONT into the printer IC, then use GDI functions like GetTextFace, GetTextMetrics, and maybe GetOutlineTextMetrics to find out about the actual font selected. Then you can create a new LOGFONT to try to more closely match what the printer would use, turn that into an HFONT, and select that into your memory DC. This is the mark of a really good implementation.
Another Edit
I've recently written new code that uses enhanced meta files, and that works really well, at least for TrueType and OpenType fonts when there's no font substitution. This eliminates all the work I described above trying to create a screen font that is a scaled match for the printer font. You can just run through your normal printing code and print to an enhanced meta file DC as though it's the printer DC.
One thing that might be worth trying is to create an enhanced metafile DC, draw to it as normal and then scale this metafile using printer metrics. This is the approach used by the WTL BmpView sample - I don't know how accurate this will be but it might be worth looking at (it should be easy to port the relevant classes to Win32 but WTL is a great replacement for Win32 programming so might be worth utilizing.)
Well it won't look the same because you have a higher resolution in the printer DC, so you'll have to write a conversion function of sorts. I'd go with the method that you got to work but the text was too small and just multiply every position/font size by the printer window width and divide by the source window width.