Simple + More Advanced Ellipse Renderer

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Simple + More Advanced Ellipse Renderer

Post by anonymous1337 »

Credits to Jofers and Kristopher Windsor for helping/showing how this is done. Figured I should post my versions in Tips & Tricks, so that one day yet another will be able to search and find two commented versions.

Also, props to anyone who can add a Simple and Clean precision step to this, so only the pixels that need to be drawn are, rather than just 0 to 360 step 1. With a small ellipse, it's a waste of CPU speed and with a larger ellipse, it's not enough to simply go 1 degree at a time for some.

Code: Select all

#include once "fbgfx.bi"
#define pi 3.14159265
#define RadToDeg(__rad__) (__rad__ * (180/Pi))
#define DegToRad(__rad__) (__rad__ * (pi/180))

Declare Sub DrawEllipse( ByVal X as Integer, ByVal Y as Integer, ByVal W as Integer, ByVal H as Integer, ByVal Ang as Integer )

Screenres 640, 480, 32

'' Our settings.
Dim as Integer X = 319, Y = 239, W = 60, H = 60, Ang

Screenlock
Do
  
  '' Get Key Presses
  '' Move the Ellipse
  If Multikey(FB.SC_LEFT) then X -= 1
  If Multikey(FB.SC_RIGHT) then X += 1
  If Multikey(FB.SC_UP) then Y -= 1
  If Multikey(FB.SC_DOWN) then Y += 1
  '' Change Ellipse Width
  If Multikey(FB.SC_A) then W -= 1
  If Multikey(FB.SC_D) then W += 1
  '' Change Ellipse Height
  If Multikey(FB.SC_W) then H += 1
  If Multikey(FB.SC_S) then H -= 1
  '' Increase Our Angle
  Ang += 1
  
  '' Check all of our variables and make sure they are valid.
  If W < 1 then W = 1
  If H < 1 then H = 1
  If Ang > 359 then Ang = 0
  
  
  '' Draw our ellipse.
  DrawEllipse( X, Y, W, H, Ang )
  
  
  '' "GUI" - Uhmm...Just text information ;p
  '' Background
  Line (0,0)-(250, 40), rgb(10, 20, 80), bf
  Line (0,0)-(250, 40), rgb(80, 20, 10), b
  Locate 1, 1
  '' Text
  Draw String (2,2), "Move with Arrow Keys"
  Draw String (2,10), "Stretch Ellipse with WASD"
  Draw String (2,18), "Pos: " & "(" & str(x) & "," & str(y) & "," & str(Ang) & ")"
  Draw String (2,26), "W/H: " & "(" & str(w) & "," & str(h) & ")"
  
  '' Flip our Page
  screenunlock
    sleep 15, 1
  screenlock
  cls
    
Loop until multikey(FB.SC_ESCAPE)
screenunlock

Sub DrawEllipse( ByVal X as Integer, ByVal Y as Integer, ByVal W as Integer, ByVal H as Integer, ByVal Ang as Integer )
  
  '' Ellipse Drawing Positions
  Dim as Integer EX, EY
  '' Rotated Positions
  Dim as Double RX, RY
  '' Our Sin/Cos Angles.  No reason to calculate it every step.
  Dim as Double SinAng = Sin(DegToRad(Ang)), CosAng = Cos(DegToRad(Ang))
  
  '' Custom Ratios.  Normally this would be r*cos(ang)
  Ex = ( W * Cos(0) )
  Ey = ( H * -Sin(0) )
  
  '' Rotate our Ellipse.  We're rotating around our own center.
  '' Since we didn't include our Drawing Positions, no complex math needed!
  '' FYI:  This is rotate around ourself math, using our own center as origin!
  Rx = ( Ex * CosAng ) - ( Ey * SinAng )
  Ry = ( Ey * CosAng ) + ( Ex * SinAng )
  
  '' Draw First Point.
  '' We don't include X in the above math so we can have rotation free from
  '' Our Ellipse Center
  Pset ( X + Rx, Y + Ry ), rgb(255, 255, 255)
  
  '' Loop through our ellipse angles.
  For CurAng as Double = 1 to 360
    '' Custom Ratios instead of Rad
    Ex = ( W * Cos(DegToRad(CurAng)) )
    Ey = ( H * -Sin(DegToRad(CurAng)) )
    
    '' Rotate our Ellipse
    Rx = ( Ex * CosAng ) - ( Ey * SinAng )
    Ry = ( Ey * CosAng ) + ( Ex * SinAng )
    
    '' A version of Line (x,y) - step (x2, y2)
    '' Except this is nothing but a step.
    Line - ( X + Rx, Y + Ry ), rgb(255, 255, 255)
  Next
