Prev: Targetting earlier Windows from VS2008
Next: Deadly embrace between SetUnhandledExceptionFilter() and threadrundown(???) in Server 2003
From: David Given on 20 Jan 2010 19:06 I'm trying to implement a simple Unicode console in a window, in as-low-level-as-possible C (it's a compatibility layer for another C program). Right now I'm storing the text in an array of WCHARs and am using brain-dead code like this: WCHAR* p = buffer; for (int y = 0; y < screenheight; y++) { int ys = y * textheight; for (int x = 0; x < screenwidth; x++) { int xs = x * textwidth; /* code here will eventually set the foreground and background * colour depending on the contents of the buffer, which is why * we're drawing each character individually */ TextOutW(dc, xs, xy, &p, 1); p++; } } However, I'm finding this has two major problems: - firstly, it's not doing any kind of font substitution. If I try to draw a character that's not in the font (which right now is SYSTEM_FIXED_FONT) I just get a black square. That's not what I want. Does Windows GDI do any kind of automatic font substitution, and if so, how do I turn it on? - secondly, and very surprisingly, it's dog slow. It's taking several hundred milliseconds to redraw a 150x40 character window. I thought TextOutW() is the fastest way to draw text? Is there anything I might be doing to slow things down? The redraw speed is the biggest problem; right now it flickers horribly whenever I try to update! I could always double-buffer it, but for heavens' sake it's just *text*, it shouldn't be necessary. Can anyone suggest anything? -- ┌─── dg@cowlark.com ───── http://www.cowlark.com ───── │ │ life←{ ↑1 ⍵∨.^3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵ } │ --- Conway's Game Of Life, in one line of APL
From: [Jongware] on 21 Jan 2010 04:30 David Given wrote: [..] > Right now I'm storing the text in an array of WCHARs and am using > brain-dead code like this: [..] (brain dead code) [..] > - firstly, it's not doing any kind of font substitution. If I try to > draw a character that's not in the font (which right now is > SYSTEM_FIXED_FONT) I just get a black square. That's not what I want. > Does Windows GDI do any kind of automatic font substitution, and if so, > how do I turn it on? Font substitution is an application thing, not an OS feature. You can use various strategies for font substitution -- I'd go for 'simplest is best' if I were you. You would typically need to get all supported characters for all installed font, and sort through them for each 'right' character to display. You'd need to ensure the width is the same, though, or else your calculations go out of whack. > - secondly, and very surprisingly, it's dog slow. It's taking several > hundred milliseconds to redraw a 150x40 character window. I thought > TextOutW() is the fastest way to draw text? Is there anything I might be > doing to slow things down? You are already slowing things down as much as you can (apart from a sleep() call in your inner loop) :-D > [..] which is why > * we're drawing each character individually */ > TextOutW(dc, xs, xy, &p, 1); The overhead of drawing one character at a time is *horrible*. Draw as much as you can in one go. You also don't have to measure every character's width > The redraw speed is the biggest problem; right now it flickers horribly > whenever I try to update! I could always double-buffer it, but for > heavens' sake it's just *text*, it shouldn't be necessary. 150 * 40 = 6000 characters. Each character is at least one filled complex polygon (some characters have more than one poly). You do the math. Even single line-buffering may yield a faster and less-flickery result. http://www.catch22.net/ discusses the basics of drawing complex characters and strings. However, for a simple console you might want to implement your own character glyph cache: one bitmap per character. Blit to screen as fast as possible -- no transparency needed. Store a black-and-white bitmap if you *really* are going for speed-without-the-memory, grayscale if you don't mind some postprocessing (to draw in different colors), or full color, optimized for your screen DC (and you have the choice of cacheing just 'plain' colored text, or all possible color combo's you might need). [Jw]
From: Richard Russell on 21 Jan 2010 04:35 On Jan 21, 12:06 am, David Given <d...(a)cowlark.com> wrote: > I'm trying to implement a simple Unicode console in a window > [snip] > Does Windows GDI do any kind of automatic font substitution Not in the sense you mean, as far as I know. If it's a Unicode console, why are you using SYSTEM_FIXED_FONT anyway? Surely you need to be using a Unicode font such as Lucida Console? > - secondly, and very surprisingly, it's dog slow. It's taking several > hundred milliseconds to redraw a 150x40 character window. Are you sure? That seems an improbably long time. You could speed it up by getting TextOutW to output complete *lines* rather than individual *characters*; that would also have other advantages such as allowing you to use a proportional-faced font and handling kerning better. Have you considered embedding newlines and using DrawTextW to output the whole thing? > The redraw speed is the biggest problem; right now it flickers horribly You don't describe the context in which your code is called. Is it in WM_PAINT? Do you handle WM_ERASEBKGND (or change the class hbrBackground to NULL)? Richard. http://www.rtrussell.co.uk/
From: Richard Russell on 21 Jan 2010 04:44 On Jan 21, 9:35 am, Richard Russell <n...(a)rtrussell.co.uk> wrote: > You could speed it up by getting TextOutW to output complete > *lines* rather than individual *characters*; Or, noting your requirements to change the colour, split the line into blocks having the same foreground and background colour, and output each of those using TextOutW. Richard. http://www.rtrussell.co.uk/
From: David Given on 21 Jan 2010 19:07
On 21/01/10 09:30, [Jongware] wrote: [...] > Font substitution is an application thing, not an OS feature. Well, I come from a Unix background, and there font substitution is done at the GUI level as a matter of course: if you ask for it to render a glyph, and it can't find the glyph in the current font, it'll use Panose to try and find a glyph in the closest matching font to the one you asked for. The end result is that you can draw any text in any script in any font and it will Just Work. It may look a bit funny if you've got an odd set of fonts installed, but it'll work. Applications don't need to worry about it. [...] > The overhead of drawing one character at a time is *horrible*. Draw as > much as you can in one go. This really surprises me. Why is it so much faster to draw multiple glyphs with a single call to TextOutW() than to draw multiple glyphs with multiple calls to TextOutW()? Is this system call overhead? TextOutW() *itself* should just be a simple loop that reads a glyph from the string and draws each one. What does it use to draw the glyphs? Is this function available for application use? [...] > 150 * 40 = 6000 characters. Each character is at least one filled > complex polygon (some characters have more than one poly). You do the > math. Even single line-buffering may yield a faster and less-flickery > result. Surely Windows caches font glyphs in bitmaps! It can't possibly rasterise each glyph onto the screen when the application asks to draw it! > http://www.catch22.net/ discusses the basics of drawing complex > characters and strings. Thanks, lots of good stuff there. > However, for a simple console you might want to implement your own > character glyph cache: one bitmap per character. Blit to screen as fast > as possible -- no transparency needed. This does sound like my best bet. I can do all the complicated work to try and determine which font to use for a glyph lazily, the first time the app tries to draw the glyph (it has to be lazy because I don't know what Unicode subset the app will be using). Does Windows have any standard data structure libraries (hash map, associative array, etc) that will help with this, or will I have to roll my own? In addition, are you *certain* that there isn't a Windows utility somewhere that will do what I want? Unfortunately Windows seems to use the phrase 'font substitution' in a slightly different meaning to the one I'm used to, so I don't know what keywords to search for. Rolling my own is going to be a horrible amount of code, and it's such a universal thing that surely there must be code already on the system that will do it for me... -- ┌─── dg@cowlark.com ───── http://www.cowlark.com ───── │ │ life←{ ↑1 ⍵∨.^3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵ } │ --- Conway's Game Of Life, in one line of APL |