May Seventeenth 2005 From: Bob Zale, President PowerBASIC, Inc. Subject: Graphics Support in PowerBASIC ======================================= Welcome to the latest edition of the PowerBASIC Gazette! In the coming months, we'll publish a number of articles to explore a variety of new functions in PowerBASIC 8 for Windows, as well as the PowerBASIC Console Compiler 4. In this edition, we'll concentrate on the graphics capabilities of these new compilers. We've got some great sample programs, too. You can download both the source and the executables -- so even if you don't yet have the new versions, you'll see just what they can do! We've got PowerBASIC PONG, just like the old arcade game. Then there's HITGAME, a devilish quest to whack some floppy disks. And a few others to show just how easy it is to print text and graphics all in one! But more about that later. First, look at what the new compilers offer... Graphic Background ================== This version of PowerBASIC offers an excellent graphics package for most any programming need. It's fast. It's complete. And it handles all those messy Windows details for you... automatically! First, it's good to know that graphics in PowerBASIC are persistent. Create it once... and forget it. You'll never need to worry about redrawing or "double buffering" with PowerBASIC. When your graphics are temporarily covered, or the window is minimized, PowerBASIC handles all the messy details automatically! When the window is again made visible, PowerBASIC restores the graphics instantly. It's just that simple. Graphic Capabilities ==================== Just what can PowerBASIC do for you? Plenty. You can use graphics to create simple text, just like you would with the old PRINT statements. You can improve it with a variety of fonts and colors. You can draw charts, pictures, and more, with surprising ease! PowerBASIC offers a complete range of graphic primitives. Lines, points, fills. Circles, ellipses, rounded rectangles. Boxes and pie sections. Ovals, polygons, polylines, and more. You control the line width, the color, and the line style. You control just about everything. You also get text. Plain or fancy text. Any font. Any color, Any size. Bold, italic, underline, or strikeout. You can mix fonts, any combination of fonts, on a single window. Plus, you can position the text at any location on the target, measuring pixel by pixel. Then, you get bitmaps. Create them from scratch, load them from a resource, load and save a BMP file on disk. You can copy them, stretch or shrink them. Change them. Display them in a window. Even mix their colors with those colors which already exist. Next, you get device independent bitmaps (DIB). This is an interesting feature you'll learn to love. You can copy any image into DIB format, where each pixel is stored in succession as a long integer color value. Then, just manipulate the pixels directly as a set of long integers. Just imagine how easy it would be to change all the red pixels to blue. Or most any other specialized task you could imagine. When you're done, just copy it back, over the original, for an instant modified display. Finally, you get scaled coordinates. You can design the coordinate system that suits your particular need, even if you want fractional floating point values. For example, you might specify the upper left corner as (0, 0), and the lower right corner as (1, 1). That means the center of the window is simply (0.5, 0.5). Of course, you can use any values in the range of a single-precision floating point variable. If x2 is greater than x1, coordinates grow larger as they move to the right. Otherwise, they grow larger as they move to the left. If y2 is greater than y1, coordinates grow larger as they move downward. Otherwise, they grow larger as they move upward. Graphic Canvas ============== First things first. You'll need a "canvas". A workspace where you can draw your works of art. These are specially designed to work with the Graphic statements in PowerBASIC. Here you have up to three choices. But remember, any number of these workspaces can exist at any time. 1- GRAPHIC WINDOW - You can use the Graphic Window statement to create a new window on the desktop. This window is immediately visible. GRAPHIC WINDOW caption$, x&, y&, wide&, high& TO hWin??? The first parameter caption$ specifies the text to be displayed in the title or caption bar of the Graphic Window. If caption$ has a length of zero, the window is displayed without a title bar, so the appearance is different and the window can not be dragged by the user. Next, x& and y& specify the location of the new window, in pixels, relative to the upper left corner of the screen. Then, wide& and high& specify the size of the new window, in pixels. Finally, hWin??? is a DWord variable which receives the handle of the newly created window. This handle is used to identify this window with other statements. If the window can not be created, then hWin??? is set to zero. 2- BITMAP - This is a "behind the scenes" workspace, sometimes known as a "Memory Bitmap" or "Off-Screen Bitmap". These special bitmaps are used to construct an image, but are never visible directly. You create your image on a Bitmap, then copy or stretch it to a visible window when you are ready. Use Graphic Bitmap New to create a blank bitmap, or Graphic Bitmap Load to create a bitmap from an image in a resource or disk file. GRAPHIC BITMAP NEW wide&, high& TO hBmp??? GRAPHIC BITMAP LOAD BitName$, wide&, high& TO hBmp??? hBmp??? is a DWord variable which receives the handle of the newly created bitmap. This handle is used to identify this bitmap with other statements. If the bitmap can not be created, then hBmp??? is set to zero. 3- GRAPHIC CONTROL - You can use CONTROL ADD GRAPHIC to add a Graphic Control to any dialog in PowerBASIC for Windows (Of course, this option is not available in PB/CC, as it doesn't offer Dialogs and Controls). It's much like a Label Control, except you can draw and print text to it. A graphic control follows visibility rules just as any other control on the dialog. CONTROL ADD GRAPHIC, hDlg, id&, "", x&, y&, wide&, high&[,styl&, exstyl&] The parameters hDlg??? and id& are used to identify this control with other graphic statements in PowerBASIC. Graphic Target ============== Since it's possible to have more than one canvas in existence at a time, there must be some way to determine which one to use. PowerBASIC uses the Graphic Attach statement for that purpose: GRAPHIC ATTACH hndl, id [, REDRAW] You use GRAPHIC ATTACH to choose a "graphic target". The parameters you enter for hndl and id specify which canvas to use with graphic operations which follow. If the target is a Graphic Window, use hWin and zero. If the target is a Bitmap, use hBmp and zero. If the target is a Graphic Control, use hDlg and id. Once a graphic target is attached, it remains attached until you execute another GRAPHIC ATTACH to change it. Move back and forth, as often as necessary, to accomplish your needs. The graphic target is maintained on a thread-by-thread basis. Therefore, a program with six threads could easily maintain six graphic windows, one for each of them. Of course, if you wish to allow multiple threads to each access a single graphic target, each thread must execute a separate GRAPHIC ATTACH statement. The optional parameter REDRAW causes all graphic statements to be buffered, until a GRAPHIC REDRAW statement is executed, or the operating system chooses to update the target window. Without REDRAW, all graphical statements (Line, Box, Print, etc.) are performed immediately. However, in certain intensive drawing operations, it may be preferable to delay the display until a number of statements have been performed. In some cases, this can improve your overall performance dramatically. Graphic Position ================ Some GRAPHIC functions use the concept of an implied "graphic position" to determine the default point on the graphic target where the next operation will take place. In PowerBASIC, we use the keyword POS to refer to this position (See GRAPHIC GET POS and GRAPHIC SET POS to alter or retrieve this position). POS is also commonly known as the LPR (Last Point Referenced) or even NPR (Next Point Referenced). For most purposes, you can consider these three terms to be synonymous. When a Graphic Window or Graphic Bitmap is created, the default POS is set to (0,0), which is the upper left corner. Unless you specify otherwise, the first graphical operation starts at that point, and the completion point is then saved as the new POS. So, if you draw a line from (0,0) to (100,100), that last point (100,100) is saved as the new POS. The next line you draw would then, by default, start at (100,100), and then automatically save its completion point as the updated POS for next time. The "Graphic Position" (POS) is used by GRAPHIC LINE, GRAPHIC PAINT, GRAPHIC PRINT, and GRAPHIC SET PIXEL. Other graphic functions neither use nor update POS. Graphic Color ============= PowerBASIC allows you to specify all colors as an RGB value. That's a long integer value in the range of 0 to &H00FFFFFF. It is used to specify a very precise color to various PowerBASIC functions and Windows API functions. The lowest three bytes of the value each specify the intensity of a primary color which combine to form the resultant color. Byte 1 (the lowest) represents the red component, byte 2 the green, and byte 3 the blue. They can each take on a value in the range of 0 to 255. Byte 4 (highest) is always 0. The RGB() function can be used to easily create an RGB value from the three component values. PowerBASIC has predefined a number of equates for common colors (%black, %blue, %cyan, %green, %gray, %ltgray, %magenta, %red, %white, %yellow). You may use these whenever it is convenient to do so. Some Windows API functions, namely those which reference Device Independent Bitmaps (DIB), require that the colors be specified in the reverse sequence (Blue-Green-Red instead of Red-Green-Blue). In order to maximize execution speed, PowerBASIC statements and functions which reference these structures also use the BGR format, namely GRAPHIC GET/SET BITS. The BGR function translates an RGB value to its BGR equivalent by swapping the first and third bytes and returning the result. Because of the nature of the translation, calling BGR() a second time converts a BGR value back to its original RGB format. For example, the value of red is &H0000FF. BGR() translates it to &HFF0000. Calling it a second time converts the value back to the original value &H0000FF. You can set the default foreground and background colors with the Graphic Color statement. GRAPHIC COLOR foreground& [, background&] Both the required foreground color and the optional background color are specified as RGB values. If either parameter is -1, the default foreground or background color is used. If the background parameter is -2, the background is made transparent. Many Graphic statements allow you to override the default color, and use an explicit color for that statement only. This has no effect on the default colors, unless another Graphic Color statement is executed. Bounding Rectangle ================== Some GRAPHIC functions, namely those involved with the drawing of curves (GRAPHIC ARC, GRAPHIC ELLIPSE, and GRAPHIC PIE), utilize the concept of a "bounding rectangle" to determine their size and position on the graphic target. A bounding rectangle is defined as the smallest rectangle which can be drawn around the circle or ellipse. For example, let's say you wish to draw a circle centered at position (200,200), which has a radius of 100 pixels. The upper left corner (x1,y1) of the bounding rectangle would be at (100,100), while the lower right corner of the bounding rectangle would be at (300,300). Execute this program to demonstrate... Function PBMain() Graphic Window "Bounding Rectangle",200,200,400,400 to hWin??? Graphic Attach hWin???, 0 Graphic Box (100,100)-(300,300), 0, %red Graphic Ellipse (100,100)-(300,300), %blue, %gray, 6 Graphic Color %magenta, -1 Graphic Set Pos (101,101) Graphic Print "(100,100)" Graphic Set Pos (201,201) Graphic Print "(200,200)" Graphic Set Pos (301,301) Graphic Print "(300,300)" Sleep 10000 End Function Graphic Text ============ Text may be displayed on a graphic target with the GRAPHIC PRINT statement. GRAPHIC PRINT expr [;expr] [;] An expr is a numeric or string expression. A semicolon can be used as separator between multiple expressions in the same statement. Drawing begins at the last point referenced (POS) by another graphic statement, or the point specified by GRAPHIC SET POS. The upper left corner of the text is positioned at the POS. Upon completion, the POS is moved to the left margin of the next line. However, if a trailing semi-colon is included, movement to the next line is suppressed. So, in its simplest form, Graphic Print is very much like a standard Print statement in text mode. If you compile: GRAPHIC PRINT "Red" GRAPHIC PRINT "White" GRAPHIC PRINT "Blue" You'll get: Red White Blue But there's more... So much more... For example, if you'd like to display the text in the color magenta, "Times New Roman" font, at 18 point size, with bold and italic attribute, just use this: GRAPHIC COLOR %Magenta GRAPHIC FONT "Times New Roman", 18, 3 GRAPHIC PRINT "Red" GRAPHIC PRINT "White" GRAPHIC PRINT "Blue" The possibilities are virtually endless. The point is, graphic text printing can be as simple or as complex as you care to make it. The more effort you expend on text display, the better the experience for your user. Windows offers both fixed fonts (like Courier New or Lucida Console), and proportional fonts (most of the rest). In a fixed font, every character is precisely the same size. In a proportional font, all characters are the same height, but the width varies from one to the next. For example, the character "W" is much wider than the character "i". This gives a pleasant appearance to the text, but poses a sure challenge to the programmer. If your text has a lot of wide characters, you may just print right off the right side of the window! What if you want to center text on the window, or even right-justify it? PowerBASIC offers GRAPHIC TEXT SIZE, for just that purpose! GRAPHIC TEXT SIZE expr$ TO x!, y! You can measure the size of a string to be printed with Graphic Text Size, before you ever display it. Be sure the font, point size, and text style have already been set, then execute it. expr$ is the string expression you wish to measure. x! and y! are variables which receive the text width and height. The sizes returned are specified in pixels, dialog units, or world coordinates, depending your choice at creation and your use of the GRAPHIC SCALE statement. Once you have the print size, it's a simple calculation to determine the appropriate start position. Device Independent Bitmaps (DIB) ================================ When working with graphics in Windows, most images are stored as Device Dependent Bitmaps. In other words, every video card, printer, scanner, etc., may well have it's own proprietary format for a bitmap. Obviously, that causes some compatibility issues, but PowerBASIC resolves virtually all of them automatically. Therefore, it's really not important that the PowerBASIC programmer even care about internal formats. Most of the time. Consider this simplistic example: You wish to scan an 800 x 800 bitmap, changing every red pixel to blue. That would require a minimum of 640,000 iterations of GRAPHIC GET PIXEL, then more compares, and more iterations of GRAPHIC SET PIXEL. A very time-consuming task. Why couldn't we just scan through the memory image and make changes on the fly? We can do that! GRAPHIC GET BITS TO bitvar$ GRAPHIC SET BITS bitexpr$ PowerBASIC provides two statements to facilitate that very concept. The GET version retrieves a copy of the target bitmap, storing it as a device independent bitmap in a dynamic string variable. You can then examine it, modify it, and use the SET version to put it back, automatically displaying it where appropriate. It's just that simple. So, what's the format of this DIB? It's almost identical to the standard Windows DIB, but simplified a bit more. The bitvar$ string will contain a series of four-byte values, each of which which represents a long integer. You can convert the four-byte string sections to numeric values with the CVL function, and convert a numeric value to a four-byte string with MKL$. The first four-byte value specifies the width of the bitmap, in pixels, and the second specifies the height. Following that will be one four-byte value for each pixel in the bitmap, which represents the color of that pixel. So, a 20 by 20 bitmap would have 400 pixels and require 1600 bytes (400 * 4), plus 4 bytes for the width and 4 bytes for the height, or a total of 1608 bytes. The first four-byte pixel value in the string represents the top-left corner of the image, the second represents the second pixel of the first row, and so on. After the last pixel of the first row will be the first pixel of the second row, etc. Of course, if execution speed is most important, it's likely that the string can be manipulated most efficiently with pointers. Some Windows API functions, namely those which reference Device Independent Bitmaps (DIB), require that colors be specified in the reverse of normal RGB sequence (Blue-Green-Red instead of Red-Green-Blue). To maximize performance, GRAPHIC GET BITS and GRAPHIC SET BITS use BGR format as well. You can use the BGR() function to translate an RGB value to its BGR equivalent. ' Change all red pixels to blue ' DIM PixelPtr AS LONG PTR GRAPHIC GET BITS TO bmp$ xsize& = CVL(bmp$,1) ysize& = CVL(bmp$,5) PixelPtr = STRPTR(bmp$) + 8 FOR i& = 1 TO xsize& * ysize& IF @PixelPtr = BGR(%red) THEN @PixelPtr = BGR(%blue) INCR PixelPtr NEXT GRAPHIC SET BITS bmp$ While this was a fairly trivial example, it should give you some ideas for additional possibilities. Using DIB structures, you can do most anything! Create a better ELLIPSE or PAINT function? Sure. Create 3-D images? Absolutely. When you have access to the entire bitmap buffer, you've eliminated all your limits. Put it all together? ==================== In just these few paragraphs, you've learned all about the structure of PowerBASIC Graphics. As you can see, it's really very straightforward. So let's put it together and make a simple graphics program... FUNCTION PBMain () Graphic Window "Graphics", 50, 50, 400, 400 to hWin??? Graphic Attach hwin???, 0 for i& = 1 to 50 x1& = rnd(0,399) x2& = rnd(0,399) y1& = rnd(0,399) y2& = rnd(0,399) clr& = rnd(0,&HFFFFFF) GRAPHIC ELLIPSE (x1&,y1&)-(x2&,y2&), clr& next sleep 3000 End Function A simple program to create 50 random ellipses! You can add other code, using various GRAPHIC statements to draw arcs, circles, lines, squares and rectangles (even with rounded corners), pie sections, polygons, polylines, and more! You can draw objects pixel by pixel. Use bitmaps, even create them from scratch. You can set color mix modes, even copy bitmaps, or stretch them to fit! We'll get into the other GRAPHIC functions in the next Gazette. Is it that easy? ================ You bet it is. Jump in and try some PowerBASIC graphics. You'll be amazed at what you can do with a little practice. When you find some good code, why not post it on the PowerBASIC Forums: http://www.powerbasic.com/support/pbforumsWe'd love to see some of your graphic code! So would many others, and they'll respond by posting their latest tidbits! So stay tuned... Lots more to follow on the web site... and the next Gazette! Ready for some sample programs? =============================== Get 'em while they're hot! PowerBASIC PONG... HITGAME... Examples of text justification, text rotation, even 3D text! Download both source and executables at: http://www.powerbasic.com/files/pub/demos/pbgraph.zip It's all in there! Time for a "Hard Break" {smile} =============================== Please indulge me for one moment? If you haven't yet upgraded to the new compilers, now is certainly the time! Check out all the great new features on any of the following pages... PB/CC 4.0: http://www.powerbasic.com/products/pbcc/ PB/WINDOWS 8.0: http://www.powerbasic.com/products/pbdll32/ PowerBASIC FORMS: http://www.powerbasic.com/products/pbforms/ PowerSHIRT 1.0: http://www.powerbasic.com/products/pbshirt/ PB/WIN 8 is attractively priced at $199, while PB/CC 4 is just $169. Upgrades from versions 7 and 3 are just $99 and $89 respectively. PowerBASIC Forms is priced at $99, while the upgrade to version 1.5 is $39. You can order by replying to this email. You can call us today at (800)780-7707 or (941)408-8700, place an e/order on our secure web site at https://www.powerbasic.com/shop/ or even mail it in. But no matter what method you choose, please do it now and with confidence. Every product PowerBASIC ships for physical delivery is offered with a money-back guarantee for a full 30 days from the transaction date. The next Gazettes will cover more graphics, printing text and graphics to Windows-only printers, and lots more. Like signed and unsigned BIT FIELD variables. THREADED variables for Thread Local Storage. ARRAY ASSIGN. Many new CONSOLE functions. FIELD for dynamic structures. New error processing functions. Even KEY functions, DESKTOP, and much, much more. Be sure you have the latest compilers... You won't want to miss this! Best regards, Bob Zale, President PowerBASIC Inc. p.s. Don't forget PowerSHIRT version 1.0! The new PowerBASIC T-Shirt! It's a high quality, black T-Shirt, emblazoned with "PowerBASIC.COM", and a personal motto "I Compile Without Compromise". You couldn't be more stylish! The new PowerSHIRT 1.0 is available in sizes M/L/XL/XXL/XXXL, and priced at just $19.95. http://www.powerbasic.com/products/pbshirt/