J'ai commencé à convertir à la volée le code que j'avais. J'arrête pour l'instant. Ce n'est pas encore fonctionnel, ni vérifié !
MAJ: j'ai laissé tomber le bézier, et refait une petite fonction 'curve' qui crée une courbe entre deux mouvements de la souris en fonction de la direction prise par le 3ème point. J'ai laissé plein de code inutile pour l'instant, dont des exemples de Catmull-Rom qui utilisent deux points directeurs et qui pourraient aussi faire le même office (en se servant du point précédent ET du point suivant). A suivre : une fonction curve qui fait tout "à la" Bresenham, avec antialiasing, tant qu'à faire.
MAJ: J'ai refait la fonction curve, en fonction des tangeantes disponibles, et la fonction de suivi du mouvement de la souris correspondante.
Code : Tout sélectionner
;
; ------------------------------------------------------------
;
; PureBasic - Drawing following mouse movement (curve approximation)
; by djes@free.fr
;
; (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)
; /* draw 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
;-------------------------------------------
; 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 = #Black)
;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 = #Black)
CompilerIf #DebugLevel = 2
LineXY(x1, y1, x2, y2, #Black)
Line(x1-4, y1, 8, 1, #Blue)
Line(x1, y1-4, 1, 8, #Blue)
Line(x2-4, y2, 8, 1, #Green)
Line(x2, y2-4, 1, 8, #Green)
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, #Black)
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 = #Black)
;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, #Red)
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, #Red)
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, #Red)
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, #Red)
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, #Red)
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, #Red)
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, #Red)
FirstElement(Coords()) : DeleteElement(Coords(), 1)
n = ListSize(Coords()) ;Continue processing
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
Wend
UnlockMutex(Mutex)
StopDrawing()
EndIf
Wend
EndProcedure
;---- Main
CreateThread(@MouseMovementFollow(), 0)
; Ouverture de la fenêtre
OpenWindow(0, 0, 0, 800, 600, "Souris - Cliquer et utiliser la molette...",#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
; Molette de la souris = Rotation du curseur
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
;plotCubicBezierSegAA(x, y, 400, 200, 400, 300, 400, 400, $FF)
;x1 = 200 : y1 = 200 : Plot(x1, y1, #Blue)
;x2 = 200 : y2 = 250 : Plot(x2, y2, #Blue)
;x3 = 350 : y3 = 250 : Plot(x3, y3, #Blue)
;x4 = 400 : y4 = 250 : Plot(x4, y4, #Blue)
;CurveStart(x1, y1, x2, y2, x, y, #Red)
;CurveMiddle(x, y, x2, y2, x3, y3, x4, y4, #Red)
;CurveEnd(x, y, x2, y2, x3, y3, #Red)
DrawText(0,5, "X=" + Str(x) + " Y=" + Str(y) + " " )
If lmb
DrawText(0,30, "Bouton Gauche", RGB(255,0,0),RGB(255,255,0))
Else
DrawText(0,30, "Bouton Gauche", RGB(255,255,255))
EndIf
If mmb
DrawText(150,30, "Bouton Central", RGB(255,0,0),RGB(255,255,0))
Else
DrawText(150,30, "Bouton Central", RGB(255,255,255))
EndIf
If rmb
DrawText(300,30, "Bouton Droit", RGB(255,0,0),RGB(255,255,0))
Else
DrawText(300,30, "Bouton Droit", RGB(255,255,255))
EndIf
If tiks <> 0
DrawText(450,30, "Molette", RGB(255,0,0),RGB(255,255,0))
Else
DrawText(450,30, "Molette", RGB(255,255,255))
EndIf
StopDrawing()
ForEver
End
End ; All the opened windows are closed automatically by PureBasic