Dark Bit Factory & Gravity

PROGRAMMING => Freebasic => Topic started by: Clyde on July 04, 2006

Title: Plotting A Circle.
Post by: Clyde on July 04, 2006
Im using tiny ptc and I wondered if anyone knew how to plot filled circles / ovals, using the FeedPixel(x,y,col) method with different heights and widths. Ive been racking my brain cell all day.

Cheers and many thanks,
Clyde.
Title: Re: Plotting A Circle.
Post by: zawran on July 04, 2006
There is a piece of code on the BR code archieves which plots a circle/eclipse using integer math. It should be fairly easy to convert to FB, there are both a bmx and bb version on the following link:

http://www.blitzbasic.com/codearcs/codearcs.php?code=1477

Title: Re: Plotting A Circle.
Post by: Clyde on July 04, 2006
Hmm seems the site is down. And Thanks man, I'll take a look whens its back online.

Cheers,
Clyde.
Title: Re: Plotting A Circle.
Post by: zawran on July 04, 2006
The site isn't down, but apparently it doesn't work to link directly to it, so here is the bb version (btw. the code is public domain so free to use/convert)


;Midpoint ellipse algorithm

Graphics 640,480,0,2

Local xCenter% = 320
Local yCenter% = 240
Local Rx%, Ry%
Local p%, px%, py%, x%, y%
Local Rx2%, Ry2%, twoRx2%, twoRy2%
Local pFloat#

Repeat
        Cls
WaitEvent()


        If MouseDown(1)
            xCenter = MouseX()
            yCenter = MouseY()
        EndIf
        Rx = Abs(xCenter - MouseX())
        Ry = Abs(yCenter - MouseY())

        Rx2 = Rx * Rx
        Ry2 = Ry * Ry
        twoRx2 = Rx2 Shl 1
        twoRy2 = Ry2 Shl 1

msStart = MilliSecs()

        ;Region 1
        x = 0
        y = Ry

        Plot xCenter + x, yCenter + y
        Plot xCenter - x, yCenter + y
        Plot xCenter + x, yCenter - y
        Plot xCenter - x, yCenter - y
        pFloat = (Ry2 - (Rx2 * Ry)) + (0.25 * Rx2)
        p = Int(pFloat)
        If pFloat Mod 1.0 >= 0.5 Then p = p + 1

        px = 0
        py = twoRx2 * y

        While px < py
                x = x + 1
                px = px + twoRy2
                If p >= 0
                        y = y - 1
                        py = py - twoRx2
                EndIf
                If p < 0 Then p = p + Ry2 + px Else p = p + Ry2 + px - py
                Plot xCenter + x, yCenter + y
                Plot xCenter - x, yCenter + y
                Plot xCenter + x, yCenter - y
                Plot xCenter - x, yCenter - y
        Wend

        ;Region 2
        pFloat = (Ry2 * (x + 0.5) * (x + 0.5)) + (Rx2 * (y - 1.0) * (y - 1.0)) - (Rx2 * (Float(Ry2)))
        p = Int(pFloat)
        If pFloat Mod 1.0 >= 0.5 Then p = p + 1
        While y > 0
                y = y - 1
                py = py - twoRx2
                If p <= 0
                        x = x +1
                        px = px + twoRy2
                EndIf
                If p > 0 Then p = p + Rx2 - py Else p = p + Rx2 - py + px
                Plot xCenter + x, yCenter + y
                Plot xCenter - x, yCenter + y
                Plot xCenter + x, yCenter - y
                Plot xCenter - x, yCenter - y
        Wend

timeToDraw = MilliSecs() - msStart
Text 20, 20, Rx + " x " + Ry
Text 20, 30, "Draw time " + timeToDraw + " ms"

        Flip(False)
Until KeyHit(1)

Title: Re: Plotting A Circle.
Post by: Shockwave on July 04, 2006
Filled circles are a bit harder, this does the trick and would probably be ok for you, it's basically my metaball generation code but I'm sure you can pull out the bits you need.


        #Include Once "tinyptc.bi"
        option dynamic
        If( ptc_open( "METABLOBS", 640, 480 ) = 0 ) Then
        End -1
        End If
   
        Dim Shared As Integer Buffer( 640 * 480 )
       
            dim as double angle,bangle
DO
radius=99
for z=1 to 99
        bangle=360
        clv=z
        if clv>255 then clv=255
        clv=rgb(clv,clv,clv)
        for a=1 to 360
           
            x1=(100+(radius*sin(angle*3.1415926535897932/180)))
            y1=(100+(radius*cos(angle*3.1415926535897932/180)))           
            x2=(100+(radius*sin(bangle*3.1415926535897932/180)))           
           
            angle=angle+.5
            bangle=bangle-.5
                               
            for l=x2 to x1
                buffer((640*y1)+l)=clv
            next
           
        next
        radius=radius-1
