Waltersmind's - Full Color Animated LED Sign
01-30-2015, 02:32 AM (This post was last modified: 04-08-2015 07:38 PM by Waltersmind.)
Post: #1
 (Print Post)
Today, I decided to take a little break from all the projects I am currently working on, and take this time to actually create the full-color animated LED sign that I spoke about a long time ago.

So with no further ado, here is the code to my new 2D graphical master-piece:

Code Snippet: [Select]
DIM CurrentScreen AS LONG
DIM LedSignTitle AS LONG



DIM ScrollLeft AS _BYTE

ScreenWidth = 800
ScreenHeight = 600
ImgMode = 32

LedWidth = 87
LedHeight = 57
LedBulbSize = 8

ScrollLeft = 1

CurrentScreen = _NEWIMAGE(ScreenWidth, ScreenHeight, ImgMode)
LedSign = _NEWIMAGE(LedWidth, LedHeight, ImgMode)
LedSignDup = _NEWIMAGE(LedWidth, LedHeight, ImgMode)
LedSignBG = _NEWIMAGE(LedWidth, LedHeight, ImgMode)
LedSignTitle = _NEWIMAGE(LedWidth, LedHeight, ImgMode)
BulbMask = _NEWIMAGE(LedBulbSize + 1, LedBulbSize + 1, ImgMode)

SCREEN CurrentScreen

_DEST BulbMask

FOR rad = LedBulbSize * 2 TO LedBulbSize / 2 STEP -.2
    CIRCLE (LedBulbSize / 2 - .5, LedBulbSize / 2 - .5), rad, _RGBA(20, 0, 0, 128)

FOR rad = LedBulbSize TO 2 STEP -.2
    CIRCLE (LedBulbSize / 2 - .5, LedBulbSize / 2 - .5), rad, _RGBA(0, 0, 0, (40 / LedBulbSize) * rad)

_DEST LedSignTitle

COLOR _RGB(255, 231, 174), _RGBA(0, 0, 0, 0)

FOR y = 0 TO 2
    FOR x = 0 TO 2
        _PRINTSTRING (x + 30, y + 5), "THE"
        _PRINTSTRING (x + 20, y + 20), "JOYFUL"
        _PRINTSTRING (x + 3, y + 35), "PROGRAMMER"

COLOR _RGB(36, 92, 123), _RGBA(0, 0, 0, 0)

    _LIMIT 60

    _DEST LedSignBG
    _PUTIMAGE (0, 0), LedSignBG, LedSignDup
    _PUTIMAGE (0, 0), LedSignDup, LedSignBG, (ScrollLeft, 0)-(_WIDTH(LedSign), _HEIGHT(LedSign))
    LINE (LedWidth - ScrollLeft, 0)-(LedWidth, LedHeight), _RGB(45, 0, 0), BF

    FOR i = 1 TO 3
        LINE (RND * LedWidth, RND * LedHeight)-(RND * LedWidth, RND * LedHeight), _RGB(RND * 128, RND * 128, RND * 128), BF

    _PUTIMAGE (110, 10), LedSignBG, CurrentScreen
    _PUTIMAGE (210, 10), LedSignTitle, CurrentScreen

    _PUTIMAGE (0, 0), LedSignBG, LedSign
    _PUTIMAGE (0, 0), LedSignTitle, LedSign

    _DEST LedSign
    LINE (0, 0)-(LedWidth - 1, LedHeight - 1), _RGBA(RND * 128 + 127, RND * 128 + 127, RND * 128 + 127, 255), B

    _PUTIMAGE (10, 10), LedSign, CurrentScreen

    DrawLED 10, 75, LedBulbSize, LedSign, CurrentScreen, BulbMask





BulbSpacing = 1 + BulbSize

FOR by = 0 TO _HEIGHT(ImgSrc) - 1
    FOR bx = 0 TO _WIDTH(ImgSrc) - 1
        DestX1 = x + bx * BulbSpacing
        DestY1 = y + by * BulbSpacing
        DestX2 = x + bx * BulbSpacing + BulbSize - 1
        DestY2 = y + by * BulbSpacing + BulbSize
        _PUTIMAGE (DestX1, DestY1)-(DestX2, DestY2), ImgSrc, ImgDest, (bx, by)-(bx, by)
        _PUTIMAGE (DestX1, DestY1), BulbMask, ImgDest