End Sub
You could add an arc begin/end to this by changing the For loop to go from StartAng to EndAng rather than 1 to 360, with only minor configuration.

Here's the more advanced version:

Code: Select all

#include once "fbgfx.bi"
#define pi 3.14159265
#define RadToDeg(__rad__) (__rad__ * (180/Pi))
#define DegToRad(__rad__) (__rad__ * (pi/180))

'' An ellipse object.
'' Store info on the object here, render it.
Type Ellipse
  '' Ellipse Drawing Center
  X as Integer
  Y as Integer
  '' Width/Height Ratios
  W as Integer
  H as Integer
  '' Rotation Angle
  Rot as Double = 0
  '' Start/End Ang
  BegAng as Double = 0
  EndAng as Double = 360
  '' Direction.  This is our loop step.
  ArcStep as Integer = 1
  '' Fill or not? 0 = No Fill.  <> 0 = Fill
  '' Only fills if BegAng is 0, and EndAng is 360
  Fill as Integer = 0
  
  '' Draw the Ellipse.
  Declare Sub Draw()
End Type

Screenres 640, 480, 32

'' Our settings.
Dim as Ellipse MyArc
'' Position
MyArc.X = 319
MyArc.Y = 239
'' Size
MyArc.W = 60
MyArc.H = 60

Screenlock
Do
  
  '' Get Key Presses
  '' Move the Ellipse
  If Multikey(FB.SC_LEFT) then MyArc.BegAng -= 1
  If Multikey(FB.SC_RIGHT) then MyArc.BegAng += 1
  If Multikey(FB.SC_UP) then MyArc.EndAng -= 1
  If Multikey(FB.SC_DOWN) then MyArc.EndAng += 1
  '' Change Ellipse Width
  If Multikey(FB.SC_A) then MyArc.W -= 1
  If Multikey(FB.SC_D) then MyArc.W += 1
  '' Change Ellipse Height
  If Multikey(FB.SC_W) then MyArc.H += 1
  If Multikey(FB.SC_S) then MyArc.H -= 1
  '' Increase Our Angle
  MyArc.Rot += 1
  
  '' Check all of our variables and make sure they are valid.
  If MyArc.W < 1 then MyArc.W = 1
  If MyArc.H < 1 then MyArc.H = 1
  If MyArc.Rot > 359 then MyArc.Rot = 0
  If MyArc.BegAng < 0 then MyArc.BegAng += 360
  If MyArc.BegAng > 360 then MyArc.BegAng -= 360
  If MyArc.EndAng < 0 then MyArc.EndAng += 360
  If MyArc.EndAng > 360 then MyArc.EndAng -= 360
  '' Reverse Drawing Direction if our End Angle's less than our start angle.
  If MyArc.EndAng < MyArc.BegAng then
    MyArc.ArcStep = -1
  Else
    MyArc.ArcStep = 1
  End If
  '' Fill if we have a full Ellipse.
  If ( MyArc.BegAng = 0 ) then
    If ( MyArc.EndAng = 360 ) then
      MyArc.Fill = 1
    Else
      MyArc.Fill = 0
    End If
  Else
    MyArc.Fill = 0
  End If
  
  
  '' Draw our ellipse.
  MyArc.Draw()
  
  
  '' "GUI" - Uhmm...Just text information ;p
  '' Background
  Line (0,0)-(250, 48), rgb(10, 20, 80), bf
  Line (0,0)-(250, 48), rgb(80, 20, 10), b
  Locate 1, 1
  '' Text
  Draw String (2,2), "Change Arc With Arrow Keys"
  Draw String (2,10), "Stretch Ellipse with WASD"
  Draw String (2,18), "Pos: " & "(" & str(MyArc.x) & "," & str(MyArc.y) & "," & str(MyArc.Rot) & ")"
  Draw String (2,26), "W/H: " & "(" & str(MyArc.w) & "," & str(MyArc.h) & ")"
  Draw String (2,34), "Start/End Ang: " & "(" & str(MyArc.BegAng) & "," & str(MyArc.EndAng) & ")"
  
  '' Flip our Page
  screenunlock
    sleep 15, 1
  screenlock
  cls
    
Loop until multikey(FB.SC_ESCAPE)
screenunlock