next

ptc_update @buffer(0)
LOOP UNTIL INKEY$<>""


Basically the Y sinus sorts out the Y co-ordinate
The two X sinus create the points to loop between to fill the circle.
Title: Re: Plotting A Circle.
Post by: Shockwave on July 04, 2006
I was feeling mean just posting that snippet...
Here.. I converted it for you..

Slow code; :P


        #Include Once "tinyptc.bi"
        option dynamic
        option explicit
       
        If( ptc_open( "METABLOBS", 640, 480 ) = 0 ) Then
        End -1
        End If
        declare sub dcircle(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CLR AS INTEGER)
        Dim Shared As Integer Buffer( 640 * 480 )
       
           
DO
dcircle (320,240,239,&hffffff)
ptc_update @buffer(0)
LOOP UNTIL INKEY$<>""

SUB dCIRCLE(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CLR AS INTEGER)
DIM  as integer a,z,x1,y1,x2,l
dim as double angle,bangle

        bangle=360

       
       
        for a=1 to 1440
           
            x1=(cx+(r*sin(angle*3.1415926535897932/180)))
            y1=(cy+(r*cos(angle*3.1415926535897932/180)))           
            x2=(cx+(r*sin(bangle*3.1415926535897932/180)))           
           
            angle=angle+.125
            bangle=bangle-.125
                               
            for l=x2 to x1
                buffer((640*y1)+l)=CLR
            next
           
        next



END SUB
Title: Re: Plotting A Circle.
Post by: Clyde on July 04, 2006
Thanks kindly to both of you.

Cheers,
Clyde.
Title: Re: Plotting A Circle.
Post by: Jim on July 05, 2006
A nice simple Blitz filled circle.

Graphics 640,480,0,2

Repeat
Color Rand(255),Rand(255),Rand(255)
fillcircle(Rand(640),Rand(480),Rand(100))
Until KeyDown(1)
End

Function fillcircle(x%,y%,r%)
r2%=r*r
For h% = -r To r
w% = Sqr(r2-h*h)
Line x-w,y+h , x+w,y+h
Next
End Function


Jim
Title: Re: Plotting A Circle.
Post by: Clyde on July 05, 2006
Thanks,
Clyde.
Title: Re: Plotting A Circle.
Post by: Shockwave on July 05, 2006
It would be easy to generate a much faster circle algo than mine in freebasic using Jims code :)
Title: Re: Plotting A Circle.
Post by: Shockwave on July 05, 2006
Here, I did it.
All it needs now is a little asm to flat fill the scan lines :)


' Coded By Jim Shaw and Shockwave.
'
' Usage..

' DCIRCLE ( XP , YP , RADIUS , COLOUR )


        #Include Once "tinyptc.bi"
        option dynamic
        option explicit
       
        If( ptc_open( "CIRCLES", 640, 480 ) = 0 ) Then
        End -1
        End If
        declare sub dcircle(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CLR AS INTEGER)
        Dim Shared As Integer Buffer( 640 * 480 )
       
  dim rrx,rry,rrr,rrc         
DO
    rrx=rnd*(640)
    rry=rnd*(480)
    rrr=rnd*(250)
    rrc=rnd*(255)
dcircle (rrx,rry,rrr,rgb(rrc,rrc,rrc))
ptc_update @buffer(0)
LOOP UNTIL INKEY$<>""

SUB dCIRCLE(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CLR AS INTEGER)
DIM  as integer r2,cc,loopy,ww,l
r2=r*r
cc=-r
for loopy = cc to r       
        ww = Sqr(r2-loopy*loopy)
        for l = CX-ww to CX+ww
                   if l>0 and l<640 and loopy+CY>0 and loopy+CY<480 then
                       buffer((640*(loopy+CY))+l)=CLR
                   end if
        next   
next
END SUB
Title: Re: Plotting A Circle.
Post by: Shockwave on July 05, 2006
Here's a quick hack to show how easy it would be to use this for generating your own bobs :)


' Fast Filled Circle Algo Using Tinyptc.
' Coded By Jim Shaw and Shockwave.
'
' Usage..

' DCIRCLE ( XP , YP , RADIUS , COLOUR )
'
' All it needs now is a little asm tweak to flat shade the scanline for
' ultimate speed.
'
' www.dbfinteractive.com
'
' A Quick hack to show shaded circles..

