Help Translating a draw strings routine to FB

New to FreeBASIC? Post your questions here.
Post Reply
bplus
Posts: 56
Joined: May 01, 2017 15:57

Help Translating a draw strings routine to FB

Post by bplus »

Hi,

I have been struggling to learn FB since March, I basically work in SmallBASIC (not MS, the one before that a total interpreter) and every now and then I get something I want to compile or really speed up. I have just finished an update to my Draw Strings routine and am toying with idea of building an editor for drawing fonts with draw strings for custom fonts. Then, I will definitely need speed.

Here is the current state of my Draw Strings routine which I need practice translating to FB. Drawing fonts will take some modified form of the subs but I can start learning with this so I am ready with it when I am ready on the SB end. Am I making sense?

Code: Select all

' Draw strings 2.bas SmallBASIC 0.12.9 (B+=MGA) 2017-05-06
'Deluxe draw strings.sdlbas [B+=MGA] 2017-01-03
'translated from:
'v2 turtle strings.bas  SmallBASIC 0.12.2 [B+=MGA] 2016-04-04
'2017-05-08 fixes Box d and e for width and height
' test draw strings fixed for arc

'=================================================================
'                   Commands Set
'==================================================================
'Note all commands are a letter for function followed by number n 
 
'commands pn -1 to 15, 0-15 are QB colors,  -1 is pen up

'command xn set absolute screen coordinate for turtle x

'command yn set absolute screen coordinate for turtle y

'command gn move turtle relative to its current x position
'        + n = right, -n = left (pneumonic g for go!)

'command hn move turtle relative to its current y position
'        + n down?, -n up?  depends which way the angle is set
'        (pnuemonic h follows g like y follows x)

'command fn draws at current ta angle a distance of n  
'        (pnuemonic f is for forward use -n for back)

'command an sets angle or heading of turtle 
'        (pnuemonic a is for angle (degrees)
'        0 degrees is true North or 12 o'clock)

'command tn (turns) t=right n degrees when positive 
'        and turn left n degrees when negative

'v2 2016-04-05 the great and powerful repeat uses recursive sub 
 
'command rn repeat drawstrings n amount of times

'command tv for setting a turtle var probably need another

'add 2 more commands for setting and incrementing the tv variable

'command sn will set tv at n value

'command in will increment tv with n value

'Deluxe draw strings 2017-01-03
' draw filled box  current tx, ty is one corner

'command z for pen siZe radius to draw thick lines

'command dn sets box width

'command en sets box height

'command bn for Box color n = 0 - 15 

'command un to set a circle radius

'command cn to draw a filled circle of color n = 0 - 15

'command jn to set the arc deg angle start

'command kn to set the arc deg angle end

'command ln draw arc color n = 0 - 15


'======================================================================
'turtle globals should you translate to another dialect
'common scale, tx, ty, tx2, ty2, tr, taStart, taStop, tc, ta, tv, tz
scale = 1
tx = 0  : ty = 0    ' x, y turtle position 
tx2 = 0 : ty2 = 0   ' 2nd x,y for fill box or for ellipse width and height
taStart = 0         ' turtle arc Start
taStop = 0          ' turtle arc Stop
tc = 15             ' turtle color (QB colors 0 - 15 and -1 means pen up
ta = 0              ' turtle angle
tv = 0              ' new turtle increment var for changing tv
tz = 1              ' tz is tracking pen size
tr = 0              ' radius


'tests 
'blue pentagon, line thickness 8
tt "z1p9x500y500a90z8"
tt "r5f300t-72"
locate 1, 1 : ? "Thick blue line pentagon, press any for next test."
pause
cls

'===================== Tomaaz/Johnno's turtle art
tt "z2"
for i = 1 to 2
  tt "a0p12x110y300"
  tt "r100f250t-198"
  tt "a0p10x230y440"
  tt "r10g2h2r18f-20p10t10f-20p-1t10"
  tt "a0p6x350y550"
  tt "s500r248i-2fvt90.5"
  color 15
  locate 1, 1
  ? "Scale: ";scale;
  ? " Turtle art from Johnno and Tomaaz,"
  if i = 2 then ? " again with z (Pen size) set at 1."
  ? "  press any to continue.."
  pause
  tt "z1"
  scale = .75 'scale is used for tt drawing 
  cls
