BBC BASIC for Windows
« Bitmap clipper & plotter (BASIC prototypes) »

Welcome Guest. Please Login or Register.
Apr 6th, 2018, 12:03am



ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018.
Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.

If you require a dump of the post on your message board, please come to the support board and request it.


Thank you Conforums members.

BBC BASIC for Windows Resources
Online BBC BASIC for Windows documentation
BBC BASIC for Windows Beginners' Tutorial
BBC BASIC Home Page
BBC BASIC on Rosetta Code
BBC BASIC discussion group
BBC BASIC for Windows Programmers' Reference

« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Bitmap clipper & plotter (BASIC prototypes)  (Read 1236 times)
David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Bitmap clipper & plotter (BASIC prototypes)
« Thread started on: Mar 4th, 2012, 3:38pm »

The BASIC prototypes (to be translated into assembly language) for a bitmap clipper and a 'generic' bitmap plotter are contained in the following - hopefully instructive - program which you can copy and paste into the BB4W IDE, and run.

Perhaps someone might like to use these prototypes as a basis for writing their own bitmap plotters. (Hehe, yeah, and pigs might fly.)

http://www.bb4wgames.com/misc/clipbitmap.html


David.
« Last Edit: Jan 2nd, 2013, 04:59am by David Williams » User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Bitmap clipper & plotter (BASIC prototypes)
« Reply #1 on: Mar 4th, 2012, 4:56pm »

on Mar 4th, 2012, 3:38pm, David Williams wrote:
Perhaps someone might like to use these prototypes as a basis for writing their own bitmap plotters. (Hehe, yeah, and pigs might fly.)

As I mentioned in a recent post, I already have! Mine in fact is a 'sprite' plotter, in that it takes into account the alpha channel of the foreground bitmap (it assumes a pre-multiplied foreground, like all Windows icons do). It also scales (nearest neighbour only, ugh!) and reflects about the x and/or y axis. Most interesting of all, arguably, is that it comes in the form of a position-independent binary module (all of 239 bytes!) that can be loaded anywhere in memory:

http://tech.groups.yahoo.com/group/bb4w/files/Graphics/DrawIconRTR.bin

Here's an adaptation of your program using my plotter:

