You are not logged in or registered. Please login or register to use the full functionality of this board...
The QB64 Edition
Waltersmind's - Full Color Animated LED Sign - Printable Version

+- The QB64 Edition (http://www.thejoyfulprogrammer.com/qb64/forum)
+ Thread: Waltersmind's - Full Color Animated LED Sign (/showthread.php?tid=211)



Waltersmind's - Full Color Animated LED Sign - Waltersmind - 01-31-2015 03:19 AM

Donald,

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;
    union{
        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: https://www.youtube.com/channel/UCkkN3_BL4IAyOc9a1MoUr1A