next

'== latest mods box bn, circle cn, arc ln <<< fixed
scale = 1
tt "z1a0p9x300y200d50e50r4b12p-1t-90f100"
tt "p9r4f-100t90"
tt "g-40h30p9a270r8f16.6t-45"
tt "p-1x600y275u50c14"
tt "p-1z2x600y275p12u30j40k140l12"
tt "p-1x585y270p12u5c9"
tt "p-1x615y270p12u5c9" 
pause


sub tt(tstring)
  local cmd, ds, i, c, d, tst, across, down, lngth, dx, dy, j, aa, stepper
  tstring = ucase(tstring)
  cmd = "" : ds = ""
  for i = 1 to len(tstring)
    c = mid(tstring, i, 1)
    if c = "V" then ds = str(tv)
    if instr("0123456789.-", c) then ds = ds + c
    if instr("ABCDEFGHIJKLPRSTUXYZ", c) or i = len(tstring) then
      'execute last cmd if one
      if cmd <> ""  then
        d = val(ds)
        select case cmd
        case "G" : tx += d  'move relative to tx, ty
        case "H" : ty += d
        case "X" : tx = d   'move to absolute screen x, y
        case "Y" : ty = d
        case "D" : tx2 = d  '2nd corner box relative to tx
        case "E" : ty2 = d  '2nd corner box relative to ty
        case "J" : taStart = d   'arc start angle
        case "K" : taStop = d    'arc stop angle
        case "P" : tc = d   'pen to qb color, -1 no pen
        case "Z" : tz = d   'pen size
        case "A" : ta = d   'set angle
        case "T" : ta += d  'change angle - = left, + = right
        case "U" : tr = d   'set radius for circle (R used for repeat)
        case "I" : tv += d  'increment variable
        case "S" : tv = d   'set or reset variable
        case "R"            ' repeat calls out for another call to tt
          tst = mid(tstring, i)  ' this assumes the rest of the string
          repete tst, d          ' is the repeat part.
          exit for
        case "F"         'Forward d distance according to angle ta
          across = scale * d * cos(rad(ta - 90))
          down = scale * d * sin(rad(ta - 90))
          if tc > -1 then
            color tc
            if tz <= 1 then
              line tx, ty, tx + across, ty + down
            else
              lngth = ((across) ^ 2  + (down) ^ 2) ^ .5
              if lngth then
                dx = across / lngth : dy = down / lngth
                for j = 0 to lngth
                  circle tx + dx * j, ty + dy * j, tz filled
                next
              end if
            end if
          end if
          tx = tx + across : ty = ty + down  'update turtle position
        case "B"
          color d
          rect tx - tx2/2, ty - ty2/2, tx + tx2/2, ty + ty2/2 filled
        case "C"
          color d
          circle tx, ty, tr filled
        case "L"   'arc ld u sets radius, j and k set start and end angle
          if tc > -1 then
            color d
            stepper = 1 / (3 * pi * tr)
            for aa = taStart to taStop step stepper
              dx = tr * cos(rad(aa)) 
              dy = tr * sin(rad(aa))
              if tz < 1 then
                pset tx + dx, ty + dy
              else
                circle tx + dx, ty + dy, tz filled
              end if
            next
          end if
        end select
        ds = "" : cmd = ""  'reset for next build of ds and cmd
      end if
      cmd = c
    end if
  next
end sub

sub repete(tts, times)
  local i
  for i = 1 to times
    tt tts
  next
end sub

If someone could help advise me step by step, I might have a routine I can use repeatedly for other SB projects. I am a fan of little graphics amusements as well as those math problems that refuse to leave my mind until I play with them a bit. But this project I am a little more serious about experiencing, seeing through to fonts (which means spending more than a day on). BTW or AND also, I recently learned about Rotozoomer at SdlBasic forum and want to do THAT with drawn "fonts".

