User Tools

Site Tools


direct_20screen_20memory_20access

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

direct_20screen_20memory_20access [2018/03/31 13:19]
127.0.0.1 external edit
direct_20screen_20memory_20access [2018/04/13 15:01] (current)
richardrussell Added syntax highlighting
Line 1: Line 1:
 =====Direct screen memory access===== =====Direct screen memory access=====
  
-//by Richard Russell, March 2007//\\ \\  Normally, your BASIC program doesn'​t have direct access to its //screen memory//, i.e. the contents of the bitmap holding the text and graphics output from the program. The only ways to write to that bitmap are by using BASIC statements and commands (e.g. **PRINT**, **PLOT**, ***MDISPLAY** etc.) or by means of Windows API functions that use the **@memhdc%** //system variable// (e.g. "SYS "​LineTo",​ @memhdc%, 1000, 1000"​). This is perfectly acceptable for most applications,​ but occasionally you may prefer to have direct memory access to the bitmap. An example might be an arcade-style game in which some special animation cannot straightforwardly (or quickly enough) be achieved in BASIC or by using the Windows API.\\ \\  It is possible to set up your program so that you //can// access the bitmap memory. This allows you to write directly to that memory, for example using custom assembler code, to achieve effects that would otherwise be impractical. The first step is to decide what //format// you wish the bitmap to have; typical choices would be **8 bits-per-pixel** (a //​paletted//​ format in which each pixel contains an index to a //colour table//) or **24 bits-per-pixel** (an RGB format containing true colour values). Other formats you might consider using are **16 bits-per-pixel** or **32 bits-per-pixel**.\\ \\  The choice of format typically depends on a trade-off between the number of different colours available (in **8 bits-per-pixel** mode the total number of different colours is 256) and speed (in **24 bits-per-pixel** mode three times as much memory is required to hold a bitmap of the same dimensions).\\ \\  The first step is to define the chosen bitmap format:\\ \\ +//by Richard Russell, March 2007//\\ \\  Normally, your BASIC program doesn'​t have direct access to its //screen memory//, i.e. the contents of the bitmap holding the text and graphics output from the program. The only ways to write to that bitmap are by using BASIC statements and commands (e.g. **PRINT**, **PLOT**, ***MDISPLAY** etc.) or by means of Windows API functions that use the **@memhdc%** //system variable// (e.g. "SYS "​LineTo",​ @memhdc%, 1000, 1000"​). This is perfectly acceptable for most applications,​ but occasionally you may prefer to have direct memory access to the bitmap. An example might be an arcade-style game in which some special animation cannot straightforwardly (or quickly enough) be achieved in BASIC or by using the Windows API.\\ \\  It is possible to set up your program so that you //can// access the bitmap memory. This allows you to write directly to that memory, for example using custom assembler code, to achieve effects that would otherwise be impractical. The first step is to decide what //format// you wish the bitmap to have; typical choices would be **8 bits-per-pixel** (a //​paletted//​ format in which each pixel contains an index to a //colour table//) or **24 bits-per-pixel** (an RGB format containing true colour values). Other formats you might consider using are **16 bits-per-pixel** or **32 bits-per-pixel**.\\ \\  The choice of format typically depends on a trade-off between the number of different colours available (in **8 bits-per-pixel** mode the total number of different colours is 256) and speed (in **24 bits-per-pixel** mode three times as much memory is required to hold a bitmap of the same dimensions).\\ \\  The first step is to define the chosen bitmap format: 
 + 
 +<code bb4w> ​
         DIM BITMAPINFOHEADER{Size%,​ Width%, Height%, Planes{l&,​h&​},​ BitCount{l&,​h&​},​ \         DIM BITMAPINFOHEADER{Size%,​ Width%, Height%, Planes{l&,​h&​},​ BitCount{l&,​h&​},​ \
         \                    Compression%,​ SizeImage%, XPelsPerMeter%,​ YPelsPerMeter%,​ \         \                    Compression%,​ SizeImage%, XPelsPerMeter%,​ YPelsPerMeter%,​ \
Line 13: Line 15:
         bmi.Header.Planes.l&​ = 1         bmi.Header.Planes.l&​ = 1
         bmi.Header.BitCount.l&​ = 8         bmi.Header.BitCount.l&​ = 8
-Here an 8 bits-per-pixel bitmap has been defined; if you want a different format set the value of **bmi.Header.BitCount.l&​** accordingly. The code assumes that you want the bitmap to be the same size as the current window (as obtained from the //system variables// **@vdu%!208** and **@vdu%!212**);​ if you require a different width or height set the structure members accordingly.\\ \\  Because the selected mode is **paletted** a colour table containing an appropriate set of colours must be created:\\ \\ +</​code>​ 
 + 
 +Here an 8 bits-per-pixel bitmap has been defined; if you want a different format set the value of **bmi.Header.BitCount.l&​** accordingly. The code assumes that you want the bitmap to be the same size as the current window (as obtained from the //system variables// **@vdu%!208** and **@vdu%!212**);​ if you require a different width or height set the structure members accordingly.\\ \\  Because the selected mode is **paletted** a colour table containing an appropriate set of colours must be created: 
 + 
 +<code bb4w>
         FOR I% = 0 TO 255         FOR I% = 0 TO 255
           r% = I%           r% = I%
Line 20: Line 26:
           bmi.Palette%(I%) = b% + (g% << 8) + (r% << 16)           bmi.Palette%(I%) = b% + (g% << 8) + (r% << 16)
         NEXT         NEXT
-Here, for simplicity, a grey-scale has been created, where each palette entry contains the same values for red, green and blue. In practice it is more likely that your program will need a selection of colours. You might need to store the colours in, for example, **DATA** statements.\\ \\  Now the bitmap format and colour table have been defined, you can create the bitmap itself:\\ \\ +</​code>​ 
 + 
 +Here, for simplicity, a grey-scale has been created, where each palette entry contains the same values for red, green and blue. In practice it is more likely that your program will need a selection of colours. You might need to store the colours in, for example, **DATA** statements.\\ \\  Now the bitmap format and colour table have been defined, you can create the bitmap itself: 
 + 
 +<code bb4w>
         SYS "​CreateDIBSection",​ @memhdc%, bmi{}, 0, ^bits%, 0, 0 TO hbitmap%         SYS "​CreateDIBSection",​ @memhdc%, bmi{}, 0, ^bits%, 0, 0 TO hbitmap%
         IF hbitmap% = 0 ERROR 100, "​Couldn'​t create DIBSection"​         IF hbitmap% = 0 ERROR 100, "​Couldn'​t create DIBSection"​
Line 27: Line 37:
         SYS "​DeleteObject",​ oldhbm%         SYS "​DeleteObject",​ oldhbm%
         CLS         CLS
-On successful completion of this code the variable **bits%** will contain the address in memory of the bitmap, hence **?bits%** would be the pixel value of the //bottom left// pixel in the window (i.e. it is a **bottom up** bitmap).\\ \\  It is most likely that you will want to '​draw'​ into the bitmap using assembler code, but for the purposes of illustration here is some very simple BASIC code which draws a diagonal line:\\ \\ +</​code>​ 
 + 
 +On successful completion of this code the variable **bits%** will contain the address in memory of the bitmap, hence **?bits%** would be the pixel value of the //bottom left// pixel in the window (i.e. it is a **bottom up** bitmap).\\ \\  It is most likely that you will want to '​draw'​ into the bitmap using assembler code, but for the purposes of illustration here is some very simple BASIC code which draws a diagonal line: 
 + 
 +<code bb4w>
         bytesperpixel% = bmi.Header.BitCount.l&​ DIV 8         bytesperpixel% = bmi.Header.BitCount.l&​ DIV 8
         bytesperline% = ((bmi.Header.Width% * bytesperpixel%) + 3) AND -4         bytesperline% = ((bmi.Header.Width% * bytesperpixel%) + 3) AND -4
Line 37: Line 51:
         NEXT         NEXT
         SYS "​InvalidateRect",​ @hwnd%, 0, 0         SYS "​InvalidateRect",​ @hwnd%, 0, 0
-The variable **bytesperpixel%** contains the number of bytes comprising each pixel (in this example **1**) and the variable **bytesperline%** contains the number of bytes in one line (row) of the bitmap, which must always be rounded up to a multiple of 4.\\ \\  The **InvalidateRect** is necessary to cause the screen to be updated from the new bitmap contents. For best performance you should invalidate only the smallest rectangle containing the changed pixels, but for convenience the code shown invalidates the entire window. If you //do// want to invalidate only a rectangle use code similar to the following:\\ \\ +</​code>​ 
 + 
 +The variable **bytesperpixel%** contains the number of bytes comprising each pixel (in this example **1**) and the variable **bytesperline%** contains the number of bytes in one line (row) of the bitmap, which must always be rounded up to a multiple of 4.\\ \\  The **InvalidateRect** is necessary to cause the screen to be updated from the new bitmap contents. For best performance you should invalidate only the smallest rectangle containing the changed pixels, but for convenience the code shown invalidates the entire window. If you //do// want to invalidate only a rectangle use code similar to the following: 
 + 
 +<code bb4w>
         DIM rc{l%, t%, r%, b%}         DIM rc{l%, t%, r%, b%}
         REM Load rectangle dimensions here (left, top, right, bottom)         REM Load rectangle dimensions here (left, top, right, bottom)
         SYS "​InvalidateRect",​ @hwnd%, rc{}, 0         SYS "​InvalidateRect",​ @hwnd%, rc{}, 0
-If you are performing some kind of animation, it is quite likely that you will want to force an immediate screen refresh:\\ \\ +</​code>​ 
 + 
 +If you are performing some kind of animation, it is quite likely that you will want to force an immediate screen refresh: 
 + 
 +<code bb4w>
         *REFRESH         *REFRESH
 +</​code>​
 +
 You can still use the majority of the standard BASIC or Windows API methods of writing to the output bitmap, in addition to the direct memory access provided by this technique. For example if you want to output text you can use **PRINT**.\\ \\  Note that this technique may not work succesfully if the PC's display is itself set to a paletted (e.g. 256 colour) mode. You can still use the majority of the standard BASIC or Windows API methods of writing to the output bitmap, in addition to the direct memory access provided by this technique. For example if you want to output text you can use **PRINT**.\\ \\  Note that this technique may not work succesfully if the PC's display is itself set to a paletted (e.g. 256 colour) mode.
direct_20screen_20memory_20access.txt · Last modified: 2018/04/13 15:01 by richardrussell