Code:
      REM. Sprite plotter and clipper using DrawIconRTR.bin relocatable module
      
      MODE 8 : OFF
      
      ON ERROR OSCLI "REFRESH ON" : ON : CLS : REPORT : PRINT " at line "; ERL : VDU 7 : END
      
      DIM mc% 255
      OSCLI "LOAD """ + @lib$ + "DrawIconRTR.bin"" " + STR$~mc%
      DrawIconRTR% = mc% + 3
      
      REM. Create then select a 32-bpp ARGB 'DIBSection' (of dimensions
      REM. @vdu%!208 by @vdu%!212 pixels) into BB4W's DC:
      pBuffer% = FN_createDIBSection( @vdu%!208, @vdu%!212 )
      DIM Buffer{T%,W%,H%,B%,P%,M%}
      Buffer.W% = @vdu%!208
      Buffer.H% = @vdu%!212
      Buffer.M% = pBuffer%
      
      REM. Create a 'test' 128x80, 32-bpp ARGB bitmap to be drawn using PROC_drawBitmap
      REM. Feel free to experiment with the dimensions
      REM. (HIMEM may need to be adjusted if bitmap is too big!)
      bmW% = 128
      bmH% = 80
      bm% = FN_createTestBitmap( bmW%, bmH% )
      DIM Bitmap{T%,W%,H%,B%,P%,M%}
      Bitmap.W% = bmW%
      Bitmap.H% = bmH%
      Bitmap.M% = bm%
      
      DIM pt{X%,Y%}
      
      *REFRESH OFF
      
      scale = 1.0
      REPEAT
        WAIT 2 : CLS
        PRINT "Left button to scale up, right button to scale down, middle button to reflect";
        
        SYS "GetCursorPos", pt{}
        SYS "ScreenToClient", @hwnd%, pt{}
        
        dx% = bmW%*scale
        dy% = bmH%*scale
        
        IF INKEY(-11) dx% = -dx%
        IF INKEY(-10) scale *= 1.05
        IF INKEY(-12) scale /= 1.05
        
        SYS DrawIconRTR%, Buffer{}, pt.X%-ABS(dx%/2), pt.Y%-ABS(dy%/2), \
        \                 Bitmap{}, dx%, dy%
        
        SYS "InvalidateRect", @hwnd%, 0, 0
        *REFRESH
      UNTIL FALSE
      END
      
      REM. ------------------------------------------------------------------------
      REM. The code contained within this function (FN_createDIBSection) is the
      REM. the work of Richard Russell, hereby acknowledged. :)
      REM. ------------------------------------------------------------------------
      DEF FN_createDIBSection( W%, H% )
      LOCAL bits%
      
      DIM BITMAPINFOHEADER{Size%, Width%, Height%, Planes{l&,h&}, BitCount{l&,h&}, \
      \                    Compression%, SizeImage%, XPelsPerMeter%, YPelsPerMeter%, \
      \                    ClrUsed%, ClrImportant%}
      
      DIM bmi{Header{} = BITMAPINFOHEADER{}}
      
      bmi.Header.Size% = DIM(BITMAPINFOHEADER{})
      bmi.Header.Width% = W%
      bmi.Header.Height% = H%
      bmi.Header.Planes.l& = 1
      bmi.Header.BitCount.l& = 32
      
      SYS "CreateDIBSection", @memhdc%, bmi{}, 0, ^bits%, 0, 0 TO hbitmap%
      IF hbitmap% = 0 ERROR 100, "Couldn't create DIBSection"
      
      SYS "SelectObject", @memhdc%, hbitmap% TO oldhbm%
      SYS "DeleteObject", oldhbm%
      CLS
      = bits%
      
      
      
      DEF FN_createTestBitmap( bmW%, bmH% )
      LOCAL bm%, I%, X%, Y%, r%
      
      DIM bm% 4 * bmW%*bmH% +3 : REM. Needs extra 4 bytes (not 3!) for memory alignment
      bm% = (bm% + 3) AND -4   : REM. Ensures bitmap base address is DWORD-aligned (divisible by 4)
      
      REM. Fill our bitmap with the colour "SlateBlue" (= &6A5ACD)
      FOR I% = bm% TO bm% + (4*bmW%*bmH% - 1) STEP 4
        !I% = &6A5ACD
      NEXT I%
      
      REM. Give our bitmap a bright yellow border
      FOR X% = 0 TO bmW%-1
        bm%!(4*X%) = &FFFF00
        bm%!(4*(bmW%*(bmH%-1) + X%)) = &FFFF00
      NEXT X%
      FOR Y% = 0 TO bmH%-1
        bm%!(4*Y%*bmW%) = &FFFF00
        bm%!(4*(Y%*bmW% + (bmW%-1))) = &FFFF00
      NEXT Y%
      
      REM. Draw a sine wave on the bitmap
      FOR X% = 0 TO bmW%-1
        Y% = bmH%DIV2 + bmH%DIV4*SIN(4*PI * X%/(bmW%-1))
        bm%!(4*(Y%*bmW% + X%)) = &FFFFFF
      NEXT X%
      
      REM. Draw a circle on our bitmap
      FOR I% = 0 TO 359
        r% = 0.25 * SQR((bmW%/2)^2 + (bmH%/2)^2)
        X% = bmW%/2 + r%*SINRADI%
        Y% = bmH%/2 + r%*COSRADI%
        IF X% < 0 X% = 0
        IF Y% < 0 Y% = 0
        IF X% > bmW%-1 X% = bmW%-1
        IF Y% > bmH%-1 Y% = bmH%-1
        bm%!(4*(Y%*bmW% + X%)) = &00FF00
      NEXT I%
      
      = bm% 

Richard.
User IP Logged

