BASIC

Author Topic: 2D drawdisc() drawcircle()  (Read 9545 times)

Offline sf-in-sf

  • Mr. Drawsprite
  • **
  • Posts: 93
  • Artist F.P. Brixey
    • View Profile
    • My computed art project
2D drawdisc() drawcircle()
« on: 2013-Feb-20 »
I'd like to share my 3 useful functions. Enjoy and experiment!
More on my artistic experimental programming: google 'artist F.P. Brixey saatchionline'. NEW: my collection is visible on deviant art.

Code: GLBasic [Select]
// --------------------------------- //
// Project: circle1
// Start: Sunday, February 03, 2013
// IDE Version: 10.244


// SETCURRENTDIR("Media") // go to media files
GLOBAL scrx%=666, scry%=666 //your custom size.
// For PC use menu;project;options;win32
GETSCREENSIZE scrx, scry
SETSCREEN scrx,scry,0           // Size matters.
CREATESCREEN 1,1,scrx,scry
        // the drawing surface.
GLOBAL cnt%
//****************************************************
WHILE TRUE
        //press F12 to view long lines of code.
        LOCAL alpha=(RND(1999)/1000.0 -1.0)+0.00000003
                // additive when >0
                // interpolated when <0, ='mix' ='cross-fade'
                // ...in my opinion.
        LOCAL color%=RGB(128*RND(2)-1,128*RND(2)-1,128*RND(2)-1)
        LOCAL smoothedge = 1.5+9*RND(2)
        LOCAL thickness=1.5+11*RND(3)
//      USESCREEN 1

IF RND(1) >0
        drawdisc2(RND(scrx), RND(scry), 4+RND(300), color, alpha, smoothedge)   // yes smoothing.
ELSE
        drawcircle2_(RND(scrx), RND(scry), 4+RND(300), thickness,color, alpha, smoothedge)   // yes smoothing.
ENDIF
        //drawdisc1(RND(scrx), RND(scry), 4+RND(300), color, alpha) // no smoothing. // unused.
       
        //USEASBMP // optional
        USESCREEN -1
        ALPHAMODE -1
        DRAWSPRITE 1,0,0
        SHOWSCREEN
                INC cnt,1
                IF cnt >4
                        cnt=0
                        SEEDRND (GETTIMERALL()) //shuffle the cards.
                ENDIF

//FOR more clarity:
        DEBUG alpha ; DEBUG "\n"
        // please activate the 'bug' icon
//      SLEEP 2012 // additional time

        SLEEP 800 +RND(3333)
        //SLEEP 787// Merry dream, liner!
WEND
//****************************************************


FUNCTION drawdisc1:cx%,cy%,r%,col%,a //raw shape
// a fast function with no blending.
//would be nearly 4x faster using symetry, working on just 1/4circle.
LOCAL r2% = r*r
USESCREEN 1
//Only plot within the screen to save time:
LOCAL bx1%=cx-r
        IF bx1 <0 THEN bx1=0
LOCAL by1%=cy-r
        IF by1 <0 THEN by1=0
LOCAL bx2%=cx+r
        IF bx2 >scrx THEN bx2=scrx
LOCAL by2%=cy+r
        IF by2 >scry THEN by2=scry

ALPHAMODE a // same speed for a=0, a=-1, strangely. Any suggestion for more speed?

FOR x%=bx1 TO bx2
FOR y%=by1 TO by2
        IF (x-cx)*(x-cx) +(y-cy)*(y-cy) <= r2 THEN SETPIXEL x,y,col
NEXT
NEXT
ENDFUNCTION

// On the day the atom is a cube I will start believing in the square pixel.

FUNCTION drawdisc2: cx,cy,r,col%,a,smoo //smoothed.
// Basic values are a=-1, smoo=1.
// N.B. a= -1...+1 but a=0 cancels the smoothing.
//   (if trouble try a permanent "INC a, 0.00000000000000042")
// Higher smoo values blur the edges. (Do try it at home!)
// Smoothing is symetrical across the circle position:
//      blurring goes both inwards and outwards. It is done in a quick
// way as it doesn't calculate SQR(d^2), using directly the r^2
// values for interpolation. Not as nice as a proper bicubic one.
// Just feel free to try your own way to interpolate the alpha
// value for a nicer smoothing/halo.
USESCREEN 1
IF smoo <0 THEN smoo =0
LOCAL halfsmoo =smoo*0.5
LOCAL r2  = (r-halfsmoo)*(r-halfsmoo) //contracted
LOCAL r2_ = (r+halfsmoo)*(r+halfsmoo) //expanded
LOCAL d2
LOCAL w=r2_ -r2

