Solved

LED type ticker in C++ for Win95/NT.

Posted on 1998-11-13
16
534 Views
Last Modified: 2013-12-02
I wrote a news ticker in C++ for Win95/NT with MS Visual C++ 5.0. But scrolling simple bitmaps is no fun. I want to make it a LED type looking ticker. I understand I can draw a LED type surface with several CDC::Ellipse() calls. But how do I make different fonts light up LEDs correctly? In other words, when I just draw text on the memory bitmap with selected font, a display pixel is a unit of granularity. With LED type surface though my own LED becomes a unit of granularity and it can be, say, 3 pixels in radius. Any advice on how to display fonts on such a custom surface, where pixels become pretty much custom sized? Thank you for any help.
0
Comment
Question by:LENINGRAD
  • 6
  • 5
  • 4
  • +1
16 Comments
 
LVL 2

Expert Comment

by:harrys
ID: 1177872
Create a memory DC and a select a Bitmap into it.
clear it and draw the font you like into the context.
Allocate some mem and use GetDIBits to copy the bitmap content into a format easy to
handle (8_BPP is a good choise..)
Now go thru the memory and for every pixel (a byte represents is a pixel in 8_BBP) which has the color of the font you draw one of your LED type pixels

0
 
LVL 22

Expert Comment

by:nietod
ID: 1177873
I don't think I would use windows fonts for this.  I would "make a font" instead.  I would determine a "font size" that is the nubmer of LED's high and wide you want the characters to be, say 10 high and 6 wide, for example.  Then create 2D arrays of booleans of these dimensions for each character.  Then write code that "prints" these characters.  
0
 
LVL 22

Expert Comment

by:nietod
ID: 1177874
Actually, maybe a better approach (for the programmer) is to use character arrays instead of arrays of bool, sort of like

const int CharHeight = 10;
const int CharWidth = 6;

Typeef char Pixels[CharWidth*CharHeight] CharData;

CharData A_Data = "  **  "
                                   " *  * "
                                   "*    *"
                                   "*    *"
                                   "******"
                                   "*    *"
                                   "*    *"
                                   "*    *"
                                   "*    *"
                                   "*    *"

Then use an array of pointers to these structures to convet ASII characters to the strucuture that defines it, like
CharData *['Z"-'A'+1] Font = {&A_Data,&B_Data, ....
0
 
LVL 2

Expert Comment

by:harrys
ID: 1177875
That would be easier.. but some people (including me) were not good in designing fonts ;-)
0
 
LVL 22

Expert Comment

by:nietod
ID: 1177876
Its not a matter of "easy"  With this technique you can generate fonts that really have the appropriate LED look.  (i.e they look bad--blocky and simple shapes) If you take a nice windows font and try to convert it, you aren't goign to end up with the right looking result.  The font will probably have lots of curves and thick and thin lines, serifs and other elements that you don't want in your simple LED look.

The other approach would be to turn my suggestion on its head.  Get a font maker program and design a font that has the LED look.  (Actually, you can buy them.  I think I have some.)
0
 

Author Comment

by:LENINGRAD
ID: 1177877
I'd like to keep talking to <harrys>, but if anybody else has ideas I'd be happy to hear them. I don't like <nietod>'s comment because fixed size and type font is not an option.
Rejection reason for <harrys>: this algorithm seems to be cool but I think there is one problem area: when I find the first display pixel to replace with my LED "pixel", this LED "pixel"  will write over adjucent display pixels and, because this is all in the loop, next time around I will mistakenly take the area covered by my LED "pixel" for a display pixel, write my LED "pixel" there and do it again and again and again. Net result will be a very messy font, correct me if I'm wrong. But I think you are moving in the right direction. Off the record: I saw some Java based tickers and they handle LED type tickers for any size any font type. If it can be done in such a silly language, I think it is a matter of our professional pride to do it. But don't take my word for it, check out http://www.ccobb.org/
Thank you everybody for the time spent answering my question.
0
 
LVL 2

Expert Comment