David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Re: Bitmap clipper & plotter (BASIC prototypes)
« Reply #2 on: Mar 4th, 2012, 6:25pm »

on Mar 4th, 2012, 4:56pm, Richard Russell wrote:
As I mentioned in a recent post, I already have!


It is intended that GFXLIB 3's core library will have a set of clipping routines for different types of graphical 'object' -- bitmaps, rectangles, polygons, arbitrary lines, horizontal and vertical lines, circles, etc.


on Mar 4th, 2012, 4:56pm, Richard Russell wrote:
Mine in fact is a 'sprite' plotter


Excellent, IMHO. I haven't tested its rendering speed, but it looks fast at this end. It doesn't suffer from a peculiar 'artefact' that GFXLIB's GFXLIB_PlotScale (and related routines) exhibit at very small scale factors -- it's hard to describe, but the image gets a bit scrambled, although it doesn't appear to be dangerous (seems to be stable).

You've mentioned in the past that writing position-independent x86-based code is not straightforward and that such code can incur execution speed penalties (or words to that effect). Is that the case with DrawIconRTR.bin?

Given the completeness of the routine (clipped, scaled, alphablended plotting), 239 bytes is impressively small.


David.
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Bitmap clipper & plotter (BASIC prototypes)
« Reply #3 on: Mar 4th, 2012, 9:33pm »

on Mar 4th, 2012, 6:25pm, David Williams wrote:
I haven't tested its rendering speed, but it looks fast at this end.

It was designed to be fast (the inner loop is 16 instructions). Something I ought to have mentioned before is that it requires 'integer SSE' (ISSE) support, which means the minimum processor families on which it will run are an Intel Pentium III or an AMD Athlon. As both of those are about ten years old now that's not too limiting, but it will simply crash if run on anything older.

Quote:
You've mentioned in the past that writing position-independent x86-based code is not straightforward and that such code can incur execution speed penalties (or words to that effect). Is that the case with DrawIconRTR.bin?

I didn't set out to make it position independent, but when I noticed that it very nearly was anyway, it seemed worth the little extra effort. The main thing you have to avoid is any absolutely-addressed 'variables', so everything which doesn't fit in a register is kept on the stack. Having the alpha byte 'inverted' (00 = opaque, FF = transparent) helped too.

Richard.
User IP Logged

David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Re: Bitmap clipper & plotter (BASIC prototypes)
« Reply #4 on: Mar 5th, 2012, 03:18am »

Here is a speed test comparing DrawIconRTR and GFXLIB_PlotScaleBlend.

The two routines, admittedly, do slightly different things:

DrawIconRTR alphablends on a pixel-by-pixel basis (using the alpha value of each source bitmap pixel, and pre-multiplied alphas of background pixels).

GFXLIB_PlotScaleBlend uses a single, global alpha (or opacity) value for all pixels, and doesn't read background alphas.

So the two routines do quite similar things.

GFXLIB_PlotScaleBlend doesn't make use of any MMX/SIMD instructions.

DrawIconRTR is certainly faster until larger scale factors are specified, and much clipping needs to be done. Eventually, GFXLIB_PlotScaleBlend overtakes. I think I know why this is, but it's currently 4:12 AM and I'm too tired to explain my thoughts.

GFXLIB is required to run the source code below.

Here's a link to the EXE (+ .BBC source):

http://www.bb4wgames.com/temp/plotspeedtest.zip