//Only plot within the screen to save time:
LOCAL bx1%=cx-r-halfsmoo
        IF bx1 <0 THEN bx1=0
LOCAL by1%=cy-r-halfsmoo
        IF by1 <0 THEN by1=0
LOCAL bx2%=cx+r+halfsmoo
        IF bx2 >scrx THEN bx2=scrx
LOCAL by2%=cy+r+halfsmoo
        IF by2 >scry THEN by2=scry


FOR x%=bx1 TO bx2
FOR y%=by1 TO by2

        d2=(x-cx)*(x-cx) +(y-cy)*(y-cy)
        IF d2 <= r2
                ALPHAMODE a
                SETPIXEL x,y,col
        ELSEIF d2 >= r2_
                // leave it alone.
        ELSE
                //interpolation:
                ALPHAMODE (r2_ -d2)*a/w
                SETPIXEL x,y,col
        ENDIF
NEXT
NEXT
ENDFUNCTION

// On the day the atom is a cube I will start believing in the square pixel.

FUNCTION drawcircle2_: cx,cy,r,thick,col%,a,smoo //smoothed.
// Same principle as drawdisc2( .
// using the real r value instead of r*r looks nicer but takes longer.
// This interpolation is linear but I believe a 'S' shape would
// be perfect. Also keep in mind that only an alpha interpolation is
// NOT enough; at the same time you should also interpolate the
// color into the next area. (Yes it's a bit bizarre.)
USESCREEN 1
IF smoo <0 THEN smoo =0
LOCAL halfsmoo =smoo*0.5
LOCAL th =thick*0.5
LOCAL ra  = (r+halfsmoo+th)
LOCAL ra2  = (r+halfsmoo+th)*(r+halfsmoo+th)    //outermost
LOCAL rb2  = (r+th)*(r+th)                                      //
LOCAL rc2  = (r-th)*(r-th)                                      //
LOCAL rd2  = (r-th-halfsmoo)*(r-th-halfsmoo) //innermost
LOCAL rd  = (r-th-halfsmoo)

LOCAL d2
LOCAL r2 =r*r
LOCAL w_out =ra-(r+th) +0.000001//r2_ -r2
LOCAL w_in  =(r-th)-rd +0.000001

//Only plot within the screen to save time:
LOCAL bx1%=cx-r-halfsmoo-th
        IF bx1 <0 THEN bx1=0
LOCAL by1%=cy-r-halfsmoo-th
        IF by1 <0 THEN by1=0
LOCAL bx2%=cx+r+halfsmoo+th
        IF bx2 >scrx THEN bx2=scrx
LOCAL by2%=cy+r+halfsmoo+th
        IF by2 >scry THEN by2=scry


FOR x%=bx1 TO bx2
FOR y%=by1 TO by2

        d2=(x-cx)*(x-cx) +(y-cy)*(y-cy) //distance to center
        IF d2 <= r2 //internal

                IF d2 >= rc2
                        //plot it plain.
                        ALPHAMODE a
                        SETPIXEL x,y,col
                ELSEIF d2 <=  rd2
                        // ignore it
                ELSE
                        // interpolate, blend it.
                        ALPHAMODE (SQR(d2) -rd)*a/w_in
                        SETPIXEL x,y,col
                ENDIF
        ELSE //external

                IF d2 < rb2
                        //plot it plain.
                        ALPHAMODE a
                        SETPIXEL x,y,col
                ELSEIF d2 >=  ra2
                        // ignore it
                ELSE
                        // interpolate, blend it.
                        ALPHAMODE (ra -SQR(d2))*a/w_out
                        SETPIXEL x,y,col
                ENDIF
        ENDIF
NEXT
NEXT
ENDFUNCTION

//__________________________________________________________________________________

// P.S. On the day the atom is a cube I will start believing in the square pixel.

 
« Last Edit: 2015-Oct-18 by sf-in-sf »
On the day the atom is a cube I will start believing in the square pixel.

Offline Wampus

  • Prof. Inline
  • *****
  • Posts: 1004
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #1 on: 2013-Feb-26 »
Thanks. This came in handy tonight when I was coding.

Offline CW

  • Mr. Polyvector
  • ***
  • Posts: 155
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #2 on: 2013-Mar-18 »
Very nice, SF.

Having recently struggled with the slow nature of plotting (drawing) circles in Basic, I am very well placed to admire how quickly your code can draw simple circles. (I especially like how you plot only those points which are actually on the screen.)

