BASIC Author Topic: 2Ddrawellipse()  (Read 1899 times) sf-in-sf 2Ddrawellipse()
« on: 2013-Mar-23 »
Read, use, enjoy! (I haven't tried your version yet, Gernot, you've been quicker than me.)
I'm surprised that the plotting with alpha seems to take much longer than the calculations and area scanning.
Any idea to improve that?

Code: GLBasic [Select]
// --------------------------------- //
// Project: ellipse1
// Start: Saturday, March 16, 2013
// IDE Version: 10.244

// SETCURRENTDIR("Media") // go to media files
// --------------------------------- //
// 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;
GETSCREENSIZE scrx, scry
SETSCREEN scrx,scry,0           // Size matters.
CREATESCREEN 1,1,scrx,scry
// the drawing surface.
GLOBAL cnt%
CONSTANT framing=0.12 // i.e. 12%
//****************************************************
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 = 2.2 +13*RND(3)
LOCAL thickness=3*RND(9) // (0 means filled ellipse, in 2nd Fn).
//      USESCREEN 1

//define the x,y of the 2 centers:
GLOBAL c1x%=scrx*framing+RND(scrx*(1-framing-framing))
GLOBAL c2x%=scrx*framing+RND(scrx*(1-framing-framing))
GLOBAL c1y%=scry*framing+RND(scry*(1-framing-framing))
GLOBAL c2y%=scry*framing+RND(scry*(1-framing-framing))
GLOBAL rr_=SQR((c1x-c2x)*(c1x-c2x)+(c1y-c2y)*(c1y-c2y))*(1.03+RND(800)*0.001)
// rr_ is the length of the string stretched between the 2 centers.
// As you draw, keep the string tentioned with the pen.
// Try at home with 2 pins on a piece of cardboard.

IF TRUE //RND(1) >0
// Choose which Fn:
//      drawellipse1(c1x,c1y,c2x,c2y,SQR((c1x-c2x)*(c1x-c2x)+(c1y-c2y)*(c1y-c2y))*(1.03+RND(800)*0.001),color, alpha)//, smoothedge)
drawellipse2(c1x,c1y,c2x,c2y,rr_, thickness,color, alpha, smoothedge)
ENDIF

//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 999
WEND
//****************************************************

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

//__________________________________________________________________________________

FUNCTION drawellipse1:c1x%,c1y%,c2x%,c2y%,r%,col%,a //raw, filled shape, fast Fn no smoothing.

LOCAL r2% = r*r //?
LOCAL bx1%,bx2%,by1%,by2%
IF r <SQR((c1x-c2x)*(c1x-c2x)+(c1y-c2y)*(c1y-c2y)) THEN RETURN 0
//impossible to draw, string is too short.
USESCREEN 1

IF c1x >=c2x
bx2 = c2x +r //(approx.)
bx1 = c1x -r
ELSE
bx2 = c1x +r
bx1 = c2x -r
ENDIF
IF c1y >=c2y
by2 = c2y +r
by1 = c1y -r
ELSE
by2 = c1y +r
by1 = c2y -r
ENDIF
ALPHAMODE a
FOR x%=bx1 TO bx2
FOR y%=by1 TO by2

IF SQR((x-c1x)*(x-c1x) +(y-c1y)*(y-c1y)) +SQR((x-c2x)*(x-c2x) +(y-c2y)*(y-c2y)) <= r THEN SETPIXEL x,y,col
NEXT
NEXT
RETURN 1
ENDFUNCTION

FUNCTION drawellipse2:c1x%,c1y%,c2x%,c2y%,r,thick,col%,a,smoo //raw shape

IF r <SQR((c1x-c2x)*(c1x-c2x)+(c1y-c2y)*(c1y-c2y)) THEN RETURN 0
//impossible to draw, string is too short.

IF smoo <0 THEN smoo =0
smoo=smoo*1.8 // approx.correction
LOCAL halfsmoo =smoo*0.5
LOCAL th =thick*0.5
LOCAL smoooo =smoo+smoo
LOCAL rs1 =r+smoooo
LOCAL ra  = (r+halfsmoo+th)
LOCAL rb  = (r+th)                                      //
LOCAL rc  = (r-th)                                      //
LOCAL rd  = (r-th-halfsmoo)

LOCAL d,d2
LOCAL r2 =r*r
LOCAL w_out =ra-(r+th) +0.000001//r2_ -r2
LOCAL w_in  =(r-th)-rd +0.000001
LOCAL w_out_plain =rs1-(r) +0.000001
LOCAL bx1%,by1%,bx2%,by2%
USESCREEN 1

IF c1x >=c2x
bx2 = c2x +r +th +smoooo //(approx.)
bx1 = c1x -r -th -smoooo
ELSE
bx2 = c1x +r +th+smoooo
bx1 = c2x -r -th-smoooo
ENDIF
IF c1y >=c2y
by2 = c2y +r +th+smoooo//(approx.)
by1 = c1y -r -th-smoooo
ELSE
by2 = c1y +r +th+smoooo
by1 = c2y -r -th-smoooo
ENDIF

FOR x%=bx1 TO bx2
FOR y%=by1 TO by2
//FOR x%=0 TO scrx
//FOR y%=0 TO scry
LOCAL d=SQR((x-c1x)*(x-c1x) +(y-c1y)*(y-c1y)) +SQR((x-c2x)*(x-c2x) +(y-c2y)*(y-c2y))
IF thick=0 // elliptic disc
IF d <= r
ALPHAMODE a
SETPIXEL x,y,col //print it plain
ELSEIF d <= rs1 // then interpolate the alpha.
ALPHAMODE (rs1-d)*a/smoooo
SETPIXEL x,y,col

ENDIF
ELSE // outlined ellipse
IF d <= r //internal

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

IF d < rb
//plot it plain.
ALPHAMODE a
SETPIXEL x,y,col
ELSEIF d >=  ra
// ignore it
ELSE
// interpolate, blend it.
ALPHAMODE (ra -d)*a/w_out
SETPIXEL x,y,col
ENDIF
ENDIF
ENDIF

NEXT
NEXT
RETURN 1 // Smooth operation hopefully
ENDFUNCTION

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

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

• Community Developer
• Prof. Inline
•      • • Posts: 2628 Re: 2Ddrawellipse()
« Reply #1 on: 2013-Mar-25 »
Very nice! In OpenGL in general switching the drawing state too regularly is to be avoided as its a slow operation. So if you could move ALPHAMODE outside of your loops, it may be quicker. Also, I have found that doing some OpenGL inline can be a bit quicker too as you have more control over the low level drawing operations. As mentioned by Fuzzy70, MEM2SPRITE can also be a good way to draw lots of pixels fast.
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)