Page 1 of 1

Drawing following mouse/pen move with curve approximation

Posted: Thu Jul 23, 2015 10:07 am
by djes
I'm trying to help blendman for his drawing/animation software.

We are used to great paint tools like TVPaint (ex-Aura) which are able to follow precisely the mouse/pen user movement. Especially when the user is fast, the software draws nice curves/splines, and not (as in other software) only lines.

Add to this that we would like to plot brushes at regular intervals, handle antialiasing and thickness. And... It should be multiplatform.

Here's a first code not optimised that I've created as a model. I'm using my own curve routines, but it's not optimal, and I'm working on a Bresenham way of doing this. But it's difficult, and any help would be appreciated.

Edit : modified code for better multiplatform, thanks to Trond and davido

Code: Select all

;
; ------------------------------------------------------------
;
;   PureBasic - Drawing following mouse movement (curve approximation)
;   by djes@free.fr in 2015
;
;    (c) 2005 - Background code by Fantaisie Software
;        2015 - MouseMovementFollow by djes for blendman (aka super-smooth)
;
; ------------------------------------------------------------
;
CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Merci d'activer la gestion des threads" 
CompilerEndIf

#DebugLevel = 1
DebugLevel #DebugLevel

;---- Constants

#CurveDeviation = 1.0
#CurveMinimalDistance = 10

;---- Structures

Structure vertex
  x.f
  y.f
EndStructure

;---- Global variables

Global Semaphore = CreateSemaphore()
Global Mutex     = CreateMutex()

Global NewList Coords.vertex()
Global Dim SplineCoords.vertex(5)

Global CanvasWidth, CanvasHeight

;---- Procedures

Procedure.d min(a.d, b.d)
  If a<b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
EndProcedure

Procedure.d max(a.d, b.d)
  If a>b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
EndProcedure

Procedure.d VectorLength(vx.d, vy.d)
  ProcedureReturn Sqr(vx*vx + vy*vy)
EndProcedure