How do you think your code for creating simple disks would compare, speed wise, with plotting a disk to the screen, doing a GRABSPRITE of that disk, and then using STRETCHSPRITE to scale the disk up or down to the diameter needed? You could even draw the disk transparent and use the sprite as a mask to stamp colored disks out from a DRAWRECT.

If the speed is favorable, I also wonder if a speed gain could be made by plotting 25% of a disk, as you suggested, and then rotating the sprite around to create the rest of the disk from which the GRABSPRITE could be taken.

I like your more complex disks and  circles, with Alpha set and with the feathered edges, very much. Yeah, they take a little longer to render, but they are worth it. Very stylish.

-Cheers!
-CW



   
« Last Edit: 2013-Mar-18 by CW »

Offline sf-in-sf

  • Mr. Drawsprite
  • **
  • Posts: 93
  • Artist F.P. Brixey
    • View Profile
    • My computed art project
Re: 2D drawdisc() drawcircle()
« Reply #3 on: 2013-Mar-23 »
Hi CW,

Just run a test on 100-10000 pieces in a row, without randomness, with my method then with yours. compare the total time and see.

Addition to drawcircle() : on the line d2= ... you can multiply the x or y part with zz >=1 to see a pseudo ellipse.
I just posted a dedicated drawellipse() Fn. See and have fun!
On the day the atom is a cube I will start believing in the square pixel.

Offline CW

  • Mr. Polyvector
  • ***
  • Posts: 155
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #4 on: 2013-Mar-24 »
Fair enough, sf. I'll add it to my to-do list.  =D
-CW

Offline sf-in-sf

  • Mr. Drawsprite
  • **
  • Posts: 93
  • Artist F.P. Brixey
    • View Profile
    • My computed art project
Re: 2D drawdisc() drawcircle()
« Reply #5 on: 2013-Mar-25 »
I find the alpha plotting too slow. To go fast, we would need to be more direct and use a pointer to the drawing surface memory location. Then the symetry trick would make sense, I think.
I don't know how to do it in practice. In GLb are we allowed to go down to such a low level C procedure? Would android -in java- accept it?
On the day the atom is a cube I will start believing in the square pixel.

Offline fuzzy70

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 828
  • Look left, Look right, LOOK OUT!!
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #6 on: 2013-Mar-25 »
SETPIXEL is the problem with regards to being the major speed killer.

I have been looking at your code & thinking of ways of how to speed it up, not got down to writing code as of yet but trying out things in my head. Symmetry would speed things up but with various degrees of increase, for example the increase would be at it's maximum effect if the whole object fitted on the screen whereas the minimum increase would be something like only a quarter of the circle being visible (defeats the point of symmetry if none of it gets seen or plotted).

As it stands with your code you check at the start of the function what is visible & only plot what's going to be visible on screen. To me that would have to be modified or removed for it to work with symmetry, or possibly kept & the symmetry points checked at runtime to see if they are visible. The problem with the latter approach is that the extra checks (4 checks for 4 point symmetry & 8 checks for 8 point) will eat into the gains of symmetry thanks to the extra code, by how much I do not know until I test it for real but I think it will still be faster than non-symmetric circles.

Sorting out the plotting speed might possibly be solved by either using MEM2SPRITE or openGL. The 1st I have used numerous times before & while the MEM2SPRITE command does have an overhead I have not come across a time yet where it has been slower than plotting pixels using SETPIXEL. Check my post http://www.glbasic.com/forum/index.php?topic=8670.0 with a simple test I done with drawing a mandelbrot with colour cycling. My 1st version of that used SETPIXEL & seriously struggled to hit 5FPS I think it was, may have been slightly faster or slower I can't remember but was nowhere near as fast as the MEM2SPRITE  version.

I can't really help on the openGL side of things or if you would gain any kind of speed increase but only mentioned it in case someone reading this with knowledge of using it can confirm or deny if it would benefit it's use.

Hopefully in the next couple of days I will be able to play around with a MEM2SPRITE version, a symmetry version & probably a combo of both to see if/how much a speed increase can be made.

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

Offline bigsofty

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 2511
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #7 on: 2013-Mar-25 »
In GLb are we allowed to go down to such a low level C procedure? Would android -in java- accept it?

Yes, GLBasic uses C, even on Android. Just remember to stick within the constraints of GLES 1.1 API when the target is a mobile platform.
Cheers,

Ian.

“It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration.”
(E. W. Dijkstra)