#define ptc_win
        #Include Once "tinyptc.bi"
       
        option static
        option explicit
       
        If( ptc_open( "CIRCLES", 640, 480 ) = 0 ) Then
        End -1
        End If
        declare sub dcircle(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CLR AS INTEGER)
        Dim Shared As Integer Buffer( 640 * 480 )
       
  dim rrx,rry,rrr,rrrc,rrgc,rrbc ,zz,rrt,rgt,rbt
DO
    rrx=rnd*(640)
    rry=rnd*(480)
    rrr=20+rnd*(50)
    rrrc=rnd*(255)
    rrgc=rnd*(255)
    rrbc=rnd*(255)
    rrt=0
    rgt=0
    rbt=0
for zz= rrr to 1 step -1
dcircle (rrx,rry,zz,rgb(rrt ,rgt ,rbt))
if rrt<rrrc then rrt=rrt+1
if rgt<rrgc then rgt=rgt+1
if rbt<rrbc then rbt=rbt+1
next

ptc_update @buffer(0)
LOOP UNTIL INKEY$<>""

SUB dCIRCLE(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CLR AS INTEGER)
DIM  as integer r2,cc,loopy,ww,l
r2=r*r
cc=-r
for loopy = cc to r       
        ww = Sqr(r2-loopy*loopy)
        for l = CX-ww to CX+ww
                   if l>0 and l<640 and loopy+CY>0 and loopy+CY<480 then
                       buffer((640*(loopy+CY))+l)=CLR
                   end if
        next   
next
END SUB
Title: Re: Plotting A Circle.
Post by: Stonemonkey on July 05, 2006
Nice stuff Shockwave, if speed is a concern (particularly if you're considering using asm) then it'd be an idea to take the screen bounds checking outside the loops instead of for every pixel.
Title: Re: Plotting A Circle.
Post by: Clyde on July 05, 2006
Cheers fellas.
Title: Re: Plotting A Circle.
Post by: thrawn89 on July 06, 2006
Quote from: Stonemonkey on July 05, 2006
Nice stuff Shockwave, if speed is a concern (particularly if you're considering using asm) then it'd be an idea to take the screen bounds checking outside the loops instead of for every pixel.

And if in that row, not all the pixels are on the screen, then what?  ???

You'd have to calculate how many pixels you're going be drawing in the row, see if it goes out of bounds, if so, at what pixel, then use the for loop below to draw to that last pixel, but I agree, it cuts down the amount of IFs from a couple hundred per line to 1 per line

Thrawn
Title: Re: Plotting A Circle.
Post by: Stonemonkey on July 06, 2006
Hmmmm sorry, I didn't word that quite right. Take the x clipping out of the x loop and take the y clipping out of the y loop.

something like:

y=cy-radius
y_end=cy+radius
if y<0 then y=0
if y_end>screenheight then y_end=screenheight
while y<y_end
Ã,  Ã,  halfwidth=sqr(radius^2-(cy-y)^2)
Ã,  Ã,  x=cx-halfwidth
Ã,  Ã,  x_end=cx+halfwidth
Ã,  Ã,  if x<0 then x=0
Ã,  Ã,  if x_end>screenwidth then x_end=screenwidth
Ã,  Ã,  while x<x_end
Ã,  Ã,  Ã,  Ã,  plot(x,y,colour)
Ã,  Ã,  Ã,  Ã,  x+=1
Ã,  Ã,  wend
Ã,  Ã,  y+=1
wend

although I'd take it a bit further and use pointers to write into memory instead of using plot.
Title: Re: Plotting A Circle.
Post by: Shockwave on July 06, 2006
Cool :) I've had some common sense whacked into me! :)

Stonemonkey >  :whack: < Shocky
Title: Re: Plotting A Circle.
Post by: thrawn89 on July 07, 2006
Why stop there and write the whole thing in ASM, you? lol just kidding ;-)

Common sense whacked into you? Hmm looks like it was more like a long, rather deformed, green,...stick that was wacked into you to me....;-)

EDIT:
In hindsight, that should have probally have been left unsaid  :o
Title: Re: Plotting A Circle.
Post by: Shockwave on July 07, 2006
All I can say is lol. :)
Title: Re: Plotting A Circle.
Post by: Shockwave on July 08, 2006
Anyway, what did you want this for Clyde? :) Anything interesting brewing mate?
Title: Re: Plotting A Circle.
Post by: Clyde on July 08, 2006
Yeah, I wanted it for hiding a few messy pixels for an effect that's going to feature in the next Gravity prod.
Thanks to all for their cool as ever advice and help.

Cheers,
Clyde.
Title: Re: Plotting A Circle.
Post by: Shockwave on July 08, 2006
Hope it hides 'em adequately, if it's just for masking then you could just pre-calculate it.