by:harrys
ID: 1177878
If you draw one LED type pixel which has eg. 4x4 real pixels you will just skip the next
three pixels in the row. When you move to process the next LED pixel line you will skip
next 3 lines of real pixels. This avoids overriding adjacent pixels in the resulting image.

0
 
LVL 22

Expert Comment

by:nietod
ID: 1177879
Do you really want "any type font"?  The way I picture an LED display, is that the characters a very blocky and simple shaped characters.  Isn't that what you would want?  Or do you really want to take any font (character shape) and make it drawn with big dots.  (That is not LED-like in my opinion).  In terms of scaling, the way I picture it, the dots that make up the characters should shrink or enlarge, but you should have the same number and pattern of dots regardless of size.  
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 2

Expert Comment

by:wyy_cq
ID: 1177880
install a new font into system.
when your application running, it can load the font.
this is the only way.

if you want to release you software, you can release it with the font ,if it is free.
0
 

Author Comment

by:LENINGRAD
ID: 1177881
Reason for <wyy_cq> rejection is the same: fixed font type and size are not an option, as well as custom designed fonts.

I am accepting the first answer of <harrys>, with using GetDIBits(). Though I'm experimenting with the code myself, I would like <harrys> to send me some short code snippets on GetDIBits()usage in this particular context, if at all possible. Thanks.
0
 
LVL 2

Accepted Solution

by:
harrys earned 250 total points
ID: 1177882
Ok, the example draw a font font into a memorydc and uses GetDIBBits to get the colors (as rgb values in this case) and draw small colored rectangles to the screen. To use this with c++ some casts maybe nessary ;-)

 workdc = CreateCompatibleDC(dc);
 workbmp = CreateCompatibleBitmap(workdc,nWidth,fHeight);
 oldbmp= SelectObject(workdc,workbmp);
 oldfont2 = SelectObject(workdc,font);

 GetObject(workbmp, sizeof(BITMAP), &bm);

 SelectObject(workdc,GetStockObject(WHITE_BRUSH));
 Rectangle(workdc,0,0,nWidth,fHeight);
 SelectObject(workdc,GetStockObject(BLACK_BRUSH));
 TextOut(workdc,0,0,text,strlen(text));


 buffer=malloc((nWidth*fHeight*4)+1);

 bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
 bmi.bmiHeader.biWidth=nWidth;
 bmi.bmiHeader.biHeight=fHeight;
 bmi.bmiHeader.biPlanes=1;
 bmi.bmiHeader.biBitCount=24;
 bmi.bmiHeader.biCompression=BI_RGB;
 bmi.bmiHeader.biSizeImage=0;

 SelectObject(workdc,oldbmp);

 GetDIBits(workdc,workbmp,0,fHeight,buffer,&bmi,0);
 for (y=0;y<fHeight+1;y++) {
 tempbuffer = &buffer[(fHeight-y) *(nWidth+1) * 3];
     for (x=0;x<=nWidth;x++) {
          brush = CreateSolidBrush((*tempbuffer++) <<16 | (*tempbuffer++) <<8 | *tempbuffer++);
          oldbrush = SelectObject(dc,brush);
          Rectangle(dc,x*4,y*4,x*4+4,y*4+4);
          SelectObject(dc,oldbrush);
          DeleteObject(brush);
     }
 }

 GetObject(workbmp, sizeof(BITMAP), &bm);

 SelectObject(workdc,GetStockObject(WHITE_BRUSH));
 Rectangle(workdc,0,0,nWidth,fHeight);
 SelectObject(workdc,GetStockObject(BLACK_BRUSH));
 TextOut(workdc,0,0,text,strlen(text));


 buffer=malloc((nWidth*fHeight*4)+1);

 bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
 bmi.bmiHeader.biWidth=nWidth;
 bmi.bmiHeader.biHeight=fHeight;
 bmi.bmiHeader.biPlanes=1;
 bmi.bmiHeader.biBitCount=24;
 bmi.bmiHeader.biCompression=BI_RGB;
 bmi.bmiHeader.biSizeImage=0;

 SelectObject(workdc,oldbmp);

 GetDIBits(workdc,workbmp,0,fHeight,buffer,&bmi,0);
 for (y=0;y<fHeight+1;y++) {
   tempbuffer = &buffer[(fHeight-y) *(nWidth+1) * 3];
     for (x=0;x<=nWidth;x++) {
          brush = CreateSolidBrush((*tempbuffer++) <<16 | (*tempbuffer++) <<8 | *tempbuffer++);
          oldbrush = SelectObject(dc,brush);
          Rectangle(dc,x*4,y*4,x*4+4,y*4+4);
          SelectObject(dc,oldbrush);
          DeleteObject(brush);
     }
 }