Procedure SetPixelAA( x0, y0, color, blend = 0)
  Define.i r = Red(color), g = Green(color), b=Blue(color), a=Alpha(color), c
  If x0 >= 0 And y0 >= 0 And x0 < CanvasWidth-1 And y0 < CanvasHeight-1
    c = Point(x0, y0)
    Plot(x0, y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
  EndIf  
EndProcedure

Procedure LineAA(x0.i, y0.i, x1.i, y1.i, color.i)
  ; /* draws an anti-aliased line on background */
  ; adapted by djes upon Alois Zingl's work - http://members.chello.at/~easyfilter/bresenham.html
  Define.i dx = Abs(x1 - x0), sx : If x0 < x1 : sx = 1 : Else : sx = -1 : EndIf
  Define.i dy = Abs(y1 - y0), sy : If y0 < y1 : sy = 1 : Else : sy = -1 : EndIf
  Define.i x2, e2, err = dx - dy; /* error value e_xy */
  Define.i ed : If dx + dy = 0 : ed = 0 : Else : ed = Sqr(dx*dx + dy*dy) : EndIf
  Define.i r = Red(color), g = Green(color), b=Blue(color), a=Alpha(color), c
  Define.i blend
  While #True ; pixel loop
    If x0 >= 0 And y0 >= 0 And x0 < CanvasWidth-1 And y0 < CanvasHeight-1
      blend = 255*Abs(err - dx+dy)/ed : c = Point(x0,y0)    
      Plot(x0, y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
    EndIf
    e2 = err : x2 = x0;
    If (2*e2 >= -dx)  ;{ /* x Step */
      If (x0 = x1) : Break : EndIf
      If (e2+dy < ed) 
        If x0 >= 0 And (y0+sy) >= 0 And x0 < CanvasWidth-1 And (y0+sy) < CanvasHeight-1
          blend = 255*(e2+dy)/ed : c = Point(x0,y0+sy)
          Plot(x0, y0+sy, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
        EndIf  
      EndIf
      err - dy : x0 + sx;
    EndIf
    If (2*e2 <= dy) ;{ /* y Step */
      If (y0 = y1) : Break : EndIf
      If (dx-e2 < ed)
        If (x2+sx) >= 0 And (y0) >= 0 And (x2+sx) < CanvasWidth-1 And y0 < CanvasHeight-1
          blend = 255*(dx-e2)/ed : c = Point(x2+sx,y0)
          Plot(x2+sx,y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
        EndIf  
      EndIf
      err + dx : y0 + sy
    EndIf
  Wend
EndProcedure

Procedure PlotLineWidth(x0.i, y0.i, x1.i, y1.i, wd.f, color)
  ; /* draws an anti-aliased line of wd pixel width
  ; adapted by djes upon Alois Zingl's work - http://members.chello.at/~easyfilter/bresenham.html
  
  Define.i dx, dy, sx, sy, err, e2, x2, y2 ;                          /* error value e_xy */
  Define.d ed, dx2, dy2
  dx = Abs(x1-x0) : sx = -1 : If x0 < x1 : sx = 1 : EndIf
  dy = Abs(y1-y0) : sy = -1 : If y0 < y1 : sy = 1 : EndIf
  err = dx-dy
  dx2 = dx*dx : dy2 = dy*dy
  If dx+dy = 0 : ed = 1 : Else : ed = Sqr(dx2+dy2) : EndIf
  
  wd = (wd+1)/2
  While #True ; /* pixel loop */
    SetPixelAA(x0, y0, color, max(0, 255*(Abs(err-dx+dy)/ed-wd+1)));
    e2 = err : x2 = x0;
    If 2*e2 >= -dx ;                                            /* x Step */
      e2 + dy : y2 = y0
      While e2 < ed*wd And (y1 <> y2 Or dx > dy); )
        y2 + sy
        SetPixelAA(x0, y2, color, max(0,255*(Abs(e2)/ed-wd+1)));
        e2 + dx
      Wend
      If (x0 = x1) : Break : EndIf
      e2 = err : err - dy : x0 + sx; 
    EndIf 
    If 2*e2 <= dy ;                                             /* y Step */
      e2 = dx-e2
      While e2 < ed*wd And (x1 <> x2 Or dx < dy)
        x2 + sx
        SetPixelAA(x2, y0, color, max(0,255*(Abs(e2)/ed-wd+1)));
        e2 + dy
      Wend
      If (y0 = y1) : Break : EndIf
      err + dx : y0 + sy 
    EndIf
  Wend
EndProcedure

;-------------------------------------------
; Curves routines For smooth mouse following
; by djes@free.fr in 2015

; spline between p0-p1, tangent with p1-p2
Procedure CurveStart( x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, color = 0)
  
  ;Curve is between p1 and p0
  vx.d = x1 - x0
  vy.d = y1 - y0
  d.d = VectorLength(vx, vy)
  
  t2x.d = x2 - x1
  t2y.d = y2 - y1
  
  ;tangeant
  n2.d = VectorLength(t2x, t2y)
  If n2 = 0 : n2 = 0.00001 : EndIf
  f2.d = 1.0/n2 * #CurveDeviation
  
  ;minimal distance between p0 and p1
  If d >= #CurveMinimalDistance And n2 > 1
    
    d/5 ;subdivide curve into 5 pixels segments
    interv.d = 1/d
    u.d = 0
    ox = x0 : oy = y0
    
    While u < 1
      ;For i = 1 To d
      
      x.d = x0 + u*vx - Sqr( Sin(u*#PI) * f2 ) * Tan(u) * t2x
      y.d = y0 + u*vy - Sqr( Sin(u*#PI) * f2 ) * Tan(u) * t2y
      
      ;SetPixelAA(x, y, color)  
      
      LineAA(ox, oy, x, y, color)
      ox = x : oy = y
      
      u + interv
      
      ;Next i
    Wend
    
    LineAA(x, y, x1, y1, color)
    
  Else
    
    LineAA(x0, y0, x1, y1, color)
    
  EndIf
  
EndProcedure  

;Spline between p1-p2 with two tangeants given by p0-p1 and p2-p3
Procedure CurveMiddle( x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, x3.d, y3.d, color = 0)
  
  CompilerIf #DebugLevel = 2
    LineXY(x1, y1, x2, y2, 0)
    Line(x1-4, y1, 8, 1, RGB(0, 0, 255))
    Line(x1, y1-4, 1, 8, RGB(0, 0, 255))
    Line(x2-4, y2, 8, 1, RGB(0, 255, 0))
    Line(x2, y2-4, 1, 8, RGB(0, 255, 0))
  CompilerEndIf
  
  ;The curve is between p1 and p2
  vx.d = x2 - x1
  vy.d = y2 - y1
  d.d = VectorLength(vx, vy)
  
  ;1st tangeant
  t1x.d = x1 - x0
  t1y.d = y1 - y0
  n1.d = VectorLength(t1x, t1y)
  If n1 = 0 : n1 = 0.00001 : EndIf
  f1.d = 1.0/n1 * #CurveDeviation
  
  ;2st tangeant
  t2x.d = x3 - x2
  t2y.d = y3 - y2
  n2.d = VectorLength(t2x, t2y)
  If n2 = 0 : n2 = 0.00001 : EndIf
  f2.d = 1.0/n2 * #CurveDeviation 
  
  Debug d
  ;minimal distance between p1 and p2
  If d >= #CurveMinimalDistance And n1 > 1 And n2 > 1
    
    d/5 ;subdivide curve into 5 pixels segments
    interv.d = 1.0/d
    u.d = 0
    ox = x1 : oy = y1
    
    While u < 1
      ;For i = 1 To cl
      
      ;      x.d = x1 + u*vx + ( Sqr( Sin(u*#PI) *f1) * Pow( Sin((1-u)*#PI/2), 2) * t1x - Sqr( Sin(u*#PI) *f2) * Pow( Sin(u*#PI/2), 2) * t2x ) /2
      ;      y.d = y1 + u*vy + ( Sqr( Sin(u*#PI) *f1) * Pow( Sin((1-u)*#PI/2), 2) * t1y - Sqr( Sin(u*#PI) *f2) * Pow( Sin(u*#PI/2), 2) * t2y ) /2
      ;      x.d = x1 + u*vx + ( Sqr( Sin(u*#PI) *f1) * Tan( Sin((1-u)*#PI/2)) * t1x - Sqr( Sin(u*#PI) *f2) * Tan( Sin(u*#PI/2)) * t2x ) /2
      ;      y.d = y1 + u*vy + ( Sqr( Sin(u*#PI) *f1) * Tan( Sin((1-u)*#PI/2)) * t1y - Sqr( Sin(u*#PI) *f2) * Tan( Sin(u*#PI/2)) * t2y ) /2
      x.d = x1 + u*vx + ( Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1x - Sqr( Sin(u*#PI) * f2) * Tan(u) * t2x ) / 2
      y.d = y1 + u*vy + ( Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1y - Sqr( Sin(u*#PI) * f2) * Tan(u) * t2y ) / 2
      
      ;SetPixelAA(x, y, 0)  
      
      LineAA(ox, oy, x, y, color)
      ox = x : oy = y
      
      u + interv
      
      ;Next i
    Wend
    
    LineAA(x, y, x2, y2, color)
    
  Else
    
    LineAA(x1, y1, x2, y2, color)
    
  EndIf
  
EndProcedure  

;Spline between p1-p2 with tangeant given by p0-p1
Procedure CurveEnd( x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, color = 0)
  
  ;The curve is between p1 and p2
  vx.d = x2 - x1
  vy.d = y2 - y1
  d.d = VectorLength(vx, vy)
  
  ;tangeant
  t1x.d = x1 - x0
  t1y.d = y1 - y0
  n1.d = VectorLength(t1x, t1y)
  If n1 = 0 : n1 = 0.00001 : EndIf
  f1.d = 1.0/n1 * #CurveDeviation
  
  ;minimal distance between p1 and p2
  If d >= #CurveMinimalDistance And n1 > 1
    
    d/5 ;subdivide curve into 5 pixels segments
    interv.d = 1/d 
    u.d = 0
    ox = x1 : oy = y1
    
    While u < 1
      ;For i = 1 To d
      
      x.d = x1 + u*vx + Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1x 
      y.d = y1 + u*vy + Sqr( Sin(u*#PI) * f1) * Tan(1-u) * t1y 
      
      ;SetPixelAA(x, y, color)  
      
      LineAA(ox, oy, x, y, color)
      ox = x : oy = y
      
      u + interv
      
      ;Next i
    Wend
    
    LineAA(x, y, x2, y2, color)
    
  Else
    
    LineAA(x1, y1, x2, y2, color)
    
  EndIf
  
EndProcedure  
;-------------------------------------------

; Wait mouse input movement sequence and draw
; corresponding plot/lines/curves
Procedure MouseMovementFollow(Null)
  
  While #True
    
    WaitSemaphore(Semaphore)
    
    If StartDrawing(CanvasOutput(0))
      LockMutex(Mutex)
      n = ListSize(Coords())
      While n > 0
        n = 0
        FirstElement(Coords())
        SplineCoords(0)\x = Coords()\x : SplineCoords(0)\y = Coords()\y
        If SplineCoords(0)\x = -2
          ;Sequence : -2 -> Nothing
          Debug "Sequence : -2"
          DeleteElement(Coords(), 1)
          n = ListSize(Coords())
        ElseIf SplineCoords(0)\x = -1
          If NextElement(Coords())
            SplineCoords(1)\x = Coords()\x : SplineCoords(1)\y = Coords()\y
            If SplineCoords(1)\x = -2
              ;Sequence : -1-2 -> Nothing
              Debug "Sequence : -1-2"
              ;Impossible... Anyway !
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              n = ListSize(Coords()) ;Continue processing
            Else
              If NextElement(Coords())
                SplineCoords(2)\x = Coords()\x : SplineCoords(2)\y = Coords()\y
                If SplineCoords(2)\x = -2
                  ;Sequence : -1P-2 -> Pixel
                  Debug "Sequence : -1P-2"
                  SetPixelAA(SplineCoords(1)\x, SplineCoords(1)\y, RGB(255, 0, 0))
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  n = ListSize(Coords()) ;Continue processing
                Else
                  If NextElement(Coords())
                    SplineCoords(3)\x = Coords()\x : SplineCoords(3)\y = Coords()\y
                    If SplineCoords(3)\x = -2
                      ;Sequence : -1PP-2 -> Line
                      Debug "Sequence : -1PP-2"
                      LineAA(SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, RGB(255, 0, 0))
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    Else
                      ;Sequence : -1PPP -> Start of curve (only one tangeant)
                      Debug "Sequence : -1PPP"
                      CurveStart(SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, SplineCoords(3)\x, SplineCoords(3)\y, RGB(255, 0, 0))
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    EndIf
                  EndIf
                EndIf
              EndIf
            EndIf
          EndIf
        Else
          If NextElement(Coords())
            SplineCoords(1)\x = Coords()\x : SplineCoords(1)\y = Coords()\y
            If SplineCoords(1)\x = -2
              ;Sequence : P-2 -> Pixel
              Debug "Sequence : P-2"
              ;Impossible... Anyway !
              SetPixelAA(SplineCoords(0)\x, SplineCoords(0)\y, RGB(255, 0, 0))
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              FirstElement(Coords()) : DeleteElement(Coords(), 1)
              n = ListSize(Coords()) ;Continue processing
            Else
              If NextElement(Coords())
                SplineCoords(2)\x = Coords()\x : SplineCoords(2)\y = Coords()\y
                If SplineCoords(2)\x = -2
                  ;Sequence : PP-2 -> Line
                  Debug "Sequence : PP-2"
                  LineAA(SplineCoords(0)\x, SplineCoords(0)\y, SplineCoords(1)\x, SplineCoords(1)\y, RGB(255, 0, 0))
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  FirstElement(Coords()) : DeleteElement(Coords(), 1)
                  n = ListSize(Coords()) ;Continue processing
                Else
                  If NextElement(Coords())
                    SplineCoords(3)\x = Coords()\x : SplineCoords(3)\y = Coords()\y
                    If SplineCoords(3)\x = -2
                      ;Sequence : PPP-2 -> End of curve (one tangeant)
                      Debug "Sequence : PPP-2"
                      CurveEnd(SplineCoords(0)\x, SplineCoords(0)\y, SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, RGB(255, 0, 0))
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    Else
                      ;Sequence : PPPP -> Full curve (two tangeants)
                      Debug "Sequence : PPPP"
                      CurveMiddle(SplineCoords(0)\x, SplineCoords(0)\y, SplineCoords(1)\x, SplineCoords(1)\y, SplineCoords(2)\x, SplineCoords(2)\y, SplineCoords(3)\x, SplineCoords(3)\y, RGB(255, 0, 0))
                      FirstElement(Coords()) : DeleteElement(Coords(), 1)
                      n = ListSize(Coords()) ;Continue processing
                    EndIf
                  EndIf
                EndIf
              EndIf  
            EndIf
          EndIf
        EndIf
      Wend
      UnlockMutex(Mutex)  
      CompilerIf #PB_Compiler_OS = #PB_OS_Linux
        gdk_threads_enter_();
        StopDrawing()
        gdk_threads_leave_();
      CompilerElse
        StopDrawing()
      CompilerEndIf
    EndIf
    
  Wend
  
EndProcedure

;----  Main

CreateThread(@MouseMovementFollow(), 0)

; Ouverture de la fenĂȘtre
OpenWindow(0, 0, 0, 800, 600, "Drawing with curve approximation",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
CanvasWidth = 800 : CanvasHeight = 600
CanvasGadget(0, 0, 0, CanvasWidth, CanvasHeight)

lmb = #False : mmb = #False : rmb = #False
x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
If y < 100 : y = 100 : EndIf   

Repeat
  
  Repeat 
    Event  = WindowEvent() 
    Select Event 
      Case #PB_Event_Gadget 
        Select EventGadget() 
          Case 0
            Select EventType()
              Case #PB_EventType_LeftButtonDown 
                lmb = #True
                LockMutex(Mutex)
                AddElement(Coords())
                Coords()\x = -1
                ;Signal to the drawing routine that we start a new curve
                UnlockMutex(Mutex)
                SignalSemaphore(Semaphore)
              Case #PB_EventType_LeftButtonUp
                lmb = #False
                LockMutex(Mutex)
                AddElement(Coords())
                Coords()\x = -2
                ;Signal to the drawing routine that we end the curve
                UnlockMutex(Mutex)
                SignalSemaphore(Semaphore)
              Case #PB_EventType_MiddleButtonDown 
                mmb = #True
              Case #PB_EventType_MiddleButtonUp
                mmb = #False  
              Case #PB_EventType_RightButtonDown 
                rmb = #True
              Case #PB_EventType_RightButtonUp
                rmb = #False
                
              Case #PB_EventType_MouseWheel
                tiks = GetGadgetAttribute(0, #PB_Canvas_WheelDelta)
              Case #PB_EventType_MouseMove
                x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
                y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
                If y < 100 : y = 100 : EndIf            
            EndSelect 
        EndSelect
      Case #PB_Event_CloseWindow 
        End  
    EndSelect 
  Until Event = 0
  
  If lmb 
    If ox <> x Or oy <> y
      ;Mouse moved
      LockMutex(Mutex)
      AddElement(Coords())
      Coords()\x = x
      Coords()\y = y
      ox = x : oy = y
      UnlockMutex(Mutex)
      SignalSemaphore(Semaphore)
    EndIf
  EndIf
  
  ;- Main drawing
  StartDrawing(CanvasOutput(0))
  
  If rmb
    Box(0, 0, 800, 600, #White)
  EndIf
  
  ;-Spline test
  ;x1 = 200 : y1 = 200 :   Plot(x1, y1, RGB(0, 0, 255))
  ;x2 = 200 : y2 = 250 :   Plot(x2, y2, RGB(0, 0, 255))
  ;x3 = 350 : y3 = 250 :   Plot(x3, y3, RGB(0, 0, 255))
  ;x4 = 400 : y4 = 250 :   Plot(x4, y4, RGB(0, 0, 255))
  ;CurveStart(x1, y1, x2, y2, x, y, rgb(255, 0, 0))
  ;CurveMiddle(x, y, x2, y2, x3, y3, x4, y4, rgb(255, 0, 0))
  ;CurveEnd(x, y, x2, y2, x3, y3, rgb(255, 0, 0))
  PlotLineWidth(500, 500, 10, 50, 5, RGB(55, 125, 25))
  
  DrawText(0,5, "X=" + Str(x) + "   Y=" + Str(y) + "     " ) 
  If lmb
    DrawText(0,30, "Left button", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(0,30, "Left button", RGB(255,255,255))
  EndIf
  If mmb
    DrawText(150,30, "Middle button", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(150,30, "Middle button", RGB(255,255,255))
  EndIf
  If rmb
    DrawText(300,30, "Right button", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(300,30, "Right button", RGB(255,255,255))
  EndIf  
  If tiks <> 0
    DrawText(450,30, "Scroll wheel", RGB(255,0,0),RGB(255,255,0))
  Else
    DrawText(450,30, "Scroll wheel", RGB(255,255,255))
  EndIf
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    gdk_threads_enter_();
    StopDrawing()
    gdk_threads_leave_();
  CompilerElse
    StopDrawing()
  CompilerEndIf
  
ForEver

End

End   ; All the opened windows are closed automatically by PureBasic

Re: Drawing following mouse/pen move with curve approximatio

Posted: Thu Jul 23, 2015 11:54 am
by Trond
It hangs on linux when pressing the left mouse button. GTK can only be used by the main thread, so maybe you can't do StartDrawing(CanvasOutput()) in another thread?

Also, the color constants are predefined in windows only:
#Black = 0
#Red = $FF0000
#White = $FFFFFF

Re: Drawing following mouse/pen move with curve approximatio

Posted: Thu Jul 23, 2015 1:34 pm
by djes
Trond wrote:It hangs on linux when pressing the left mouse button. GTK can only be used by the main thread, so maybe you can't do StartDrawing(CanvasOutput()) in another thread?

Also, the color constants are predefined in windows only:
#Black = 0
#Red = $FF0000
#White = $FFFFFF
Thank you for your report ! I don't know for GTK but if true, it's annoying !

Re: Drawing following mouse/pen move with curve approximatio

Posted: Thu Jul 23, 2015 10:35 pm
by davido
@djes,
Works fine on Mac if colours defined.

Re: Drawing following mouse/pen move with curve approximatio

Posted: Thu Jul 23, 2015 10:50 pm
by Trond
Hangs / crashes in mouse follow:

Code: Select all

          EndIf
        EndIf
      Wend
      Debug "End"
      UnlockMutex(Mutex) 
      Debug "end 2"
      StopDrawing() ; <---------------- here
      Debug "end 3" ; not shown.
    EndIf
   
  Wend
 
EndProcedure
http://blogs.operationaldynamics.com/an ... -awareness

Re: Drawing following mouse/pen move with curve approximatio

Posted: Thu Jul 23, 2015 11:03 pm
by Trond
There I fixed it. No guarantees!

Code: Select all

      gdk_threads_enter_();
      StopDrawing()
      gdk_threads_leave_();
Really interesting, as I have read about the "can't do gtk from threads" many times. Turns out it's not really a problem as long as you lock and unlock the gdk mutex properly.

Re: Drawing following mouse/pen move with curve approximatio

Posted: Thu Jul 23, 2015 11:24 pm
by djes
Great, thank you ! I'll change the code for linux (and mac) tomorrow.

Re: Drawing following mouse/pen move with curve approximatio

Posted: Fri Jul 24, 2015 5:25 pm
by Trond
Note that maybe the lock needs to be locked before StartDrawing().