2D drawdisc() drawcircle()

Previous topic - Next topic

sf-in-sf

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.

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

Wampus

Thanks. This came in handy tonight when I was coding.

CW

#2
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



   

sf-in-sf

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.

CW

Fair enough, sf. I'll add it to my to-do list.  =D
-CW

sf-in-sf

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.

fuzzy70

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)

bigsofty

Quote from: sf-in-sf 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)

Brick Redux

Quote from: fuzzy70 on 2013-Mar-25
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!

sf-in-sf

#9
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.
On the day the atom is a cube I will start believing in the square pixel.

sf-in-sf

Quote from: CW on 2013-Mar-18
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.

CW

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

Brick Redux

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!

Brick Redux

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!

kanonet

Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64