Code:
      REM. -----------------
      REM. PlotSpeedTest.BBC
      REM. -----------------
      REM.
      REM. Compare -- not too scientifically! -- plotting speeds of
      REM. DrawIconRTR and GFXLIB_PlotScaleBlend
      
      MODE 8
      
      SOUND 1, 0, 0, 0 : SOUND OFF
      
      ON ERROR OSCLI "REFRESH ON" : ON : CLS : REPORT : PRINT " at line "; ERL : VDU 7 : END
      
      INSTALL @lib$ + "GFXLIB2.BBC" : PROCInitGFXLIB(d{}, 0)
      INSTALL @lib$ + "GFXLIB_modules\PlotScaleBlend.BBC" : PROCInitModule
      
      GetTickCount% = FNSYS_NameToAddress( "GetTickCount" )
      
      DIM mc% 255
      OSCLI "LOAD """ + @lib$ + "DrawIconRTR.bin"" " + STR$~mc%
      DrawIconRTR% = mc% + 3
      
      DIM Buffer{T%,W%,H%,B%,P%,M%}
      Buffer.W% = @vdu%!208 : Buffer.H% = @vdu%!212 : Buffer.M% = d.bmBuffAddr%
      
      REM. Create a 'test' 128x80, 32-bpp ARGB bitmap
      bmW% = 128 : bmH% = 80 : bm% = FN_createTestBitmap( bmW%, bmH% )
      DIM Bitmap{T%,W%,H%,B%,P%,M%}
      Bitmap.W% = bmW% : Bitmap.H% = bmH% : Bitmap.M% = bm%
      
      COLOUR 15 : PRINT '" DrawIconRTR vs. GFXLIB_PlotScaleBlend"' : COLOUR 7
      INPUT '" Enter a scale factor (1.0) "; scale
      INPUT '" How many iterations? (10000) "; N%
      IF N% <= 0 THEN N% = 10000
      IF scale = 0 THEN scale = 1.0
      IF scale < 0 THEN scale *= -1.0
      
      DIM pt{X%,Y%}
      
      dx% = bmW%*scale
      dy% = bmH%*scale
      pt.X% = 320
      pt.Y% = 256
      
      bmW2% = scale * bmW%
      bmH2% = scale * bmH%
      
      OFF : WAIT 50
      
      SYS "GetCurrentProcess" TO hprocess%
      SYS "SetPriorityClass", hprocess%, &80
      
      REM. Display the 'test bitmap' using DrawIconRTR
      SYS DrawIconRTR%, Buffer{}, pt.X%, pt.Y%, Bitmap{}, dx%, dy%
      SYS "InvalidateRect", @hwnd%, 0, 0
      *REFRESH
      
      REM. Time DrawIconRTR%
      PRINT '" Timing DrawIconRTR ("; N%; " calls; scale factor: ";scale;")..." : WAIT 50
      *REFRESH OFF
      SYS GetTickCount% TO timeA_0%
      FOR I% = 1 TO N%
        SYS DrawIconRTR%, Buffer{}, pt.X%, pt.Y%, Bitmap{}, dx%, dy%
      NEXT
      SYS GetTickCount% TO timeA_1%
      
      *REFRESH ON
      
      REM. Display the 'test bitmap' using GFXLIB_PlotScaleBlend
      SYS GFXLIB_PlotScaleBlend%, d{}, bm%, bmW%, bmH%, bmW2%, bmH2%, pt.X%, pt.Y%, 254
      SYS "InvalidateRect", @hwnd%, 0, 0
      *REFRESH
      
      REM. Time GFXLIB_PlotScaleBlend
      PRINT '" Timing GFXLIB_PlotScaleBlend ("; N%; " calls; scale factor: ";scale;")..." : WAIT 50
      *REFRESH OFF
      SYS GetTickCount% TO timeB_0%
      FOR I% = 1 TO N%
        SYS GFXLIB_PlotScaleBlend%, d{}, bm%, bmW%, bmH%, bmW2%, bmH2%, pt.X%, pt.Y%, 254
      NEXT
      SYS GetTickCount% TO timeB_1%
      
      *REFRESH ON
      
      SYS "GetCurrentProcess" TO hprocess%
      SYS "SetPriorityClass", hprocess%, &20
      
      PRINT '" " + STRING$(40,"-")'
      PRINT '" DrawIconRTR took "; (timeA_1% - timeA_0%)/1000; " s."
      PRINT '" GFXLIB_PlotScaleBlend took "; (timeB_1% - timeB_0%)/1000; " s."
      
      COLOUR 3 : PRINT ''" Finished." : COLOUR 7
      SOUND 1, -10, 220, 1
      ON
      END
      
      DEF FN_createTestBitmap( bmW%, bmH% )
      LOCAL bm%, I%, X%, Y%, r%
      
      DIM bm% 4 * bmW%*bmH% +3 : REM. Needs extra 4 bytes (not 3!) for memory alignment
      bm% = (bm% + 3) AND -4   : REM. Ensures bitmap base address is DWORD-aligned (divisible by 4)
      
      REM. Fill our bitmap with the colour "SlateBlue" (= &6A5ACD)
      FOR I% = bm% TO bm% + (4*bmW%*bmH% - 1) STEP 4
        !I% = &6A5ACD
      NEXT I%
      
      REM. Give our bitmap a bright yellow border
      FOR X% = 0 TO bmW%-1
        bm%!(4*X%) = &FFFF00
        bm%!(4*(bmW%*(bmH%-1) + X%)) = &FFFF00
      NEXT X%
      FOR Y% = 0 TO bmH%-1
        bm%!(4*Y%*bmW%) = &FFFF00
        bm%!(4*(Y%*bmW% + (bmW%-1))) = &FFFF00
      NEXT Y%
      
      REM. Draw a sine wave on the bitmap
      FOR X% = 0 TO bmW%-1
        Y% = bmH%DIV2 + bmH%DIV4*SIN(4*PI * X%/(bmW%-1))
        bm%!(4*(Y%*bmW% + X%)) = &FFFFFF
      NEXT X%
      
      REM. Draw a circle on our bitmap
      FOR I% = 0 TO 359
        r% = 0.25 * SQR((bmW%/2)^2 + (bmH%/2)^2)
        X% = bmW%/2 + r%*SINRADI%
        Y% = bmH%/2 + r%*COSRADI%
        IF X% < 0 X% = 0
        IF Y% < 0 Y% = 0
        IF X% > bmW%-1 X% = bmW%-1
        IF Y% > bmH%-1 Y% = bmH%-1
        bm%!(4*(Y%*bmW% + X%)) = &00FF00
      NEXT I%
      
      = bm%
 