The languages are so similar "...should be easy" but I anticipate difficulties with FB's graphics options / methods...

EDIT: Removed link
Last edited by bplus on May 12, 2017 1:09, edited 2 times in total.
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

Re: Help Translating a draw strings routine to FB

Post by thesanman112 »

The language looks similar but i font know if fb still uses drawstring commands or not....
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Help Translating a draw strings routine to FB

Post by dodicat »

Crudely, to get it to run:

Code: Select all

' Draw strings 2.bas SmallBASIC 0.12.9 (B+=MGA) 2017-05-06
'Deluxe draw strings.sdlbas [B+=MGA] 2017-01-03
'translated from:
'v2 turtle strings.bas  SmallBASIC 0.12.2 [B+=MGA] 2016-04-04
'2017-05-08 fixes Box d and e for width and height
' test draw strings fixed for arc

'=================================================================
'                   Commands Set
'==================================================================
'Note all commands are a letter for function followed by number n 
 
'commands pn -1 to 15, 0-15 are QB colors,  -1 is pen up

'command xn set absolute screen coordinate for turtle x

'command yn set absolute screen coordinate for turtle y

'command gn move turtle relative to its current x position
'        + n = right, -n = left (pneumonic g for go!)

'command hn move turtle relative to its current y position
'        + n down?, -n up?  depends which way the angle is set
'        (pnuemonic h follows g like y follows x)

'command fn draws at current ta angle a distance of n  
'        (pnuemonic f is for forward use -n for back)

'command an sets angle or heading of turtle 
'        (pnuemonic a is for angle (degrees)
'        0 degrees is true North or 12 o'clock)

'command tn (turns) t=right n degrees when positive 
'        and turn left n degrees when negative

'v2 2016-04-05 the great and powerful repeat uses recursive sub 
 
'command rn repeat drawstrings n amount of times

'command tv for setting a turtle var probably need another

'add 2 more commands for setting and incrementing the tv variable

'command sn will set tv at n value

'command in will increment tv with n value

'Deluxe draw strings 2017-01-03
' draw filled box  current tx, ty is one corner

'command z for pen siZe radius to draw thick lines

'command dn sets box width

'command en sets box height

'command bn for Box color n = 0 - 15 

'command un to set a circle radius

'command cn to draw a filled circle of color n = 0 - 15

'command jn to set the arc deg angle start

'command kn to set the arc deg angle end

'command ln draw arc color n = 0 - 15
screen 20
'color ,15



const pi=4*atn(1)
#define rad(x) (x)*pi/180
declare sub repete(tts as string, times as integer)
declare sub tt(tstring as string)
'======================================================================
'turtle globals should you translate to another dialect
dim shared as integer scale, tx, ty, tx2, ty2, tr, taStart, taStop, tc, ta, tv, tz
scale = 1
tx = 0  : ty = 0    ' x, y turtle position 
tx2 = 0 : ty2 = 0   ' 2nd x,y for fill box or for ellipse width and height
taStart = 0         ' turtle arc Start
taStop = 0          ' turtle arc Stop
tc = 15             ' turtle color (QB colors 0 - 15 and -1 means pen up
ta = 0              ' turtle angle
tv = 0              ' new turtle increment var for changing tv
tz = 1              ' tz is tracking pen size
tr = 0              ' radius


'tests 
'blue pentagon, line thickness 8
tt "z1p9x500y500a90z8"
tt "r5f300t-72"
locate 1, 1 : ? "Thick blue line pentagon, press any for next test."
sleep

cls

'===================== Tomaaz/Johnno's turtle art
tt "z2"
for i as integer = 1 to 2
  tt "a0p12x110y300"
  tt "r100f250t-198"
  tt "a0p10x230y440"
  tt "r10g2h2r18f-20p10t10f-20p-1t10"
  tt "a0p6x350y550"
  tt "s500r248i-2fvt90.5"
  color 15
  locate 1, 1
  ? "Scale: ";scale;
  ? " Turtle art from Johnno and Tomaaz,"
  if i = 2 then ? " again with z (Pen size) set at 1."
  ? "  press any to continue.."
  sleep
  tt "z1"
  scale = .75 'scale is used for tt drawing 
  cls