Sub Ellipse.Draw()
  
  '' Ellipse Drawing Positions
  Dim as Integer EX, EY
  '' Rotated Positions
  Dim as Double RX, RY
  '' Our Sin/Cos Angles.  No reason to calculate it every step.
  Dim as Double SinAng = Sin(DegToRad(This.Rot)), CosAng = Cos(DegToRad(This.Rot))
  
  '' Custom Ratios.  Normally this would be r*cos(ang)
  Ex = ( This.W * Cos(DegToRad(This.BegAng)) )
  Ey = ( This.H * -Sin(DegToRad(This.BegAng)) )
  
  '' Rotate our Ellipse.  We're rotating around our own center.
  '' Since we didn't include our Drawing Positions, no complex math needed!
  '' FYI:  This is rotate around ourself math, using our own center as origin!
  Rx = ( Ex * CosAng ) - ( Ey * SinAng )
  Ry = ( Ey * CosAng ) + ( Ex * SinAng )
  
  '' Draw First Point.
  '' We don't include X in the above math so we can have rotation free from
  '' Our Ellipse Center
  Pset ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)
  
  '' Loop through our ellipse angles.
  For CurAng as Double = This.BegAng + 1 to This.EndAng step This.ArcStep
    '' Custom Ratios instead of Rad
    Ex = ( This.W * Cos(DegToRad(CurAng)) )
    Ey = ( This.H * -Sin(DegToRad(CurAng)) )
    
    '' Rotate our Ellipse
    Rx = ( Ex * CosAng ) - ( Ey * SinAng )
    Ry = ( Ey * CosAng ) + ( Ex * SinAng )
    
    '' A version of Line (x,y) - step (x2, y2)
    '' Except this is nothing but a step.
    Line - ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)
  Next
  
  '' Fill our ellipse if we have chosen to do so.
  If This.Fill <> 0 then
    Paint (This.X, This.Y), rgb(255, 255, 255), rgb(255, 255, 255)
  End If
End Sub
And finally, here's a version useful for enemy paths, if you want to curve to direct from the player (center, edge of ellipse) to the target. Replace the "Advanced" Ellipse.Draw Sub with This One:

Code: Select all

Sub Ellipse.Draw()
 
  '' Ellipse Drawing Positions
  Dim As Integer EX, EY
  '' Rotated Positions
  Dim As Double RX, RY
  '' Origin Position
  Dim as Integer OX, OY
  '' Our Sin/Cos Angles.  No reason to calculate it every step.
  Dim As Double SinAng = Sin(DegToRad(This.Rot)), CosAng = Cos(DegToRad(This.Rot))
 
  '' Set an origin point for all of the ellipse drawing.
  Ox = ( This.W * Cos(DegToRad(This.BegAng)) )
  Oy = ( This.H * -Sin(DegToRad(This.BegAng)) )
 
  '' Custom Ratios.  Normally this would be r*cos(ang)
  Ex = ( This.W * Cos(DegToRad(This.BegAng)) ) + OX
  Ey = ( This.H * -Sin(DegToRad(This.BegAng)) ) + OY
  
  '' Rotate our Ellipse.  We're rotating around our own center.
  '' Since we didn't include our Drawing Positions, no complex math needed!
  '' FYI:  This is rotate around ourself math, using our own center as origin!
  Rx = ( Ex * CosAng ) - ( Ey * SinAng )
  Ry = ( Ey * CosAng ) + ( Ex * SinAng )
 
  '' Draw First Point.
  '' We don't include X in the above math so we can have rotation free from
  '' Our Ellipse Center
  Pset ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)
 
  '' Loop through our ellipse angles.
  For CurAng As Double = This.BegAng + 1 To This.EndAng Step This.ArcStep
    '' Custom Ratios instead of Rad
    Ex = ( This.W * Cos(DegToRad(CurAng)) ) + OX
    Ey = ( This.H * -Sin(DegToRad(CurAng)) ) + OY
   
    '' Rotate our Ellipse
    Rx = ( Ex * CosAng ) - ( Ey * SinAng )
    Ry = ( Ey * CosAng ) + ( Ex * SinAng )
   
    '' A version of Line (x,y) - step (x2, y2)
    '' Except this is nothing but a step.
    Line - ( This.X + Rx, This.Y + Ry ), rgb(255, 255, 255)
  Next
 
  '' Fill our ellipse if we have chosen to do so.
  If This.Fill <> 0 Then
    Paint (This.X + Rx / 2, This.Y + Ry / 2), rgb(255, 255, 255), rgb(255, 255, 255)
  End If
End Sub
Post Reply