David.

« Last Edit: Jan 2nd, 2013, 05:01am by David Williams » User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Bitmap clipper & plotter (BASIC prototypes)
« Reply #5 on: Mar 5th, 2012, 4:44pm »

on Mar 5th, 2012, 03:18am, David Williams wrote:
DrawIconRTR alphablends on a pixel-by-pixel basis (using the alpha value of each source bitmap pixel, and pre-multiplied alphas of background pixels).

I don't really know what you mean by "pre-multiplied alphas of background pixels" here. In what sense do 'background' pixels have an alpha anyway? I don't guarantee that my routine will do anything sensible with the 'alpha' byte in the background bitmap: it may well corrupt it. I treat it as a 'don't care' byte.

Quote:
So the two routines do quite similar things

Does yours have the 'reflect' (about either axis) option? That added a significant degree of complexity, as I recollect.

My routine is, of course, optimised for no clipping, since (at least in my applications) clipping is very much an exceptional case.

Richard.
« Last Edit: Mar 5th, 2012, 4:54pm by admin » User IP Logged

David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Re: Bitmap clipper & plotter (BASIC prototypes)
« Reply #6 on: Mar 6th, 2012, 03:21am »

on Mar 5th, 2012, 4:44pm, Richard Russell wrote:
I don't really know what you mean by "pre-multiplied alphas of background pixels" here.


Neither do I (lol).

I now know that what I wrote was nonsense.


on Mar 5th, 2012, 4:44pm, Richard Russell wrote:
Does yours have the 'reflect' (about either axis) option? That added a significant degree of complexity, as I recollect.


No, mine doesn't.

The only GFXLIB routine that performs any kind of flipping/reflection is GFXLIB_PlotFlip (and a variant of it). This may be about to change, however.


David.
User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

| |

This forum powered for FREE by Conforums ©
Terms of Service | Privacy Policy | Conforums Support | Parental Controls