next

'== latest mods box bn, circle cn, arc ln <<< fixed
scale = 1
tt "z1a0p9x300y200d50e50r4b12p-1t-90f100"
tt "p9r4f-100t90"
tt "g-40h30p9a270r8f16.6t-45"
tt "p-1x600y275u50c14"
tt "p-1z2x600y275p12u30j40k140l12"
tt "p-1x585y270p12u5c9"
tt "p-1x615y270p12u5c9" 
sleep


sub tt(tstring as string)
'  local cmd, ds, i, c, d, tst, across, down, lngth, dx, dy, j, aa, stepper
  tstring = ucase(tstring)
dim as string  cmd = "" , ds = "",c,tst
  for i as integer = 1 to len(tstring)
    c = mid(tstring, i, 1)
    if c = "V" then ds = str(tv)
    if instr("0123456789.-", c) then ds = ds + c
    if instr("ABCDEFGHIJKLPRSTUXYZ", c) or i = len(tstring) then
      'execute last cmd if one
      if cmd <> ""  then
       var d = val(ds)
        select case cmd
        case "G" : tx += d  'move relative to tx, ty
        case "H" : ty += d
        case "X" : tx = d   'move to absolute screen x, y
        case "Y" : ty = d
        case "D" : tx2 = d  '2nd corner box relative to tx
        case "E" : ty2 = d  '2nd corner box relative to ty
        case "J" : taStart = d   'arc start angle
        case "K" : taStop = d    'arc stop angle
        case "P" : tc = d   'pen to qb color, -1 no pen
        case "Z" : tz = d   'pen size
        case "A" : ta = d   'set angle
        case "T" : ta += d  'change angle - = left, + = right
        case "U" : tr = d   'set radius for circle (R used for repeat)
        case "I" : tv += d  'increment variable
        case "S" : tv = d   'set or reset variable
        case "R"            ' repeat calls out for another call to tt
          tst = mid(tstring, i)  ' this assumes the rest of the string
          repete tst, d          ' is the repeat part.
          exit for
        case "F"         'Forward d distance according to angle ta
         var across = scale * d * cos(rad(ta - 90))
         var down = scale * d * sin(rad(ta - 90))
          if tc > -1 then
            color tc
            if tz <= 1 then
              line (tx, ty)- (tx + across, ty + down)
            else
            var  lngth = ((across) ^ 2  + (down) ^ 2) ^ .5
              if lngth then
             var   dx = across / lngth , dy = down / lngth
                for j as integer= 0 to lngth
                  circle (tx + dx * j, ty + dy * j), tz ,,,,,f'illed
                next
              end if
            end if
          end if
          tx = tx + across : ty = ty + down  'update turtle position
        case "B"
          color d
          line (tx - tx2/2, ty - ty2/2)- (tx + tx2/2, ty + ty2/2),,bf' filled
        case "C"
          color d
          circle (tx, ty),tr,,,,,f' filled
        case "L"   'arc ld u sets radius, j and k set start and end angle
          if tc > -1 then
            color d
         var   stepper = 1 / (3 * pi * tr)
            for aa as single = taStart to taStop step stepper
            var  dx = tr * cos(rad(aa)) 
             var dy = tr * sin(rad(aa))
              if tz < 1 then
                pset (tx + dx, ty + dy)
              else
                circle (tx + dx, ty + dy),tz,,,,,f' tz filled
              end if
            next
          end if
        end select
        ds = "" : cmd = ""  'reset for next build of ds and cmd
      end if
      cmd = c
    end if
  next
end sub

sub repete(tts as string, times as integer)
  'local i
  for i as integer= 1 to times
    tt tts
  next
end sub
 