Here is a screenshot of the Full-Color Animated LED Sign:


Walter Whitman
The Joyful Programmer
Please subscribe to my YouTube channel at:

Dedicated to working with computer programming hobbyists, tinkerers, amateurs, and enthusiasts.
Find all posts by this user
Like Post
The following 1 user Likes Waltersmind's post:
Anthony.R.Brown (01-31-2015)
01-30-2015, 10:44 PM
Post: #2
 (Print Post)

That is a really neat sign for very small code. I'll have to play around with the code to get a better understanding of how it works.

Very nice. Thanks for sharing.

Find all posts by this user
Like Post
01-31-2015, 03:19 AM (This post was last modified: 04-08-2015 07:39 PM by Waltersmind.)
Post: #3
 (Print Post)

This concept behind this Full Color Animated LED Sign is very simple and I wished I had thought of this when I created my red LED scrolling sign. Here is the run down to how I created this effect, minus the playing, testing, and adding of some stuff:

First, it is very rare that I use any screen mode in QB64 other than the 32Bit mode, as I love having a huge palette of colors to work with. With that in mind, I know I will be creating all images, including the main window, or screen, with the _NEWIMAGE keyword. With that keyword, I can define an image of any reasonable size. So I start the demo off by defining a LONG variable to hold the index value of the image I will use as my main screen.

A little side note, when you use _NEWIMAGE to create a usable image, the keyword returns an index number of a negative value that you will need to keep up with so you can access the image later. When you create an image with _NEWIMAGE, or load an external image with _LOADIMAGE, QB64 keeps up with all images with a TYPE array, like the sample below. In c++, the language that a good bit of QB64 is written in, the TYPE is called a STRUCTURE. Here is the actual c++ structure used for all images in QB64, which can be found in qb64\internal\c\common.cpp, starting on line 144:

Code Snippet: [Select]
struct img_struct{
    void *lock_offset;
    int64 lock_id;
    uint8 valid;                          //0,1 0=invalid
    uint8 text;                           //if set, surface is a text surface
    uint8 console;                      //dummy surface to absorb unimplemented console functionality
    uint16 width, height;
    uint8 bytes_per_pixel;            //1,2,4
    uint8 bits_per_pixel;              //1,2,4,8,16(text),32
    uint32 mask;                        //1,3,0xF,0xFF,0xFFFF,0xFFFFFFFF
    uint16 compatible_mode;        //0,1,2,7,8,9,10,11,12,13,32,256
    uint32 color, background_color, draw_color;
    uint32 font;                         //8,14,16,?
    int16 top_row,bottom_row;    //VIEW PRINT settings, unique (as in QB) to each "page"
    int16 cursor_x,cursor_y;        //unique (as in QB) to each "page"
    uint8 cursor_show, cursor_firstvalue, cursor_lastvalue;
        uint8 *offset;
        uint32 *offset32;
    uint32 flags;
    uint32 *pal;
    int32 transparent_color;        //-1 means no color is transparent
    uint8 alpha_disabled;
    uint8 holding_cursor;
    uint8 print_mode;

    //BEGIN apm ('active page migration')
    //everything between apm points is migrated during active page changes
    //note: apm data is only relevent to graphics modes