Offline Brick Redux

  • Mr. Drawsprite
  • **
  • Posts: 60
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #8 on: 2013-Apr-26 »
SETPIXEL is the problem with regards to being the major speed killer.

Drawline seemed to speed things up(instead of Setpixel) when I was using MEM2SPRITE for image editing. Even when plotting a single point. The only other solution on offer seemed to be Inline code that turns off Setpixels Safe mode.  Playbasic for example has a fast fill command that uses this. (But its limited in its use.)
A mournful owner of a HP HDX18 Laptop that has died...FECK!

Offline sf-in-sf

  • Mr. Drawsprite
  • **
  • Posts: 93
  • Artist F.P. Brixey
    • View Profile
    • My computed art project
Re: 2D drawdisc() drawcircle()
« Reply #9 on: 2013-May-25 »
Code: GLBasic [Select]
// We need something like
POKE 53280, 0
im_loc% = VARPTR(my_foot_image_73052)
// same with VARSEG
POKE im_loc, 0xB787

Hi guys!
As the bear says, "sorry for the long paws!"... :D...  Eventually I'm back after a test of MEM2SPRITE. Good news: yes it speeds things up. I get a constant 2.2 fps at 1.1 GHz or so, and a 800x600 window -no double glazing, sorry.
But the constant fps is not normal, regardless whether a huge circle/ellipse or a tiny dot has been printed. It means that the plotting job to the array[] is very fast (only tested with no alpha, oh lazy me), but the rest is slow. Can DRAWSPRITE be so slow? Mmmh... I don't think so but need to check. If not, MEM2SPRITE would be the slow element (?...).
//*******
Anyway, I'd like to find a fast way to do it, for an app. Please can anyone help us? How can I find (in inline C) the pointer to the back buffer, so that I can plot directly into it instead of {into the array[], then MEM2SPRITE, then DRAWSPRITE, then SHOWSCREEN}?
If this question was tricky or cheeky, here is another option: 1) with CREATESCREEN I create a sprite to the right size. 2) Again, what is the pointer to that sprite? Pleeeeeeease!...
And thanks in advance.
« Last Edit: 2013-May-25 by sf-in-sf »
On the day the atom is a cube I will start believing in the square pixel.

Offline sf-in-sf

  • Mr. Drawsprite
  • **
  • Posts: 93
  • Artist F.P. Brixey
    • View Profile
    • My computed art project
Re: 2D drawdisc() drawcircle()
« Reply #10 on: 2013-May-25 »
How do you think your code for creating simple disks would compare, speed wise, with plotting a disk to the screen, doing a GRABSPRITE of that disk, [...]

Hi cw!
I never use GRABSPRITE, it doesn't work on iOS and android. It returns a white square on android. See Gernot's introduction to iOS in the online manual.
On the day the atom is a cube I will start believing in the square pixel.

Offline CW

  • Mr. Polyvector
  • ***
  • Posts: 155
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #11 on: 2013-May-30 »
Hi sf!

I don't have a smart phone, so I've never had the opportunity to play with GLbasic on one. Nope, I just program for my laptop system.
I look forward to being able to write my own apps for a smartphone. When I do, knowing what GRABSPITE can and can't do will be handy; so I'll keep that problem with GRABSPITE in mind.

Thanks!
-CW

Offline Brick Redux

  • Mr. Drawsprite
  • **
  • Posts: 60
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #12 on: 2013-Jul-28 »
Perhaps pre-calculating the math into an array is one way to speed things up - if limited in its use...You have an idea on the size of a disc needed and then read from a FOR/NEXT DIM loop to display it instead of doing calculations in real time?
A mournful owner of a HP HDX18 Laptop that has died...FECK!

Offline Brick Redux

  • Mr. Drawsprite
  • **
  • Posts: 60
    • View Profile
Re: 2D drawdisc() drawcircle()
« Reply #13 on: 2013-Jul-29 »
Because were all at different levels in development here.

So calm down, take a deep breath and post and example instead of venting your pointless frustration.

Your Ocean is not a calm place right now :D
A mournful owner of a HP HDX18 Laptop that has died...FECK!

Offline kanonet

  • Administrator
  • Prof. Inline
  • *******
  • Posts: 1142
    • View Profile
    • My GLBasic code archiv
Re: 2D drawdisc() drawcircle()
« Reply #14 on: 2013-Jul-29 »
Maybe you also want to have a look at this code: http://www.glbasic.com/forum/index.php?topic=4498.msg49701#msg49701
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64