FreeBASIC has draw which is similar.
bplus
Posts: 56
Joined: May 01, 2017 15:57

Re: Help Translating a draw strings routine to FB

Post by bplus »

Thanks dodicat for reply AND translation,

> "FreeBASIC has draw which is similar."

Yes, so does SmallBASIC, but I can remember my system better when I make it my own. I had a few ideas for "improvements", in my mind at least.


Since FB does have similar, has any other worked on similar project with aims I mentioned in OP?

I don't mind reinventing the wheel occasionally but...

wait, I do want to work this out on my own before learning "the right way" to do it.

OK thanks for quick reply!

Oh, from quick skim, I just see Screen 20 as my complete and total graphics worries. hmm... that does not seem like much.

Maybe I need to talk to Tourist Trap. ( a joke, is he laughing? )
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Help Translating a draw strings routine to FB

Post by dodicat »

Example of freebasic's DRAW.

Code: Select all

#define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c) 
Dim As String sh = "BM400,300M+0,10M+0,-90"
ScreenRes 800,600,,2 : screenset 1,0
Width 800\8,600\16 'font size
Dim As long sa,ma,ha,ctr
Dim As String lt,TheString,t,s,m,h
Dim As Any Ptr i=Imagecreate(800,600,18)
For z As Single=0 To 8*Atn(1)-.1 Step 8*Atn(1)/12
    ctr+=1
    Draw String i,(400+180*Cos(z-2*Atn(1)*(2/3)),300+180*Sin(z-2*Atn(1)*(2/3))),Str(ctr Mod 13),2
    Circle i,(400+220*Cos(z),300+220*Sin(z)),2,15,,,,f
Next z
Circle i,(400,300),220,6
Do
    t=Time :  windowtitle date
    If lt<>t Then
     s=Mid(t,7,2):m=Mid(t,4,2):h=Mid(t,1,2)
sa=map(0,60,Vallng(s),360,0):ma=map(0,60,(Vallng(m)+Val(s)/60),360,0):ha=map(0,12,(Vallng(h)+Val(m)/60),360,0)
 TheString="C6S6Ta" & ha & sh & "C6S10Ta" &ma & sh & "C3S11Ta" &sa & sh
        Put(0,0),i,pset
        locate 3,1: color 7,18
        print TheString
        draw  TheString
        flip
    End If
    Sleep 100,1
    lt=t
Loop Until Len(Inkey)
Imagedestroy i
 
 
bplus
Posts: 56
Joined: May 01, 2017 15:57

Re: Help Translating a draw strings routine to FB

Post by bplus »

Ha! I didn't see that coming, nice one.
OSchmidt
Posts: 49
Joined: Jan 01, 2016 12:27
Contact:

Re: Help Translating a draw strings routine to FB

Post by OSchmidt »

bplus wrote: > "FreeBASIC has draw which is similar."

... I can remember my system better when I make it my own. I had a few ideas for "improvements", in my mind at least.

Since FB does have similar, has any other worked on similar project with aims I mentioned in OP?
FWIW, I've implemented (more or less for fun) a quite FB/QB-compatible Draw-replacement in VB6
(as part of an ImageWidget, see VB6-ClassCode below).

Though this "maps" the parsed DrawString-commands against the cairo-graphics-library for rendering
(which I prefer with all my stuff) - but what then comes along "for free", is antialiased Output of Lines and Polygons.

For example, here is (expressed in VBScript), basically the same thing as in dodicats Clock-example
(just in a Timer-EventHandler instead of a "BackBuffer-Flipping-Loop"):

Code: Select all

Sub tmrRefresh_Timer()
    Dim S, HandsDef, T:  T = Time 
      
    HandsDef = " BM" & Int(ImgW.CanvasWidth  / 2) & "," & Int(ImgW.CanvasHeight / 2) & "M+0,15M+0,-95"

    S = "BW8 C4S5Ta" & -((Hour(T) Mod 12) + Minute(T) / 60) * 30 & HandsDef & _
        "BW4 C3S7Ta" & -(Minute(T) + Second(T) / 60) * 6 & HandsDef & _
        "BW1 C2S9Ta" & -Second(T) * 6 & HandsDef

    ImgW.Cls
    ImgW.QBDraw Cstr(S) 
    ImgW.Refresh