    uint8 apm_p1;
    int32 view_x1, view_y1, view_x2, view_y2;
    int32 view_offset_x, view_offset_y;
    float x, y;
    uint8 clipping_or_scaling;
    float scaling_x, scaling_y, scaling_offset_x, scaling_offset_y;
    float window_x1, window_y1, window_x2, window_y2;
    double draw_ta;
    double draw_scale;
    uint8 apm_p2;
    //END apm

As you can see, there is a lot of information kept up with for image created or loaded.

Now back to my demo...

I can make the demo screen any size I want, but I choose to keep the resolution at 800 x 600, so it can be easily viewed on most monitors and laptops. So I created the image I will use for my main screen or window like so, "CurrentScreen& = _NEWIMAGE(800, 600, 32)". Once you create an image that you want to use for the main screen, you will need to change the SCREEN to the created image, like, "SCREEN CurrentScreen&".

Now that we have our primary screen (main screen / main window / etc...), I needed to come up with what I wanted to have in the demo. I knew from the beginning I wanted to draw the LED sign straight to the window, so I do not need a storage image for it. I did however need to experiment with the width and height of LED sign, as well as the bulb size, to find something that was going to look good. Since LED's in LED signs are not bumped up together, I knew that I would need to have a little spacing between each bulbs as well. I also wanted to make sure the bulbs where large enough to seen on various sizes of monitors, but small enough to fit as many bulbs on screen as possible. After some experimentation, I felt that if I create a LED bulb size of 8 pixels, bulb spacing of 1 pixel, I could fit 87 bulbs across by 57 bulbs down. I guess I could of done more bulbs on the height, but I wanted to use a small portion at the top to display some of the various images I used to put the complete LED sign together with.

Now that I have my LED sign dimensions in pixels, I knew that I would need to create an image of that size to hold the final drawing that will then be used to draw the larger LED sign later. So, I created an image that is stored in the LedSign& variable.

Now that I got this far, I needed to decide what I wanted to draw on the LED sign. Since I knew this was a demo I would be posting, I wanted to put the words, "THE JOYFUL PROGRAMMER" on it. So I created another image the size of the LED sign, and stored it in the LedSignTitle& variable. I thought about animated the text, but decided it would be more interesting if added random colored filled boxes. I could of drew the boxes on the Led Sign& image, but I wanted to animate the boxes by scrolling them to the left. So I created another image the size of the LED sign to draw the boxes to, and stored it in the LedSignBG& variable. Since I will be using the _PUTIMAGE keyword to scroll the boxes, I had to create yet another image the size of the LED sign called, LedSignDup&, because you cannot use the same image for the source and destination.

To make the bulbs appear round and semi-realistic, I realized I needed to create one last image to create and store the shadows for the bulb.

After creating all the images I needed, I then step into a DO...LOOP area. The first thing I do in it is copy a portion of the LED sign background into the extra image, and then copy the whole extra image back into the LED background image and draw new boxes into it. By doing that, I can create the illusion of scrolling boxes. Then I would copy the LED background, and title onto the LED sign and show both images on screen. Finally, I would cal a SUB that would create the large LED sign.

In the DrawLED SUB, I use two loops to scan through every pixel in the LedSign& image. Inside both loops, I use two _PUTIMAGE keywords to draw each bulb in its rightful place. The first _PUTIMAGE basically takes the current pixel it is on, and draw it on screen as an enlarged pixel, or filled box. drawing bigger pixels with _PUTIMAGE instead of changing the _SOURCE to the LedSign& image, getting the current pixel color, shange the _SOURCE to the main screen, and then draw a fill box with the LINE keyword, which would of been much slower.

Once a larger pixel is drawn, then we copy the bulb mask image on top of the new bigger colored pixel, and this gives you the illusion of a LED bulb. The two _PUTIMAGE keywords are so fast, that you can create any kind of full color animation for the LED sign and still hit 60 frames per second.

Walter Whitman
The Joyful Programmer
Please subscribe to my YouTube channel at:

Dedicated to working with computer programming hobbyists, tinkerers, amateurs, and enthusiasts.
Find all posts by this user
Like Post
The following 1 user Likes Waltersmind's post:
Anthony.R.Brown (01-31-2015)
01-31-2015, 10:51 AM
Post: #4
 (Print Post)
Very Nice Walter

An Amazing Full Color Animated LED Sign Smile

I think you may have read before that I mentioned... I remember when the Real ones came out in the UK (an actual Black Box with LEDS in it) and they were quite Expensive!

People fitted them in Shop & Hotel Windows Etc. Advertising various things & you could just link your Program to a Monitor running from a main PC via a HDMI Cable and do the same on the Cheap! Smile

Find all posts by this user
Like Post
01-31-2015, 10:26 PM
Post: #5
 (Print Post)

That was a great tutorial. I did work with the program a little last night. I changed the message and re-centered it.

I haven't been using 32 bit colors because 256 works ok for me, but I did try using it and had problems. I tried assigning the colors to variables, but got errors. I think that the variables needed to be LONG. I didn't know that at the time. I use screen mode _NEWIMAGE because it allows me to custom size the windows. I know at some point I'll need to switch to 32 bit. I tried saving, loading and displaying images, but was not successful. I even asked for help through the QB64 forum on loading and displaying images in 256 mode, but I got no help that worked for me. Maybe it's not possible to do that in 256 mode. Maybe if I need a little help when I bring it back out, I may ask you for some help.

I have a puzzle game I started a little while ago that will save an image then reloads it back into the game. re-sizes it and then displays it. after have no luck getting help in 256 mode, I put it on the back burner worked on other projects. But the sign has inspired me to want to some day bring it back out get it working, even if I have to do it in 32 bit mode.

I the mean time, I've learned a little more on the DRAW statement. Back when I made my games in GW-BASIC, TA and P was not not included. Menn at QB64 forum help to learn some new techniques. And steve also tried to help with explaining some TRIG statements which I new learned. These forums has some very talented people who shares a lot of knowledge gives a lot of help.

Find all posts by this user
Like Post
02-02-2015, 06:12 PM (This post was last modified: 04-08-2015 07:40 PM by Waltersmind.)
Post: #6
 (Print Post)
Anthony / Donald,

Thank you for the compliments! I am excited that some of my work can bring joy to others, which is what "The Joyful Programmer" is all about.

Anthony, you did mention LED signs in the red color LED sing thread, and I have read them. Also, thank you for the wonderful links you provided in your last post.

It is very easy to change from 256-color images and screens, to 32Bit full color when using the SCREEN & _NEWIMAGE keywords. All you have to do is: SCREEN _NEWIMAGE(Width, Height, 32). The last parameter, the number "32", tells QB64 to create the new image as a 32Bit image.

I have attempted to load 8Bit (256 color) *.BMP images into my test demo using the _LOADIMAGE keyword, and have been both successful and unsuccessful. You can load 8Bit, uncompressed *.BMP images, but you cannot load 8Bit, compressed images into QB64. Plus, even though you can load 8Bit images into QB64, you can not use _PUTIMAGE to place the image onto the screen, or it gives an error. I have no idea at this point what is going on. I would have to do some intense investigation into QB64's source code to figure that out.

All 32Bit Color values need to be stored in a LONG variable like: Colr1& = _RGB(255, 0, 0) or Colr2& = _RGBA(255, 0, 0, 255).

I would fully suggest that you start using the 32Bit image mode, as you would have so much more fun.

The DRAW statement is a long time favorite of mine along with PLAY, though I don't use them in my modern demos. DRAW was the first graphic keyword I learned when I started playing with BASIC on the IBM PC's.

Donald, don't be shy about asking questions on this forum as well. There are some knowledgeable people on both forums that can, and will be happy to help.

Walter Whitman
The Joyful Programmer
Please subscribe to my YouTube channel at:

Dedicated to working with computer programming hobbyists, tinkerers, amateurs, and enthusiasts.
Find all posts by this user
Like Post
02-02-2015, 10:40 PM
Post: #7
 (Print Post)

I am starting to try out 32 bit more and have a better understanding of how to incorporate it into my games. I think that all of me new games I'll start will use 32 bit. Also, I think I might try using QB64 GL also instead of using SDL only. Reading all the posts when I first joined QB64 forum, I was lost in all the conversations about SDL and GL.

When I first downloaded QB64, it was the SDL version. I went on YouTube and watched all the QB64 tutorial series and found that most of the code was the same as my GW-BASIC I used to program in. I anticipated using the 640x480 screen mode for my games, since that's the closet match to 640x400 on the Tandy 2000. After running the 640x480 window, I was shocked to see just how small that window size was. So I went searching for another screen mode. That's when I found _NEWIMAGE and the 256 color palettes worked for me.

I joint that forum right after I completed a few of my games. After posting my games on the QB64 forun, Walter you were the first to respond back. You probably don't remember that with all the new members joining. There has been a few people leave the forum since I joined. I think it's a shame to see members feel they should leave for various reasons. With Anthony the first I saw to leave, But I found a friend with Anthony and you here. Then to see Pete and Menn leave.

Oh, by the way Walter, how do you make one image pass behind another image. For instance: I thinking of enhancing my Connect 4 game. The first change is to highlight the pieces that make up the 4 in a row when a player wins. Instead of making then search for the pattern. Second, I would like the piece that being played drop from the top of the screen and fall behind the game board. When I worked with GameMaker before learning about QB64, you could assign each sprite depth. The smaller the number, the closer the sprite was to front of the screen. For instance: the game board might be given a depth of 100 and the piece a depth of 1000. As the the sprite moves across the screen, the sprite passes behind the images with smaller depth. The images I referring to don't have to be loaded into the game, the pieces are circles that are painted.

Find all posts by this user
Like Post
02-03-2015, 04:34 AM (This post was last modified: 04-08-2015 07:41 PM by Waltersmind.)
Post: #8
 (Print Post)

I will be happy to help you in any way that I can, all you have to do is ask.

The differences between QB64-SDL and QB64-GL are: QB64-SDL is no longer supported, updated, or modified. It is basically obsolete. The SDL designation in QB64-SDL is a reference to the fact that Galleon used SDL 1.0 (Simple DirectMedia Layer) library to help provide more features to QB64. You can find the SDL library at:

QB64-GL introduces OPEN-GL (similar to Direct-X) features that was suppose to provide more powerful 3-D capabilities in QB64, but it is rarely used mainly due to most QB64 users do not understand OPEN-GL, and very little documentation, and samples in QB64's wiki. But Galleon did manage to incorporate OPEN-GL into some of QB64's keywords, to give us hardware acceleration. These include, but not limited to, _NEWIMAGE, _PUTIMAGE, and my favorite _MAPTRIANGLE. You can see these in action in the demo that Steve McNeil and myself (I add some additional features to his original demo) created, the _MAPTRIANGLE Test #1 demo that has Steve's rotating text boxes, and my explosions. This is located at: for those of you who are interested.

I do remember being the first to respond to your games. I don't keep up with all the members on, and there are only a few of us members on this forum that actively participate, so it is very easy to remember everyone. A lot of good programmers and developers have come in gone on, but it has to do with the politics, and what is allowed on the forum. I will not tolerate negative posts, and hateful members on our forum here.

Anthony was not treated with respect over at and he retaliated. I found a friend in Anthony on that forum and I had really enjoy his great posts over there. When I decided to start this forum, I emailed Anthony to let him know what was going on. He was the one that pushed my to go live with the forum long before I wanted to. I was very thankful for that push. When Anthony came aboard on this forum, I didn't have to ask him to act right, because he chose to out of respect, and he has been a valuable asset to our forum by providing great links to many things all over the internet, and providing some really fascinating projects. He has given much more than that, but I don't want to give too big of a head on his shoulders (he he).

And finally, to answer your question about graphics being placed on top of one another. Actually, your answer is in the last sentence. Put simply, all you have to do is draw, or _PUTIMAGE, the images that are in the back first. In the Connect 4 instance, you would draw the chip first, then draw the board on top of it. This is exactly how I draw my animated clock's which you can see at Here is the run down:

• Draw gradient background
• Draw clock face with numbers
• Draw hour hand
• Draw minute hand
• Draw second hand
• Draw clock face
• Display finished masterpiece to the user
• After slight delay (given by _DISPLAY and _LIMIT #) then loop back and start the drawing all over again

Here is some simple code to help you out on the Connect 4 question.

Code Snippet: [Select]
DIM MainScreen AS LONG
DIM Connect4Board AS LONG
DIM BlackPiece AS LONG
'DIM background AS LONG


ScreenWidth = 800
ScreenHeight = 600
SquareSize = 60
HoleSize = SquareSize - 10
PieceSize = SquareSize - 6

MainScreen = _NEWIMAGE(ScreenWidth, ScreenHeight, 32)
Connect4Board = _NEWIMAGE(SquareSize * 7, SquareSize * 6, 32)
RedPiece = _NEWIMAGE(PieceSize, PieceSize, 32)
BlackPiece = _NEWIMAGE(PieceSize, PieceSize, 32)
'background = _NEWIMAGE(ScreenWidth, ScreenHeight, 32)

SCREEN MainScreen

' *** Draw the board
_DEST Connect4Board
FOR y = 0 TO 5
    FOR x = 0 TO 6
        CIRCLE (x * SquareSize + SquareSize / 2, y * SquareSize + SquareSize / 2), HoleSize / 2, _RGB(255, 255, 0)

LINE (0, 0)-(_WIDTH(Connect4Board) - 1, _HEIGHT(Connect4Board) - 1), _RGB(255, 255, 0), B
PAINT (1, 1), _RGB(255, 255, 0)

FOR y = 0 TO 5
    FOR x = 0 TO 6
        CIRCLE (x * SquareSize + SquareSize / 2, y * SquareSize + SquareSize / 2), HoleSize / 2, _RGB(100, 100, 0)

' *** Draw Black Piece
_DEST BlackPiece
CIRCLE (PieceSize / 2, PieceSize / 2), PieceSize / 2, _RGB(32, 32, 32)
PAINT (PieceSize / 2, PieceSize / 2), _RGB(32, 32, 32)

' *** Draw Red Piece
_DEST RedPiece
CIRCLE (PieceSize / 2, PieceSize / 2), PieceSize / 2, _RGB(200, 0, 0)
PAINT (PieceSize / 2, PieceSize / 2), _RGB(200, 0, 0)

    _LIMIT 10

    _DEST MainScreen

    ' *** Draw Background First
    LINE (0, 0)-(ScreenWidth, ScreenHeight), _RGB(40, 40, 200), BF

    ' *** Draw Some Pieces next
    FOR i = 0 TO 10
        p = INT(RND * 2)

        IF p = 1 THEN
            _PUTIMAGE (RND * (SquareSize * 7) + 170, RND * (SquareSize * 6) + 70), RedPiece, MainScreen
            _PUTIMAGE (RND * (SquareSize * 7) + 170, RND * (SquareSize * 6) + 70), BlackPiece, MainScreen
        END IF

    ' *** Draw Connect 4 Board last
    _PUTIMAGE (200, 100), Connect4Board, MainScreen



Walter Whitman
The Joyful Programmer
Please subscribe to my YouTube channel at:

Dedicated to working with computer programming hobbyists, tinkerers, amateurs, and enthusiasts.
Find all posts by this user
Like Post

Forum Jump:

User(s) browsing this thread: 1 Guest(s)

QB64 Member Project - Score 4
QB64 Member Project - Qubic
QB64 Member Project - Blokus
QB64 Member Project - Connect Four
QB64 Member Project - Color Rotating Text
QB64 Member Project - Line Thickness
QB64 Member Project - Touche
QB64 Member Project - Kings Vallery version two
QB64 Member Project - Bowditch curve
QB64 Member Project - Kings Valley verion one
QB64 Member Project - Full Color LED Sign
QB64 Member Project - Pivet version one
QB64 Member Project - Kings Court
QB64 Member Project - ARB Checkers
QB64 Member Project - 9 Board
QB64 Member Project - Martin Fractals version two
QB64 Member Project - Kobolts Monopoly
QB64 Member Project - Domain
QB64 Member Project - Exit
QB64 Member Project - Color Triangles
QB64 Member Project - Martin Fractals version three
QB64 Member Project - Swirl
QB64 Member Project - Point Blank
QB64 Member Project - Basic Dithering
QB64 Member Project - Quarto
QB64 Member Project - Foursight
QB64 Member Project - Dakapo
QB64 Member Project - Rotating Background
QB64 Member Project - Pivot version two
QB64 Member Project - Isolation
QB64 Member Project - Martin Fractals version one
QB64 Member Project - Algeria Weather
QB64 Member Project - Input
QB64 Member Project - Rubix's Magic
QB64 Member Project - STxAxTIC 3D World
QB64 Member Project - Splatter
QB64 Member Project - Amazon
QB64 Member Project - RGB Color Wheel
QB64 Member Project - Overboard
QB64 Member Project - OpenGL Triangles
QB64 Member Project - Martin Fractals version four
QB64 Member Project - Othello
QB64 Member Project - Sabotage
QB64 Member Project - Spinning Color Wheel
QB64 Member Project - MAPTRIANGLE
QB64 Member Project - Inside Moves
QB64 Member Project - Spiro Roses
QB64 Member Project - Dreamy Clock
QB64 Member Project - Red Scrolling LED Sign