Drawing following mouse/pen move with curve approximation

Just starting out? Need help? Post your questions and find answers here.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Drawing following mouse/pen move with curve approximation

Post 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
Last edited by djes on Fri Aug 21, 2015 6:25 pm, edited 3 times in total.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Drawing following mouse/pen move with curve approximatio

Post 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
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Drawing following mouse/pen move with curve approximatio

Post 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 !
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Drawing following mouse/pen move with curve approximatio

Post by davido »

@djes,
Works fine on Mac if colours defined.
DE AA EB
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Drawing following mouse/pen move with curve approximatio

Post 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
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Drawing following mouse/pen move with curve approximatio

Post 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.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Drawing following mouse/pen move with curve approximatio

Post by djes »

Great, thank you ! I'll change the code for linux (and mac) tomorrow.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Drawing following mouse/pen move with curve approximatio

Post by Trond »

Note that maybe the lock needs to be locked before StartDrawing().
Post Reply