End Sub
In the ScreenShot below you can see, how the AntiAliasing of cairo makes the rendered ClockHands nicer to look at:
Image

In case you want to take a look at the full VBScript-Demo, I've included it as another example (QBDrawString.vbs)
in the Zip-Download for "ScriptGUI5" (which runs "out of the box" on Win-Systems > WinXP, no installer needed).
Here is the Download-Link for it: http://vbRichClient.com/Downloads/ScriptGUI5.zip

The VBScript-Demo also shows the output of somewhat larger (more complex) Draw-Strings, which I've
"stolen" here in the Forum (e.g. the DrawStrings for the Polygon-Faces are from BasicCoder2 here:
http://www.freebasic.net/forum/viewtopi ... 1f#p213539

Ok, here the VB6-ClassModule, as a kind of "BluePrint" for those who plan to convert it to FB or other languages
(probably easiest to port, when a mapping to the cairo-flat-API is planned)

Code: Select all

Option Explicit

Private mCanvasSrf As cCairoSurface, mCanvas As cCairoContext
 
Private sDraw$, Pos&, Cmd$, Args(1) As String, x#, y#, Scl#, Angles(), Agl#, AglX#, AglY#, LW#
Private IsAbs As Boolean, NoCoordUpdates As Boolean, StrokeColor&, FillColor&, RevFillColor&

Public Sub SetCanvasSize(ByVal Width As Long, ByVal Height As Long)
  Set mCanvasSrf = Cairo.CreateSurface(Width, Height)
End Sub
 
Public Property Get Canvas() As cCairoContext
  If mCanvasSrf Is Nothing Then SetCanvasSize 800, 600
  If mCanvas Is Nothing Then Set mCanvas = mCanvasSrf.CreateContext
  Set Canvas = mCanvas
End Property

Public Sub Cls(Optional ByVal BackColor As Long = -1)
  If mCanvasSrf Is Nothing Then Exit Sub
  If BackColor = -1 Then Canvas.Operator = CAIRO_OPERATOR_CLEAR Else Canvas.SetSourceColor BackColor
  Canvas.Paint
  Canvas.Operator = CAIRO_OPERATOR_OVER
End Sub

Public Property Get CanvasWidth() As Long
  If mCanvasSrf Is Nothing Then SetCanvasSize W.ScaleWidth, W.ScaleHeight
  CanvasWidth = mCanvasSrf.Width
End Property
Public Property Get CanvasHeight() As Long
  If mCanvasSrf Is Nothing Then SetCanvasSize W.ScaleWidth, W.ScaleHeight
  CanvasHeight = mCanvasSrf.Height
End Property

Public Sub Draw(ByVal sDrawString, Optional ByVal UseFloodFill As Boolean, Optional ByVal UseQBColors As Boolean)
Dim Pxl() As Long, sx#, sy#, xx!, yy!
  If mCanvasSrf Is Nothing Then SetCanvasSize 800, 600
  
  Angles = Array(0, 90, 180, 270)
  
  If Len(sDrawString) = 0 Then x = 0: y = 0: Agl = 0: AglX = 0: AglY = 0: Scl = 1: SetScaleAndAngle: Exit Sub
  
  If Scl = 0 Then
    Scl = 1: SetScaleAndAngle
    Canvas.SetSourceColor vbBlack
    Canvas.FillRule = CAIRO_FILL_RULE_EVEN_ODD
  End If
  
  sDraw = Replace$(Replace$(Replace$(Trim$(UCase$(sDrawString)), " ", ""), "+-", "-"), "-+", "-")
  Pos = 0
  Canvas.AntiAlias = IIf(UseFloodFill, CAIRO_ANTIALIAS_NONE, CAIRO_ANTIALIAS_DEFAULT)
  Do
    NoCoordUpdates = False
    ParseCommand
    If Len(Cmd) Then ParseArgs UseQBColors Else Exit Do
    Select Case Cmd
      Case "C"
        If LW > 0 Then mCanvas.SetLineWidth 1 / Scl * LW
        mCanvas.Stroke
        mCanvas.MoveTo x, y
        mCanvas.SetSourceColor StrokeColor
      Case "BW"
        If LW > 0 Then mCanvas.SetLineWidth 1 / Scl * LW: mCanvas.Stroke
        LW = Args(0)
      Case "BM"
        mCanvas.MoveTo Args(0), Args(1)
        If Not NoCoordUpdates Then x = Args(0): y = Args(1)
        If IsAbs Then AglX = x: AglY = y: SetScaleAndAngle
      Case "M"
        mCanvas.LineTo Args(0), Args(1)
        If NoCoordUpdates Then mCanvas.MoveTo x, y Else x = Args(0): y = Args(1)
      Case "P"
        If LW > 0 Then mCanvas.SetLineWidth 1 / Scl * LW
        If UseFloodFill Then
          mCanvas.Save
            mCanvas.Matrix.CalculateScale sx, sy: If mCanvas.GetLineWidth * sx < 1 Then mCanvas.SetLineWidth 1 / sx
            If LW > 0 Then mCanvas.SetLineWidth 1 / Scl * LW
            mCanvas.SetSourceColor StrokeColor: mCanvas.Stroke
          mCanvas.Restore
          xx = x: yy = y: mCanvas.Matrix.CalculatePointSingle xx, yy
          FloodFill xx, yy, RevFillColor
        Else
          mCanvas.SetSourceColor FillColor:   mCanvas.Fill True
          mCanvas.SetSourceColor StrokeColor: mCanvas.Stroke
        End If
      Case "S", "TA"
        If Cmd = "S" Then Scl = Args(0) / 4 Else Agl = Args(0): AglX = x: AglY = y
        SetScaleAndAngle
    End Select
  Loop
  If LW > 0 Then mCanvas.SetLineWidth 1 / Scl * LW: LW = 0
  mCanvas.SetSourceColor StrokeColor: mCanvas.Stroke
  mCanvas.AntiAlias = CAIRO_ANTIALIAS_DEFAULT
End Sub

Public Sub FloodFill(ByVal x As Long, ByVal y As Long, ByVal NewColor As Long)
  If mCanvasSrf Is Nothing Then SetCanvasSize 800, 600
  Dim Pxl() As Long
  If Not mCanvasSrf.BindToArrayLong(Pxl) Then Exit Sub
  RecFloodFill Pxl, x, y, NewColor
  mCanvasSrf.ReleaseArrayLong Pxl
End Sub

Private Sub RecFloodFill(Pxl() As Long, ByVal x&, ByVal y&, ByVal NewColor&)
Dim xL&, xR&, OldColor&, UBx&, UBy&
  UBx = UBound(Pxl, 1): UBy = UBound(Pxl, 2)
  If x < 0 Or x > UBx Or y < 0 Or y > UBy Then Exit Sub
  If Pxl(x, y) = NewColor Then Exit Sub Else OldColor = Pxl(x, y)

  For xL = x To 1 Step -1 'find most left pixel
    If Pxl(xL - 1, y) <> OldColor Then Exit For
  Next xL
  For xR = x To UBx - 1 'find most right pixel
    If Pxl(xR + 1, y) <> OldColor Then Exit For
  Next xR
  For x = xL To xR: Pxl(x, y) = NewColor: Next 'fill this part

  'Recursion only in y-direction
  If y > 0 Then 'check scanline above
    For x = xL To xR
      If Pxl(x, y - 1) = OldColor Then RecFloodFill Pxl, x, y - 1, NewColor
    Next
  End If
  If y < UBy Then 'check scanline below
    For x = xL To xR
      If Pxl(x, y + 1) = OldColor Then RecFloodFill Pxl, x, y + 1, NewColor
    Next
  End If
End Sub

Private Sub ParseCommand()
  Cmd = ""
  For Pos = Pos + 1 To Len(sDraw)
    Cmd = Mid$(sDraw, Pos, 1)
    If Cmd = "B" And Mid$(sDraw, Pos + 1, 1) = "B" Then Pos = Pos + 1 ': mCanvas.Stroke: mCanvas.ClearPath
    Select Case Cmd
      Case "A", "C", "M", "L", "R", "U", "D", "E", "F", "G", "H", "S", "P": Exit Sub
      Case "B", "T": Pos = Pos + 1: Cmd = Cmd & Mid(sDraw, Pos, 1): Exit Sub
      Case "N": NoCoordUpdates = True: ParseCommand: Exit Sub
    End Select
  Next
End Sub
 
Private Sub ParseArgs(UseQBColors As Boolean)
  Dim i As Long, a() As String, BPrefix As Boolean
  For i = Pos + 1 To Len(sDraw)
    If Mid$(sDraw, i, 1) >= "A" Then Exit For
  Next
  
  a = Split(Trim$(Mid$(sDraw, Pos + 1, i - Pos - 1)), ",")
  ReDim Preserve a(1)
  Pos = i - 1
  IsAbs = True
  For i = 0 To UBound(a)
    a(i) = Trim$(a(i))
    Args(i) = Val(IIf(Len(a(i)), a(i), 1))
    If Left(a(i), 1) = "-" Or Left(a(i), 1) = "+" Or IsAbs = False Then
      Args(i) = IIf(i, y, x) + Args(i): IsAbs = False
    End If
  Next
  
  If Left$(Cmd, 1) = "B" Then Cmd = Right$(Cmd, 1): BPrefix = True
  Select Case Cmd
    Case "L": Cmd = "M":  Args(1) = y:           Args(0) = x - Args(0)
    Case "R": Cmd = "M":  Args(1) = y:           Args(0) = x + Args(0)
    Case "U": Cmd = "M":  Args(1) = y - Args(0): Args(0) = x
    Case "D": Cmd = "M":  Args(1) = y + Args(0): Args(0) = x
    Case "E": Cmd = "M":  Args(1) = y - Args(0): Args(0) = x + Args(0)
    Case "F": Cmd = "M":  Args(1) = y + Args(0): Args(0) = x + Args(0)
    Case "G": Cmd = "M":  Args(1) = y + Args(0): Args(0) = x - Args(0)
    Case "H": Cmd = "M":  Args(1) = y - Args(0): Args(0) = x - Args(0)
    Case "A": Cmd = "TA": Args(0) = Angles(Args(0))
    Case "C": StrokeColor = GetColor(Args(0), UseQBColors): FillColor = -1
    Case "P": StrokeColor = GetColor(Args(1), UseQBColors): FillColor = GetColor(Args(0), UseQBColors, RevFillColor)
    Case "TA": If Not IsAbs Then Args(0) = Args(0) - x
  End Select
  If BPrefix Then Cmd = "B" & Cmd
End Sub

Private Function GetColor(ByVal c As Currency, UseQBColors As Boolean, Optional ColorReverse As Long)
  If c > 2147483648@ And Not UseQBColors Then c = c - 2147483648@ Else GetColor = QBColor(c And &HF&): Exit Function
  GetColor = RGB((c \ 65536) And &HFF, (c \ CLng(256)) And &HFF, c And &HFF)
  ColorReverse = RGB(c And &HFF, (c \ CLng(256)) And &HFF, (c \ 65536) And &HFF)
End Function

Private Sub SetScaleAndAngle()
  Canvas.ClearPath
  Canvas.MatrixResetToIdentity
  Canvas.TranslateDrawings AglX + 0.5, AglY + 0.5
    Canvas.ScaleDrawings Scl, Scl
    Canvas.RotateDrawingsDeg -Agl
    Canvas.SetLineWidth 1 / Scl
  Canvas.TranslateDrawings -AglX, -AglY
End Sub
HTH

Olaf
Post Reply