0
 
LVL 2

Expert Comment

by:harrys
ID: 1177883
Ups, it seems like i pressed ctrl-v  to often, sorry for that
0
 

Author Comment

by:LENINGRAD
ID: 1177884
The answer is cool but I'd like to ask for a few clarifications if possible:
1. You calc buffer size as W*H*4+1, in docs I saw another formula ((((W*BitCount)+31)&~31)>>3)*H. They do roundoffs to DWORD-align bmp at end of each scanline. Is your way still OK? 2. If BitCount==24 drivers do not return/gen color table. Typo? 3. Could you explain tempbuffer = &buffer[(fHeight-y) *(nWidth+1) * 3]; a little bit, I mean where does this fancy indice come from?
4. What's the trick with CreateSolidBrush()? And what is the tempbuffer C data type?
0
 

Author Comment

by:LENINGRAD
ID: 1177885
Your pages do not show correct number of points I assigned to <harrys>. The correct number of points is two hundred and fifty (250) and NOT twenty five (25) as it shows now all over the place. Make sure, people, <harrys> gets the right amount: two hundred and fifty, 250 that is.
0
 
LVL 2

Expert Comment

by:harrys
ID: 1177886
ment
>>1. You calc buffer size as W*H*4+1, in docs I saw another formula >>((((W*BitCount)+31)&~31)>>3)*H. They do roundoffs to DWORD-align bmp at end of >>each scanline. Is your way still OK? 2. If BitCount==24 drivers  do not return/gen color >>table.

The forumla you saw is the better one, I just was to lazy to figure out why w*h*3 was not enough to hold the rgb values, and I didn't recall that they use multiples of 4 to store the scanlines, so I just made it big enough. not nice but worked

>>3. Could you explain tempbuffer = &buffer[(fHeight-y) *(nWidth+1) * 3]; a little bit, I >>mean where does this fancy indice come from?

GetDIBits stores the scanlines from the bottom up, but I draw it top -> down, this calculates the scanline to draw..

>>4. What's the trick with CreateSolidBrush()? And what is the tempbuffer C data type?
tempbuffer is (char*) it stores the RGB color values from the bitmap, CreateSolidBrush creates a brush with the same color, this is again a result of my lazyness, for a monocrom bitmap this is  just unnessary, you only need one bit to figure out if a pixel is set. Using RGB values you could "LEDify" any bitmap you have (and the code is shorter, which was the real reason to do it like that.. ;-)

0
 

Author Comment

by:LENINGRAD
ID: 1177887
To <harrys>. Thanks for your answers. Actually, when I tried this code myself, I answered most of my own question. But it still didn't quite work. All the args for CreateSolidBrush() turned out to be 0 all the time, so I got black bmp with a few white rects on it. I don't know what the problem is. May be because data in BITMAP struct, after GetObject() call, doesn't match data that is set manually in BITMAPINFO. Documentation says they have to match. System I tried it on returned 16bpp and compression 3(BI_BITFIELD), while manually we set BITMAPINFO to 24bpp and compression to 0. Also I had to select the original bmp back to device context right after call to GetDIBits() for drawing to take place.
Anyway, I guess I'll take it from here. It is just amazing that Microsoft has no good documentation and examples for this crucial function - small graphics engine in itself.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now