Here is a new "test" I've made for optimisation. it's not finished at all, but it's speeder than the actual version of animatoon.
I can easily draw on a 3000*3000 image without matter of speed .
I have add a zoom option which works fine I think.
I have to optimise still , for example, to add :
- tile technic for image layer
- only draw the width/height of the canvas, not the complete image (for exemple, by default 3000*3000, I could only draw about 1200* 800 for example)
- merge all layer for preview when moving the canvas (shortcut = space)
I have add a new brush editing test, which is interesting I think ^^.
Code: Select all
; Blendman 07/2012 - pb 4.61
; Test for Animatoon, my 2D painting and animation software
; help by Falsam (2011) (keyboard event with canvas)
;{ constante, enum
#windowMain = 0
#statusbar =0
#toolbar = 0
Enumeration ; Gadget
#canvas
#canvasRulersTop
#canvasRulersLeft
; panel brush
#panel_brush
#ImageColor
; brush parameters
#Gad_BrushSize
#Gad_BrushSizeTB
#Gad_BrushAlpha
#Gad_BrushAlphaTB
#Gad_BrushTool
#Gad_BrushPreview
#Gad_BrushPas
#Gad_BrushRotationRnd
#Gad_BrushRotation
; for the circle custom brush tool
#Gadget_FrCustomBrush
#Gadget_GradientX
#Gadget_GradientX2
#Gadget_GradientX3
#Gadget_AlphaGradientX
#Gadget_AlphaGradientX2
#Gadget_AlphaGradientX3
; panel Layer
#panel_Layer
#gadget_TGLayer
#gadget_btnAddLayer
#gadget_TB_LayerAlpha
; animation
#gadget_AnimPreview
#gadget_LayerAnim
EndEnumeration
Enumeration ;image
#image_brush
#image_brushCopy
#img_brushPreview
#img_final
#img_Copy
#img_Color
EndEnumeration
;{ menu
#menu = 0
Enumeration
#menu_open
#menu_new
#menu_File_SaveLayer
#menu_exit
#menu_Edit_Clear
#menu_Image_SizeImage
#menu_Image_Document
#menu_WinAnimProp
#menu_Help_About
EndEnumeration
;}
;}
;{ structures & variables
Structure StLayer
x.w : y.w : img.l : imgcopy.l : name$ : pos.a : visible.a : alpha.a : selected.a : locked.a
EndStructure
Global NewList layer.StLayer()
Structure StDoc
LayerActif.l : LayerCopyActif.l : h.w : w.w : zoom.w
EndStructure
Global doc.stdoc
doc\w = 3000 : doc\h = 3000 : doc\zoom = 100
Structure StBrush
x.w : y.w : alpha.a : size.w : color.l : tool.a : pas.u
gradientX.d : gradientX2.d : gradientX3.d
alphaGradientX.a : alphaGradientX2.a : alphaGradientX3.a
EndStructure
Global brush.stbrush
Global scrollw,scrollh,MouseX_Old,MouseY_Old,canvas_x,canvas_y
;{ brush parameters
With brush
\alpha = 255
\color = RGBA(0,0,0,brush\alpha)
\size = 50
\gradientX = 0.1
\gradientX2 = 0.1
\gradientX3 = 0.5
\alphaGradientX = 255
\alphaGradientX2 = 0
\alphaGradientX3 = 125
\pas = 5
EndWith
;}
;}
;{ procedures
Macro point_distance(x1,y1,x2,y2)
Int(Sqr((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)))
EndMacro
Macro point_direction(x1,y1,x2,y2)
ATan2((y2- y1),(x2- x1))
EndMacro
Procedure UpdateScreen(x=0,y=0)
If StartDrawing(CanvasOutput(#canvas))
Box(0,0,doc\w,doc\h,RGBA(200,200,200,255))
Box(x,y,doc\w* doc\zoom/100,doc\h*doc\zoom/100,RGBA(255,255,255,255))
DrawingMode(#PB_2DDrawing_AlphaBlend)
ForEach layer()
With layer()
If layer()\visible
DrawAlphaImage(ImageID(\imgcopy),x,y, layer()\alpha)
EndIf
EndWith
Next
StopDrawing()
EndIf
EndProcedure
; layer
Procedure UpdateLayerUi()
ClearGadgetItems(#gadget_TGLayer)
ForEach layer()
AddGadgetItem(#gadget_TGLayer,layer()\pos-1,layer()\name$)
SetGadgetItemState(#gadget_TGLayer,layer()\pos-1,#PB_Tree_Checked)
Next
EndProcedure
Procedure AddLayer()
AddElement(layer())
With layer()
\img = CreateImage(#PB_Any,doc\w,doc\h,32|#PB_Image_Transparent)
\imgcopy =CopyImage(\img,#PB_Any)
\pos = ListSize(layer())
doc\LayerActif = \img
doc\LayerCopyActif = \imgcopy
\name$ = "Layer"+Str(ListSize(layer()))
\alpha = 255
\visible = 1
EndWith
UpdateLayerUi()
EndProcedure
; brush
Procedure DrawBrush(x1,y1)
Define.d paspos,x_result,y_result
Shared distTotal,x3,y3
x2 = MouseX_Old - canvas_x
y2 = MouseY_Old - canvas_y
dist = point_distance(x1,y1,x2,y2) ; to find the distance between two brush dots
d.d = point_direction(x1,y1,x2,y2) ; to find the direction between the two brush dots
sinD.d = Sin(d)
cosD.d = Cos(d)
b = brush\size*brush\pas/100
For u = 0 To dist -2
u + b
x_result = x1 + sinD * u ;+ rndX
y_result = y1 + cosD * u ;+ rndY
DrawAlphaImage(ImageID(#image_brushCopy),x_result-(brush\size/2)*doc\zoom/100,y_result-(brush\size/2)*doc\zoom/100)
Next
; other methode, don't work :(
; distTotal + dist
; nb = Round(distTotal/(brush\size * brush\pas/100),0)
;
; If nb >0
;
; b = (brush\size* brush\pas/100)
;
; distTotal - nb * b
;
; For u = 0 To nb-1
;
; x_result = x1 + sinD * u ;+ rndX
; y_result = y1 + cosD * u ;+ rndY
; DrawAlphaImage(ImageID(#image_brushCopy),x_result-(brush\size/2)*doc\zoom/100,y_result-(brush\size/2)*doc\zoom/100)
; ;Round(brush\size*(brush\pas/100),0);*doc\zoom/100
; Next
;
; EndIf
;
EndProcedure
Procedure DrawBrushFinal(x1,y1)
Define.d paspos,x_result,y_result
Shared distTotal,x3,y3
x2 = MouseX_Old - canvas_x
y2 = MouseY_Old - canvas_y
dist = point_distance(x1,y1,x2,y2) ; to find the distance between two brush dots
d.d = point_direction(x1,y1,x2,y2) ; to find the direction between the two brush dots
sinD.d = Sin(d)
cosD.d = Cos(d)
b = brush\size*brush\pas/100
For u = 0 To dist -2
u + b
x_result = x1 + sinD * u ;+ rndX
y_result = y1 + cosD * u ;+ rndY
DrawAlphaImage(ImageID(#image_brush),x_result*100/doc\zoom-brush\size/2,y_result*100/doc\zoom-brush\size/2)
Next
EndProcedure
Procedure UpdateBrushPreview()
tempimg = CopyImage(#image_brush,#PB_Any)
ResizeImage(tempimg,60,60)
If StartDrawing(ImageOutput(#img_brushPreview))
Box(0,0,60,60,RGB(255,255,255))
DrawAlphaImage(ImageID(tempimg),0,0)
StopDrawing()
EndIf
FreeImage(tempimg)
SetGadgetState(#Gad_BrushPreview,ImageID(#img_brushPreview))
EndProcedure
Procedure CreateBrush()
If IsImage(#image_brush)
FreeImage(#image_brush)
EndIf
If IsImage(#image_brushCopy)
FreeImage(#image_brushCopy)
EndIf
If CreateImage(#image_brush,brush\size,brush\size,32|#PB_Image_Transparent)
If StartDrawing(ImageOutput(#image_brush))
DrawingMode(#PB_2DDrawing_AlphaBlend)
If brush\tool = 0 ; circle hard
Circle(brush\size/2,brush\size/2,brush\size/2-1,brush\color)
ElseIf brush\tool = 1 ; circle shine
DrawingMode(#PB_2DDrawing_Gradient|#PB_2DDrawing_AllChannels)
BackColor (brush\color)
FrontColor(RGBA(0,0,0,0))
EllipticalGradient(brush\size/3,brush\size/3, brush\size,brush\size)
Circle(brush\size/2,brush\size/2,brush\size/2-1)
ElseIf brush\tool = 2 ; circle soft
DrawingMode(#PB_2DDrawing_Gradient|#PB_2DDrawing_AllChannels)
BackColor (brush\color)
FrontColor(RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),0))
EllipticalGradient(brush\size/2,brush\size/2, brush\size/2,brush\size/2)
Circle(brush\size/2,brush\size/2,brush\size/2-1)
ElseIf brush\tool = 3 ; circle custom brush
DrawingMode(#PB_2DDrawing_Gradient|#PB_2DDrawing_AlphaBlend)
BackColor(RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alphaGradientX))
GradientColor(brush\gradientX, RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alphaGradientX))
GradientColor(brush\gradientX3,RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alphaGradientX3))
GradientColor(brush\gradientX2,RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alphaGradientX2))
FrontColor(RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha))
CircularGradient(brush\size/2, brush\size/2, brush\size-1)
Circle(brush\size/2,brush\size/2,brush\size/2-1)
EndIf
StopDrawing()
EndIf
CopyImage(#image_brush,#image_brushCopy)
ResizeImage(#image_brushCopy,brush\size*doc\zoom/100,brush\size*doc\zoom/100,#PB_Image_Raw)
EndIf
UpdateBrushPreview()
EndProcedure
; drawing/painting
Procedure Zoom()
If doc\zoom < 10
doc\zoom = 10
ElseIf doc\zoom > 1200
doc\zoom = 1200
EndIf
CreateBrush()
w = ImageWidth(#img_final) * doc\zoom/100
h = ImageHeight(#img_final) * doc\zoom/100
Debug Str(w)+"/"+Str(h)
If w >0 And h> 0 And w < 8000 And h <8000
; ; a test for resize the canvas with the zoom. Be carefull, it's not good.
;If doc\zoom<=100
;canvas_w = (scrollw-50) *doc\zoom/100
;canvas_h = (scrollh-50) *doc\zoom/100
;ResizeGadget(#canvas, #PB_Ignore, #PB_Ignore,canvas_w,canvas_h)
;EndIf
ForEach layer()
FreeImage(layer()\imgcopy)
layer()\imgcopy = CopyImage(layer()\img,#PB_Any)
ResizeImage(layer()\imgcopy,w,h,#PB_Image_Raw)
doc\LayerCopyActif = layer()\imgcopy
Next
UpdateScreen(canvas_x,canvas_y)
EndIf
StatusBarText(#statusbar,2,"Doc Width : "+Str(doc\w)+"/Height : "+Str(doc\h))
StatusBarText(#statusbar,1,"Zoom : "+Str(doc\zoom)+"%")
EndProcedure
Procedure paint(xx,yy)
;CreateBrush() ; When I will make change on brush dynamically (rotation, random size..)
If StartDrawing(ImageOutput(doc\LayerCopyActif))
DrawingMode(#PB_2DDrawing_AlphaBlend)
drawbrush(xx,yy)
StopDrawing()
EndIf
If StartDrawing(ImageOutput(doc\LayerActif))
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawBrushFinal(xx,yy)
StopDrawing()
EndIf
EndProcedure
; thread // not used and not finished at all , for the moment. But it could be great to use a thread to have a better fps, for the image original (not the preview)
;Procedure PaintThread(*Valeur)
; If StartDrawing(ImageOutput(doc\layeractif))
; DrawingMode(#PB_2DDrawing_AlphaBlend)
; Circle(brush\x,brush\y,brush\size,brush\color)
; StopDrawing()
; EndIf
;EndProcedure
;}
;{ images
; create the image for the layer and canvas (preview)
If CreateImage(#img_final,doc\w,doc\h,32|#PB_Image_Transparent)
EndIf
If CreateImage(#img_Copy,doc\w,doc\h,32|#PB_Image_Transparent)
EndIf
;CreateThread(@PaintThread(), 23)
;}
;{ open window
If ExamineDesktops()
winW = DesktopWidth(0)
winH = DesktopHeight(0)
Else
winW = 1024
winh = 768
EndIf
If UsePNGImageDecoder() And UsePNGImageEncoder() : EndIf
If OpenWindow(#windowMain, 0, 0, winw, winH, "Animatoon- Brush test", #PB_Window_SystemMenu|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered|#PB_Window_Maximize) =0
End
EndIf
SmartWindowRefresh(#windowMain,1) ; needed ?
;{ menu
CreateImageMenu(#menu,WindowID(#windowMain),#PB_Menu_ModernLook)
MenuTitle("File")
MenuItem(#menu_open, "Open")
MenuItem(#menu_New, "New")
MenuBar()
MenuItem(#menu_File_SaveLayer, "Save Layer As PNG")
MenuBar()
MenuItem(#menu_exit, "Exit"+Chr(9)+"Escape")
MenuTitle("Edition")
MenuItem(#menu_Edit_Clear, "Clear Layer"+Chr(9)+"Ctrl+X")
MenuTitle("Images")
MenuItem(#menu_Image_SizeImage, "Size Image")
MenuItem(#menu_Image_Document, "Size Document")
MenuTitle("Window")
MenuItem(#menu_WinAnimProp, "Animation properties")
MenuTitle("Help")
MenuItem(#menu_Help_About, "About")
;}
;{ toolbar
CreateToolBar(#toolbar, WindowID(0))
;}
;{ statusbar
CreateStatusBar(#statusbar,WindowID(#windowMain))
AddStatusBarField(100)
AddStatusBarField(200)
AddStatusBarField(200)
StatusBarText(#statusbar,2,"Doc Width : "+Str(doc\w)+"/Height : "+Str(doc\h))
StatusBarText(#statusbar,1,"Zoom : "+Str(doc\zoom)+"%")
;}
;{ gadgets
h = ToolBarHeight(#toolbar) + 10
PanelRight = 200
Panelleft = 200
PanelAnimationH = 150
scrollw = winw - PanelRight - Panelleft
scrollh = winh-90-h-StatusBarHeight(#statusbar)-PanelAnimationH
;Debug Str(scrollw)+"/"+Str(scrollh)
If CanvasGadget(#canvas, Panelleft+10, h, scrollw-20, scrollh, #PB_Canvas_Keyboard|#PB_Canvas_Border)
SetGadgetAttribute(#canvas,#PB_Canvas_Cursor,#PB_Cursor_Cross)
EndIf
;{ panel brush
If CreateImage(#img_Color,48,48)
EndIf
If PanelGadget(#panel_brush,5,h,Panelleft-10,scrollh)
AddGadgetItem(#panel_brush,-1,"Brush")
SpinGadget(#Gad_BrushSize,15,5,40,20,1,1000,#PB_Spin_Numeric)
SetGadgetState(#Gad_BrushSize,brush\size)
TrackBarGadget(#Gad_BrushSizeTB, 60,5,100,20,1,1000)
SetGadgetState(#Gad_BrushSizeTB,brush\size)
GadgetToolTip(#Gad_BrushSize,"Size of the brush")
SpinGadget(#Gad_BrushAlpha,15,30,40,20,0,255,#PB_Spin_Numeric)
SetGadgetState(#Gad_BrushAlpha,brush\alpha)
TrackBarGadget(#Gad_BrushAlphaTB,60,30,100,20,0,255)
SetGadgetState(#Gad_BrushAlphaTB,brush\alpha)
GadgetToolTip(#Gad_BrushAlpha,"Alpha of the brush")
; brush
ComboBoxGadget(#Gad_BrushTool,15,60,100,20)
AddGadgetItem(#Gad_BrushTool,-1,"Circle Hard")
AddGadgetItem(#Gad_BrushTool,-1,"Circle Shine")
AddGadgetItem(#Gad_BrushTool,-1,"Circle Soft")
AddGadgetItem(#Gad_BrushTool,-1,"Circle Custom")
SetGadgetState(#Gad_BrushTool,brush\tool)
GadgetToolTip(#Gad_BrushTool,"Brush Tool")
SpinGadget(#Gad_BrushPas,120,60,35,20,0,1000,#PB_Spin_Numeric)
SetGadgetState(#Gad_BrushPas,brush\pas)
GadgetToolTip(#Gad_BrushPas,"Spacing")
x = 20 : y = 90
Frame3DGadget(#Gadget_FrCustomBrush,5, y,160,x*8,"Circle Custom")
TrackBarGadget(#Gadget_GradientX,10,y+x,150,20,0,100)
SetGadgetState(#Gadget_GradientX,brush\gradientX *100)
TrackBarGadget(#Gadget_GradientX2,10,y+x*2,150,20,0,100)
SetGadgetState(#Gadget_GradientX2,brush\gradientX2 *100)
TrackBarGadget(#Gadget_GradientX3,10,y+x*3,150,20,0,100)
SetGadgetState(#Gadget_GradientX3,brush\gradientX3 *100)
TrackBarGadget(#Gadget_AlphaGradientX,10,y+x*4,150,20,0,255)
SetGadgetState(#Gadget_AlphaGradientX,brush\alphaGradientX)
TrackBarGadget(#Gadget_AlphaGradientX2,10,y+x*5,150,20,0,255)
SetGadgetState(#Gadget_AlphaGradientX2,brush\alphaGradientX2)
TrackBarGadget(#Gadget_AlphaGradientX3,10,y+x*6,150,20,0,255)
SetGadgetState(#Gadget_AlphaGradientX3,brush\alphaGradientX3)
;#Gad_BrushRotationRnd
;#Gad_BrushRotation
y = 90 + x*8 + 50
If CreateImage(#img_brushPreview,60,60)
ImageGadget(#Gad_BrushPreview, 15, y, 60, 60, ImageID(#img_brushPreview),#PB_Image_Border)
EndIf
; the image for the brush
CreateBrush()
ImageGadget(#ImageColor, 20, 450, 48, 48, ImageID(#img_Color),#PB_Image_Border)
AddGadgetItem(#panel_brush,-1,"Dyn")
CloseGadgetList()
EndIf
;}
;{ panel layer
If PanelGadget(#panel_Layer,winw-PanelRight+10,h,PanelRight-10,scrollh)
AddGadgetItem(#panel_Layer,-1,"Layer")
h1 = 50
TrackBarGadget(#gadget_TB_LayerAlpha,10,10,100,20,0,255)
TreeGadget(#gadget_TGLayer, 10,h1,PanelRight-40,scrollh-150-h1,#PB_Tree_CheckBoxes )
AddLayer()
ButtonGadget(#gadget_btnAddLayer,10,scrollh-120,60,20,"Add Layer")
CloseGadgetList()
EndIf
;}
;{ animation
h2 = winH -h - GadgetHeight(#panel_brush) - StatusBarHeight(#statusbar)-5 - 90
btn_h = 30
y = h+GadgetHeight(#panel_brush)+5+btn_h
If ScrollAreaGadget(#gadget_LayerAnim,5,y,Panelleft-10,h2-btn_h,Panelleft-50,h2-30-btn_h)
CloseGadgetList()
EndIf
If ScrollAreaGadget(#gadget_AnimPreview,Panelleft+5,y,scrollw,h2-btn_h,scrollw-50,h2-30-btn_h)
CloseGadgetList()
EndIf
;}
SetActiveGadget(#canvas)
;}
;{ shortcuts
AddKeyboardShortcut(#windowMain,#PB_Shortcut_Escape,#menu_exit)
AddKeyboardShortcut(#windowMain,#PB_Shortcut_X|#PB_Shortcut_Control,#menu_Edit_Clear)
;}
UpdateScreen()
;}
Repeat
event = WaitWindowEvent()
Select event
Case #PB_Event_Menu
Select EventMenu()
Case #menu_File_SaveLayer
file$= SaveFileRequester("","","PNG image|*.PNG;*.png",0)
If file$
SaveImage(#img_final,RemoveString(file$,"*.png")+".png",#PB_ImagePlugin_PNG)
EndIf
Case #menu_exit
End
Case #menu_Edit_Clear
If StartDrawing(ImageOutput(doc\LayerActif))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0,0,doc\w,doc\h,RGBA(0,0,0,0))
StopDrawing()
EndIf
If StartDrawing(ImageOutput(doc\LayerCopyActif))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0,0,doc\w,doc\h,RGBA(0,0,0,0))
StopDrawing()
EndIf
UpdateScreen(canvas_x,canvas_y)
Case #menu_Image_Document
w = Val(InputRequester("Width","Width of the document",Str(doc\w)))
h = Val(InputRequester("Height","Height of the document",Str(doc\h)))
If w >0
doc\w =w
ok = 1
EndIf
If h >0
doc\h =h
ok = 1
EndIf
If ok = 1
ok = 0
tempimg = CreateImage(#PB_Any,doc\w,doc\h,32|#PB_Image_Transparent)
If StartDrawing(ImageOutput(tempimg))
DrawAlphaImage(ImageID(#img_final),0,0)
StopDrawing()
EndIf
CopyImage(tempimg,#img_final)
w = ImageWidth(#img_Copy)
h = ImageHeight(#img_Copy)
CopyImage(#img_final,#img_Copy)
ResizeImage(#img_Copy,w,h,#PB_Image_Raw)
FreeImage(tempimg)
EndIf
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #canvas
Select EventType()
Case #PB_EventType_LeftButtonDown
paint = 1
If move_canvas = 0
xx= GetGadgetAttribute(#canvas,#PB_Canvas_MouseX)
yy= GetGadgetAttribute(#canvas,#PB_Canvas_MouseY)
brush\x = xx
brush\y = yy
startx = xx
starty = yy
MouseX_Old = xx
MouseY_Old = yy
paint((xx-canvas_x),(yy - canvas_y))
UpdateScreen(canvas_x,canvas_y)
EndIf
Case #PB_EventType_LeftButtonUp
paint = 0
Case #PB_EventType_MouseMove
xx= GetGadgetAttribute(#canvas,#PB_Canvas_MouseX)
yy= GetGadgetAttribute(#canvas,#PB_Canvas_MouseY)
If move_canvas = 0
If paint = 1
paint((xx-canvas_x),(yy - canvas_y))
MouseX_Old = xx
MouseY_Old = yy
UpdateScreen(canvas_x,canvas_y)
EndIf
Else ; on bouge le canvas
canvas_x = cx + xx - startx
canvas_y = cy + yy - starty
UpdateScreen(canvas_x,canvas_y)
EndIf
Case #PB_EventType_KeyDown
If keypressed = 0
Debug "Key Down" + Str(GetGadgetAttribute(#canvas,#PB_Canvas_Key ))
keypressed = 1
Select GetGadgetAttribute(#canvas,#PB_Canvas_Key )
Case 32 ; space
SetGadgetAttribute(#canvas,#PB_Canvas_Cursor,#PB_Cursor_Hand)
move_canvas = 1
xx= GetGadgetAttribute(#canvas,#PB_Canvas_MouseX)
yy= GetGadgetAttribute(#canvas,#PB_Canvas_MouseY)
startx = xx
starty = yy
Case 107; zoom +
doc\zoom + 10
Zoom()
Case 109; zoom-
doc\zoom - 10
Zoom()
EndSelect
EndIf
Case #PB_EventType_KeyUp
keypressed = 0
Select GetGadgetAttribute(#canvas,#PB_Canvas_Key )
Case 32 ; space
SetGadgetAttribute(#canvas,#PB_Canvas_Cursor,#PB_Cursor_Cross)
move_canvas = 0
cx + xx - startx
cy + yy - starty
EndSelect
Case #PB_EventType_MouseWheel
If ImageWidth(#img_final) * (doc\zoom+10)/100< 8000 And ImageHeight(#img_final) * (doc\zoom+10)/100 < 8000 And doc\zoom>10
doc\zoom + GetGadgetAttribute(#canvas, #PB_Canvas_WheelDelta)*10
Zoom()
Else
If GetGadgetAttribute(#canvas, #PB_Canvas_WheelDelta)<0
doc\zoom -10
Zoom()
EndIf
EndIf
EndSelect
;{ others gadgets
Case #ImageColor
col = ColorRequester(brush\color)
brush\color = RGBA(Red(col),Green(col),Blue(col),brush\alpha)
If StartDrawing(ImageOutput(#img_Color))
Box(0,0,80,80,brush\color)
StopDrawing()
EndIf
SetGadgetState(#imagecolor,ImageID(#img_Color))
CreateBrush()
SetActiveGadget(#canvas)
Case #gadget_btnAddLayer
AddLayer()
Case #gadget_TGLayer
pos = GetGadgetState(#gadget_TGLayer)+1
ForEach layer()
layer()\selected = 0
Next
ForEach layer()
If layer()\pos = pos
doc\LayerActif =layer()\img
doc\LayerCopyActif =layer()\imgcopy
layer()\selected = 1
SetGadgetState(#gadget_TB_LayerAlpha,layer()\alpha);
Break
EndIf
Next
If EventType() = #PB_EventType_LeftDoubleClick
name$ = InputRequester("Animatoon","Name of the Layer",layer()\name$)
If name$ <>""
layer()\name$ = name$
EndIf
UpdateLayerUi()
Else
visible = GetGadgetItemState(#gadget_TGLayer,pos-1)
If visible & #PB_Tree_Checked
layer()\visible = 1
UpdateScreen(canvas_x,canvas_y)
Else
layer()\visible = 0
UpdateScreen(canvas_x,canvas_y)
EndIf
EndIf
Case #gadget_TB_LayerAlpha
ForEach layer()
If layer()\selected = 1
layer()\alpha = GetGadgetState(#gadget_TB_LayerAlpha)
Break
EndIf
Next
UpdateScreen(canvas_x,canvas_y)
;}
;{ brush editing
Case #Gad_BrushPas
brush\pas = GetGadgetState(#Gad_BrushPas)
Case #Gad_BrushSize,#Gad_BrushSizeTB
brush\size = GetGadgetState(EventGadget())
SetGadgetState(#Gad_BrushSize,brush\size)
SetGadgetState(#Gad_BrushSizeTB,brush\size)
CreateBrush()
Case #Gad_BrushAlpha,#Gad_BrushAlphaTB
brush\alpha = GetGadgetState(EventGadget())
SetGadgetState(#Gad_BrushAlpha,brush\alpha)
SetGadgetState(#Gad_BrushAlphaTB,brush\alpha)
brush\color = RGBA(Red(col),Green(col),Blue(col),brush\alpha)
CreateBrush()
Case #Gad_BrushTool
brush\tool = GetGadgetState(#Gad_BrushTool)
brush\color = RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha)
createbrush()
Case #Gadget_GradientX
brush\gradientX= GetGadgetState(#Gadget_GradientX)/100
brush\color = RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha)
createbrush()
Case #Gadget_GradientX2
brush\gradientX2 = GetGadgetState(#Gadget_GradientX2)/100
brush\color = RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha)
createbrush()
Case #Gadget_GradientX3
brush\gradientX3 = GetGadgetState(#Gadget_GradientX3)/100
brush\color = RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha)
createbrush()
Case #Gadget_AlphaGradientX
brush\alphaGradientX = GetGadgetState(#Gadget_AlphaGradientX)
brush\color = RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha)
createbrush()
Case #Gadget_AlphaGradientX2
brush\alphaGradientX2 = GetGadgetState(#Gadget_AlphaGradientX2)
brush\color = RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha)
createbrush()
Case #Gadget_AlphaGradientX3
brush\alphaGradientX3 = GetGadgetState(#Gadget_AlphaGradientX3)
brush\color = RGBA(Red(brush\color),Green(brush\color),Blue(brush\color),brush\alpha)
createbrush()
;}
Default
SetActiveGadget(#canvas)
EndSelect
Case #PB_Event_CloseWindow
End
EndSelect
ForEver
Hi Marc .marc_256 wrote:For my CAD/CAM/CAE program I use only the 'canvasgadget'
it is very versatile in its use.
And you can draw all objects directly on it.
First you can draw on some images, and then draw all the images on the canvasgadget.
I use a lot the canvasgadget. It's a great and excellent gadget !
We can do everything with it.
I do the methode than you describe, but it needs to be optimised, because with big image and a few layer, it's slow.
Thankskenmo wrote:This looks very cool! I will try it out.
Thanks, I know Luis rotation and Djes/LSI rotation .IdeasVacuum wrote:Luis coded a cross platform Rotate (and Mirror/Flip). It works very well: http://www.purebasic.fr/english/viewtop ... 12&t=38975
I will try Luis Solution for rotate the canvas.
HiDanilo wrote:Very nice start for a painting application (do you know Corel Painter, Project Dogwaffle Digital Painter Pro 5 (or Howler / Project Broomhead), ArtRage Studio Pro?).
I know a lot of the applications .
I have tested :
- painter demo (11)/paint it/sketch pad/paint shop pro/paint essential, toonboom, Dogwaffle, tv animation (demo), twisted brush, paint tool SAi,
I use ((I've got a licence, or it's a freeware) :
- photoshop , painter (classic), artweaver, artrage, mypaint, gimp, pencil, synfig, inkscape, Qaquarelle, serfi photoplus SE...
I haven't find a software (free or cheap) with w<hich I have the tools for painting and do animation (with interesting fonctions lfor animation).
So I'm trying to do it ^^.
It's Ok in the next version.- I would like image previews for the brushes (instead names only), there are too many brushes to remember names.
It's a swatch. It's not finished. For the moment, it's not working.- What is the "Nuancier" palette for? It does not work here if i select a color in this palette.
I would like to add support Tablet for Window/linux/mac if possible, but I don't know how I can do that- Will you add support for Win8 Surface Pro tablets with pen input?
I have try 2 codes from that, but I have some "bugs" with it. When I "clic" on the menu, the drawing after that is very strange.
here is one of the test (from blueznl) :
Code: Select all
;{ Infos
; purebasic survival guide
; touch_tablet - 11.11.2003 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/pure1.htm
;
; - using a touch tablet in purebasic
; - references to pages / tables refer to a word document by lcs/telegraphics:
;
; wintab interface specification 1.0
; 16- and 32-bit api reference by Rick Poyner
; revised december 13, 1994
;
; - use google, the doc above is NOT part of the wintab sdk (duh!) but is on their site
; - to do: disable tablet context when window is not in focus
; - to do: handle pen vs. lmb issues (pen can generate lmb message at pressure 0, timing is all...)
; - to do: tilt detection (wacom) etc.
; Modified by Blendman : 2012 - pb 4.61
; - add a canvas
; - add a menu mode (tablette, mouse)
; - test to draw on a screen /sprite
;}
;{ constantes
#screenOutput = 0; to use the screen instead of the canvas
#windowMain = 0
Enumeration ; Tool
#Toolline
#ToolCircle
#ToolBrush
#ToolBrushLine
EndEnumeration
Enumeration ; Gadget
#canvas
#ImageBrush
#brush_radius
#brush_alpha
#brush_color
#brush_tool
#brush_pas
#brush_pressure
EndEnumeration
#WM_MOUSELEAVE = $2A3
;
;{ wintab constants
; device configuration constants (ch5.7.1 p21)
;
#WTDC_NONE = 0
#WTDC_CANCEL = 1
#WTDC_OK = 2
#WTDC_RESTART = 3
;
; message constants (ch6 p34)
;
#WT_DEFBASE = $7FF0
#WT_MAXOFFSET = $F
#WT_MAX = $7FFF ; aka wt_defbase + wt_maxoffset
Enumeration #WT_DEFBASE
#WT_PACKET
#WT_CTXOPEN
#WT_CTXCLOSE
#WT_CTXUPDATE
#WT_CTXOVERLAP
#WT_PROXIMITY
#WT_INFOCHANGE
#WT_CSRCHANGE
EndEnumeration
;
; packet constants (t7.1 p38)
;
#PK_CONTEXT = $1 ; context
#PK_STATUS = $2 ; status bits
#PK_TIME = $4 ; time stamp
#PK_CHANGED = $8 ; change bit vector
#PK_SERIAL_NUMBER = $10 ; packet serial number
#PK_CURSOR = $20 ; reporting cursor
#PK_BUTTONS = $40 ; button information
#PK_X = $80 ; x-axis
#PK_Y = $100 ; y-axis
#PK_Z = $200 ; z-axis
#PK_NORMAL_PRESSURE = $400 ; normal or tip pressure
#PK_TANGENT_PRESSURE = $800 ; tangential or barrel pressure
#PK_ORIENTATION = $1000 ; orientation info / tilts
#PK_ROTATION = $2000
;
; unit specifiers (t7.2)
;
#TU_NONE = 0
#TU_INCHES = 1
#TU_CENTIMETERS = 2
#TU_CIRCLE = 3
;
; wti category definitions (t7.3)
;
#WTI_INTERFACE = 1
#WTI_STATUS = 2
#WTI_DEFCONTEXT = 3
#WTI_DEFSYSCTX = 4
#WTI_DEVICES = 100
#WTI_CURSORS = 200
#WTI_EXTENSIONS = 300
#WTI_DDCTXS = 400
#WTI_DSCTXS = 500
;
; wti_interface index definitions (t7.4)
;
#IFC_WINTABID = 1
#IFC_SPECVERSION = 2
#IFC_IMPLVERSION = 3
#IFC_NDEVICES = 4
#IFC_NCURSORS = 5
#IFC_NCONTEXTS = 6
#IFC_CTXOPTIONS = 7
#IFC_CTXSAVESIZE = 8
#IFC_NEXTENSIONS = 9
#IFC_NMANAGERS = 10
#IFC_MAX = 10
;
; wti_status index definitions (t7.5)
;
#STA_CONTEXTS = 1
#STA_SYSCTXS = 2
#STA_PKTRATE = 3
#STA_PKTDATA = 4
#STA_MANAGERS = 5
#STA_SYSTEM = 6
#STA_BUTTONUSE = 7
#STA_SYSBTNUSE = 8
#STA_MAX = 8
;
; wti_defcontext / wti_defsysctx index definitions (t7.6)
;
#CTX_NAME = 1
#CTX_OPTIONS = 2
#CTX_STATUS = 3
#CTX_LOCKS = 4
#CTX_MSGBASE = 5
#CTX_DEVICE = 6
#CTX_PKTRATE = 7
#CTX_PKTDATA = 8
#CTX_PKTMODE = 9
#CTX_MOVEMASK = 10
#CTX_BTNDNMASK = 11
#CTX_BTNUPMASK = 12
#CTX_INORGX = 13
#CTX_INORGY = 14
#CTX_INORGZ = 15
#CTX_INEXTX = 16
#CTX_INEXTY = 17
#CTX_INEXTZ = 18
#CTX_OUTORGX = 19
#CTX_OUTORGY = 20
#CTX_OUTORGZ = 21
#CTX_OUTEXTX = 22
#CTX_OUTEXTY = 23
#CTX_OUTEXTZ = 24
#CTX_SENSX = 25
#CTX_SENSY = 26
#CTX_SENSZ = 27
#CTX_SYSMODE = 28
#CTX_SYSORGX = 29
#CTX_SYSORGY = 30
#CTX_SYSEXTX = 31
#CTX_SYSEXTY = 32
#CTX_SYSSENSX = 33
#CTX_SYSSENSY = 34
#CTX_MAX = 34
;
; wti_devices index definitions (t7.7)
;
#DVC_NAME = 1
#DVC_HARDWARE = 2
#DVC_NCSRTYPES = 3
#DVC_FIRSTCSR = 4
#DVC_PKTRATE = 5
#DVC_PKTDATA = 6
#DVC_PKTMODE = 7
#DVC_CSRDATA = 8
#DVC_XMARGIN = 9
#DVC_YMARGIN = 10
#DVC_ZMARGIN = 11
#DVC_X = 12
#DVC_Y = 13
#DVC_Z = 14
#DVC_NPRESSURE = 15
#DVC_TPRESSURE = 16
#DVC_ORIENTATION = 17
#DVC_ROTATION = 18
#DVC_PNPID = 19
#DVC_MAX = 19
;
; dvc_hardware hardware capabilities (t7.7)
;
#HWC_INTEGRATED = $1
#HWC_TOUCH = $2
#HWC_HARDPROX = $4
#HWC_PHYSID_CURSORS = $8
;
; wti_cursors (t7.8)
;
#CSR_NAME = 1
#CSR_ACTIVE = 2
#CSR_PKTDATA = 3
#CSR_BUTTONS = 4
#CSR_BUTTONBITS = 5
#CSR_BTNNAMES = 6
#CSR_BUTTONMAP = 7
#CSR_SYSBTNMAP = 8
#CSR_NPBUTTON = 9
#CSR_NPBTNMARKS = 10
#CSR_NPRESPONSE = 11
#CSR_TPBUTTON = 12
#CSR_TPBTNMARKS = 13
#CSR_TPRESPONSE = 14
#CSR_PHYSID = 15
#CSR_MODE = 16
#CSR_MINPKTDATA = 17
#CSR_MINBUTTONS = 18
#CSR_CAPABILITIES = 19
#CSR_MAX = 19
;
; wti_extensions (t7.9)
;
#EXT_NAME = 1
#EXT_TAG = 2
#EXT_MASK = 3
#EXT_SIZE = 4
#EXT_AXES = 5
#EXT_DEFAULT = 6
#EXT_DEFCONTEXT = 7
#EXT_DEFSYSCTX = 8
#EXT_CURSORS = 9
#EXT_MAX = 109
;
; system button assignment values (t7.10)
;
#SBN_NONE = $0
#SBN_LCLICK = $1
#SBN_LDBLCLICK = $2
#SBN_LDRAG = $3
#SBN_RCLICK = $4
#SBN_RDBLCLICK = $5
#SBN_RDRAG = $6
#SBN_MCLICK = $7
#SBN_MDBLCLICK = $8
#SBN_MDRAG = $9
;
; pen windows assignments (t7.10)
;
#SBN_PTCLICK = $10
#SBN_PTDBLCLICK = $20
#SBN_PTDRAG = $30
#SBN_PNCLICK = $40
#SBN_PNDBLCLICK = $50
#SBN_PNDRAG = $60
#SBN_P1CLICK = $70
#SBN_P1DBLCLICK = $80
#SBN_P1DRAG = $90
#SBN_P2CLICK = $A0
#SBN_P2DBLCLICK = $B0
#SBN_P2DRAG = $C0
#SBN_P3CLICK = $D0
#SBN_P3DBLCLICK = $E0
#SBN_P3DRAG = $F0
;
; context option values (t7.11)
;
#CXO_SYSTEM = $1
#CXO_PEN = $2
#CXO_MESSAGES = $4
#CXO_MARGIN = $8000
#CXO_MGNINSIDE = $4000
;
; context status values (t.12)
;
#CXS_DISABLED = $1
#CXS_OBSCURED = $2
#CXS_ONTOP = $4
;
; context lock condition values (t7.13)
;
#CXL_INSIZE = $1
#CXL_INASPECT = $2
#CXL_SENSITIVITY = $4
#CXL_MARGIN = $8
#CXL_SYSOUT = $10
;
; relative buttons (t7.13)
;
#TBN_NONE = 0
#TBN_UP = 1
#TBN_DOWN = 2
;
; packet status values (t7.14)
;
#TPS_PROXIMITY = $1
#TPS_QUEUE_ERR = $2
#TPS_MARGIN = $4
#TPS_GRAB = $8
#TPS_INVERT = $10
;
; hook constants
;
#WTH_PLAYBACK = 1
#WTH_RECORD = 2
#WTHC_GETLPLPFN = (-3)
#WTHC_LPLPFNNEXT = (-2)
#WTHC_LPFNNEXT = (-1)
#WTHC_ACTION = 0
#WTHC_GETNEXT = 1
#WTHC_SKIP = 2
;
; cursor capabilities
;
#CRC_MULTIMODE = $1
#CRC_AGGREGATE = $2
#CRC_INVERT = $4
;}
;}
;{ structures
Structure tagLOGCONTEXT ; (ch7.3.1 p47)
lcName.b[40] ; name
lcOptions.l ; options (see t7.11)
lcStatus.l ; current status (see t7.12)
lcLocks.l ; locked conditions (see t7.13)
lcMsgBase.l ; range of message numbers (see ch6)
lcDevice.l ; device
lcPktRate.l ; packet report rate in hz (n per sec)
lcPktData.l ; optional data to report (?)
lcPktMode.l ; bit per option, 1 = relative, 0 = absolute
lcMoveMask.l ; specify packet data items that generate move events
lcBtnDnMask.l ; specify buttons that generate button events
lcBtnUpMask.l ; (p48)
lcInOrgX.l ; xyz origin on input (tablet)
lcInOrgY.l
lcInOrgZ.l
lcInExtX.l ; xyz range on input (tablet)
lcInExtY.l
lcInExtZ.l
lcOutOrgX.l ; xyz origin on output (dc?)
lcOutOrgY.l
lcOutOrgZ.l
lcOutExtX.l ; xyz range on output
lcOutExtY.l
lcOutExtZ.l
lcSensX.l ; sensitivity in relative mode
lcSensY.l
lcSensZ.l
lcSysMode.l ; system cursor tracking mode (0 = absolute) (p49)
lcSysOrgX.l ; origin of screen mapping are for system cursor tracking in screen coordinates
lcSysOrgY.l
lcSysExtX.l
lcSysExtY.l
lcSysSensX.l ; system cursor relative mode sensitivity
lcSysSensY.l
EndStructure
;
Structure tagAXIS
axMin.l
axMax.l
axUnits.l
axResolution.l ; fix32, float = fix32 / 65536
EndStructure
; wanna' have a message to notify the mouse leaving the window? use the trackmouseevent_() function
; here's the structure and the constants we might need later (uncomment when needed)
;
; Structure tagTRACKMOUSEEVENT
; cbSize.l
; dwFlags.l
; hwndTrack.l
; dwHoverTime.l
; EndStructure
; #TME_LEAVE = 2
;}
;{ declaration procedure & macro
Macro point_distance(x1,y1,x2,y2)
Int(Sqr((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) )
EndMacro
Macro point_direction(x1,y1,x2,y2)
Degree(ATan2((y2-y1),(x2-x1)))
EndMacro
Macro point_direction2(x1,y1,x2,y2)
ATan2((y2- y1),(x2- x1))
EndMacro
;{ declare
Declare DrawLine(x,y,x2,y2,Color,Alpha)
Declare DrawLineBrush(x1,y1,x2,y2,Color=0,Alpha=255,size=1)
Declare DrawBrush(x1,y1,x2,y2,Color=0,Alpha=255,size=1)
;}
;}
;{ open window
; enough declarations that are not used... now, let's open a window and do some stuff
If #screenOutput = 1; to use the screen
InitSprite() : InitSprite3D()
EndIf
main_whnd.l = OpenWindow(#windowMain,0,0,800,600,"Tablet Pressure", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
;
If CreateMenu(0,WindowID(#windowMain))
MenuTitle("Mode")
MenuItem(0,"Tablet")
MenuItem(1,"Mouse")
DisableMenuItem(0,1,1)
MenuTitle("Image")
MenuItem(10,"Clear"+Chr(9)+"Ctrl+X")
EndIf
SetMenuItemState(0,0,1)
AddKeyboardShortcut(#windowMain,#PB_Shortcut_Control|#PB_Shortcut_X,10)
AddKeyboardShortcut(#windowMain,#PB_Shortcut_Control|#PB_Shortcut_R,2)
;}
;{ wintab library
wt_nr.l = 778
OpenLibrary(wt_nr,"WINTAB32.dll")
;
; the following is nice if you want to list all the stuff in a library
; (has nothing to do with this example though :-))
;
; Debug ExamineLibraryFunctions(wt_nr)
; While NextLibraryFunction()<>0
; Debug LibraryFunctionName()
; Debug LibraryFunctionAddress()
; Wend
;
; find functions in the wintab32 dll (there's a lot more but i haven't declared all)
WTInfo = GetFunction(wt_nr,"WTInfoA")
WTOpen = GetFunction(wt_nr,"WTOpenA")
WTPacketsGet = GetFunction(wt_nr,"WTPacketsGet")
WTClose = GetFunction(wt_nr,"WTClose")
;
; get size of the largest possible reply from WTInfo, can also be used to check existence of a tablet
;
; buffer_l.l = CallFunctionFast(WTInfo,0,0,0)
;
; set up a context for wt_WTOpen
;
; notes:
; still gotta' play a little with this, there are some interesting things possible
; and some things don't behave as i would expect :-(
; the context is not automatically updated after screen resizes
; as far as i can tell, this tablet / driver only supports ONE context at a time
; opening up multiple programs with tablet support does not go well
; setting up coords / corner points in the LOGCONTEXT might solve this if all programs do so (fat chance)
tablet_lc.tagLOGCONTEXT ; create context
;CallFunctionFast(WTInfo,#WTI_DEFCONTEXT,0,@tablet_lc) ; fill it with default values
CallFunctionFast(WTInfo,#WTI_DEFSYSCTX,0,@tablet_lc) ; fill it with default values
PokeS(@tablet_lc\lcName,"TEST_TABLET",39)
tablet_lc\lcOptions = tablet_lc\lcOptions | #CXO_MESSAGES ; options (see t7.11)
tablet_lc\lcMsgBase = #WT_DEFBASE ; base for message numbers (see ch6)
tablet_lc\lcPktData = #PK_X|#PK_Y|#PK_NORMAL_PRESSURE|#PK_BUTTONS ; data to report
tablet_lc\lcPktMode = 0 ; bit per option, 1 = relative, 0 = absolute
tablet_lc\lcMoveMask = tablet_lc\lcPktData ; specify packet data items that generate move events
tablet_lc\lcBtnDnMask = #SBN_LCLICK|#SBN_RCLICK|#SBN_LDBLCLICK ; specify buttons that generate button events
tablet_lc\lcBtnUpMask = tablet_lc\lcBtnDnMask ; (p48)
tablet_hctx = CallFunctionFast(WTOpen,main_whnd,@tablet_lc,1) ; open and enable it
;
Structure WT_PACKET ; (see p52) size and length of and fields in packet struct depend on options set
pkButtons.l
pkX.l
pkY.l
pkNormalPressure.l
EndStructure
packet.WT_PACKET
;}
;{ screen or canvas gadget
; parameter of the brush
color = 0
alpha =255
Radius = 1
tool = 2
Global pas =0,oldsize
SpinGadget(#brush_radius,10,5,50,20,1,200,#PB_Spin_Numeric)
GadgetToolTip(#brush_radius,"Set the Radius (circle and brush tool)")
SetGadgetState(#brush_radius,radius)
TrackBarGadget(#brush_alpha,115,5,100,20,0,255)
GadgetToolTip(#brush_alpha,"Set the Alpha")
SetGadgetState(#brush_alpha,alpha)
ComboBoxGadget(#brush_tool,220,5,100,20)
AddGadgetItem(#brush_tool,-1,"Line")
AddGadgetItem(#brush_tool,-1,"Circle")
AddGadgetItem(#brush_tool,-1,"Brush")
AddGadgetItem(#brush_tool,-1,"Brush Line")
SetGadgetState(#brush_tool,0)
SpinGadget(#brush_pas,325,5,50,20,0,100,#PB_Spin_Numeric)
GadgetToolTip(#brush_pas,"Set the pas of the brush Tool")
SetGadgetState(#brush_pas,pas)
;{ the brush editor
Global gradientX.d=0.7, gradientX2.d=0.15, gradientX3.d = 0.1
CreateImage(0,42,42,32|#PB_Image_Transparent)
Macro Update()
If StartDrawing(ImageOutput(0))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0, 0, 400, 200, RGBA(0,0,0,0))
; DrawingMode(#PB_2DDrawing_Gradient|#PB_2DDrawing_AlphaBlend)
; BackColor(RGBA(0,0,0,255))
; GradientColor(gradientX, 0)
; GradientColor(gradientX3, RGBA(0,0,0,125))
; GradientColor(gradientX2, RGBA(0,0,0,0))
; FrontColor(RGBA(0,0,0,0))
; CircularGradient(42, 42, radius)
; Box(0,0,42,42)
; Box(0,0,42,42)
DrawingMode(#PB_2DDrawing_AlphaBlend)
Circle(24,24,10,0)
StopDrawing()
EndIf
EndMacro
ImageGadget(#ImageBrush,400,0,42,42,ImageID(0),#PB_Image_Border)
Update()
SetGadgetState(#ImageBrush,ImageID(0))
;}
If #screenOutput=0
CanvasGadget(#canvas,0,50,800,600-50)
Else
;{ open screen to draw on it // don't work
If OpenWindowedScreen(WindowID(main_nr),0,0, 800, 600, 1, 0, 0)
CreateSprite(0,800,600,#PB_Sprite_Texture|#PB_Sprite_AlphaBlending)
ClearScreen(#White)
If StartDrawing(SpriteOutput(0))
Box(0,0,800,600,#White)
;Circle(50,50,10,0)
StopDrawing()
EndIf
DisplaySprite(0,0,0)
EndIf
;}
EndIf
mouselmb.l = #False
done.l = #False
;}
;{ procedure
Macro CreateTablet()
WTInfo = GetFunction(wt_nr,"WTInfoA")
WTOpen = GetFunction(wt_nr,"WTOpenA")
WTPacketsGet = GetFunction(wt_nr,"WTPacketsGet")
WTClose = GetFunction(wt_nr,"WTClose")
tablet_lc.tagLOGCONTEXT
CallFunctionFast(WTInfo,#WTI_DEFSYSCTX,0,@tablet_lc) ; fill it with default values
PokeS(@tablet_lc\lcName,"TEST_TABLET",39)
tablet_lc\lcOptions = tablet_lc\lcOptions | #CXO_MESSAGES ; options (see t7.11)
tablet_lc\lcMsgBase = #WT_DEFBASE ; base for message numbers (see ch6)
tablet_lc\lcPktData = #PK_X|#PK_Y|#PK_NORMAL_PRESSURE|#PK_BUTTONS ; data to report
tablet_lc\lcPktMode = 0 ; bit per option, 1 = relative, 0 = absolute
tablet_lc\lcMoveMask = tablet_lc\lcPktData ; specify packet data items that generate move events
tablet_lc\lcBtnDnMask = #SBN_LCLICK|#SBN_RCLICK|#SBN_LDBLCLICK ; specify buttons that generate button events
tablet_lc\lcBtnUpMask = tablet_lc\lcBtnDnMask ; (p48)
tablet_hctx = CallFunctionFast(WTOpen,main_whnd,@tablet_lc,1) ; open and enable it
packet.WT_PACKET
EndMacro
Procedure DestroyTablet()
EndProcedure
;}
;{ loop / repeat
Repeat
; processing windows messages using waitevent() instead of callback
;
Event.l = WaitWindowEvent() ; wait for an event
Window.l = EventWindow() ; on which window?
SetActiveGadget(#brush_tool)
Select Event
Case #PB_Event_Menu
; it's a bad technic, how can I do a better technic than not close and open the tablet ?
If tabletok = 1
CallFunctionFast(WTClose,tablet_hctx) ; close and destroy
tabletok = 0
EndIf
Select EventMenu()
Case 0 ; mode tablet
ModeMouse = 0
SetMenuItemState(0,0,1)
SetMenuItemState(0,1,0)
Case 1; mode mouse
ModeMouse =1
SetMenuItemState(0,0,0)
SetMenuItemState(0,1,1)
Case 10
If StartDrawing(CanvasOutput(0))
Box(0,0,800,600,#White)
StopDrawing()
EndIf
EndSelect
Case #PB_Event_Gadget
If tabletok = 0
tabletok = 1
CreateTablet()
EndIf
Select EventGadget()
Case #canvas
; canvas_ok = 1
; mousex = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseX)
; mousey = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseY)
; Type = EventType()
;
; Select EventType()
;
; Case #PB_EventType_LeftButtonDown
; mouseDown = #True
;
; Case #PB_EventType_LeftButtonUp
; If mouseDown
; mouseDown = #False
; ReleaseCapture_()
; canvas_ok = 0
; EndIf
;
; Case #PB_EventType_MouseMove
; ;If GetGadgetAttribute(#Canvas, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton
; mousex = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseX)
; mousey = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseY)
; ;EndIf
;
; EndSelect
;
Case #brush_tool
tool = GetGadgetState(#brush_tool)
Case #brush_alpha
alpha = GetGadgetState(#brush_alpha)
Case #brush_radius
Radius = GetGadgetState(#brush_radius)
Case #brush_pas
pas = GetGadgetState(#brush_pas)
EndSelect
Case #WM_KEYDOWN
event_parameter.l = EventwParam() ; undocumented / deprecated / windows only // use the canvas key to have a multiplatform
Select event_parameter ; eventwparam() gets additional info on event
Case #VK_ESCAPE
done=#True
EndSelect
Case #PB_Event_CloseWindow
done = #True
Case #WM_MOUSEMOVE
; EventwParam() contains info on variuos virtual keys
; EventlParam() contains the cursor coords
;
; the implementation of mousecoordinates is somewhat fuzzy in purebasic, they are
; reported in relation to the upper left corner of the window, not of the client area
; using the EventlParam() field an accurate position can be retrieved
If ModeMouse = 0
mousex = (EventlParam() % 65536)
mousey = (EventlParam() / 65536) ;- GadgetY(#canvas)
If mouselmb = #False
mouselmb = #True
mousex_old = mousex
mousey_old = mousey
EndIf
; mousex.l = (EventlParam() % 65536) * (1-ModeMouse) + modemouse*WindowMouseX(#windowMain)
; mousey.l = (EventlParam() / 65536) * (1-ModeMouse) + modemouse*WindowMouseY(#windowMain)
Else
; mousex = modemouse*WindowMouseX(#windowMain)
; mousey = modemouse*WindowMouseY(#windowMain)
; pressure.l = modemouse * Radius * mouselmb
EndIf
; if you want to use the build in commands, you have to compensate for the size
; of window borders etc.
;
; mousex.l = WindowMouseX()-GetSystemMetrics_(#SM_CYSIZEFRAME)
; mousey.l = WindowMouseY()-GetSystemMetrics_(#SM_CYCAPTION)-GetSystemMetrics_(#SM_CYSIZEFRAME)
;
; if you want To detect when the mouse leaves the window, you could set a TrackMouseEvent_()
;
; mouseleave.tagTRACKMOUSEEVENT
; mouseleave\cbSize = SizeOf(tagTRACKMOUSEEVENT)
; mouseleave\dwFlags = #TME_LEAVE
; mouseleave\hwndTrack = main_whnd
; TrackMouseEvent_(@mouseleave)
;
; when using SetCapture_() windows 'prefilters' messages, that is you won't receive
; messages unless another condition is met (virtual keys, mousebuttons, etc.)
; so you can't use SetCapture() to see if the cursor left the area with no button
; pressed
;
Case #WM_LBUTTONDOWN
If tabletok = 0
tabletok = 1
CreateTablet()
EndIf
; If tool = 0
mousex = (EventlParam() % 65536)
mousey = (EventlParam() / 65536)
mousex_old = mousex
mousey_old = mousey
;EndIf
;
; mouselmb = #True
; ; if a mousebutton is pressed, and the cursor is moved outside the window client area
; ; no more messages will be received, including the WM_LBUTTONUP message
; ; to make sure such a message is received grab all messages until we got what we
; ; want
;SetCapture_(main_whnd)
Case #WM_LBUTTONUP ;
mouselmb = #False ;
;ReleaseCapture_()
;
;Case #WM_MOUSELEAVE ;
;Debug "675 $2A3WM_MOUSELEAVE mouse left window (after a trackmouseevent was used)" ;
; only generated after calling TrackMouseEvent_(), see #WM_MOUSEMOVE above
;
Default ;
; all other events
If Event >= #WT_DEFBASE And Event <= #WT_MAX
CallFunctionFast(WTPacketsGet,tablet_hctx,1,@packet) ;
; there's more information that can be retrieved from the tablet, depending on type etc.
; here i only look for pressure ;
pressure.l = (packet\pkNormalPressure)
EndIf
EndSelect
;{ if screen
If #screenOutput = 1
If StartDrawing(SpriteOutput(0))
Circle(mousex+10,mousey+10,10+pressure/50,RGB(0,0,0))
StopDrawing()
EndIf
mousex_old = mousex
mousey_old = mousey
DisplaySprite(0,0,0) ;}
Else
If mousex <> mousex_old Or mousey<>mousey_old Or pressure <> pressure_old ;And (mousex >=0 And mousey >=0)
If mouselmb = #True
If StartDrawing(CanvasOutput(#canvas))
DrawingMode(#PB_2DDrawing_AlphaBlend)
Select tool
Case #Toolline
DrawLine(mousex,mousey,mousex_old,mousey_old,Color,Alpha)
Case #ToolCircle
If pressure > 0
rad = (radius*pressure)
DrawImage(ImageID(0), mousex,mousey)
;Circle(mousex,mousey,(Radius*pressure)/100,RGBA(0,0,0,alpha))
EndIf
Case #ToolBrush
If pressure > 0
DrawBrush(mousex,mousey,mousex_old,mousey_old,Color,Alpha,(Radius*pressure))
EndIf
Case #ToolBrushLine
If pressure >0
DrawLineBrush(mousex,mousey,mousex_old,mousey_old,Color,Alpha,(Radius*pressure))
EndIf
EndSelect
mousex_old = mousex
mousey_old = mousey
pressure_old = pressure
oldsize = pressure_old*Radius
EndIf
StopDrawing()
EndIf
EndIf
EndIf
Until done = #True
CallFunctionFast(WTClose,tablet_hctx) ; close and destroy
CloseLibrary(wintab_nr)
;}
;{ procedure (drawing)
Procedure DrawLineSpace(x,y,x2,y2,Color,Alpha)
LineXY(x,x,x2,y2,RGBA(Red(color),Green(color),Blue(color),alpha))
EndProcedure
Procedure DrawLine(x,y,x2,y2,Color,Alpha)
LineXY(x,y,x2,y2,RGBA(Red(color),Green(color),Blue(color),alpha))
EndProcedure
Procedure DrawLineBrush(x1,y1,x2,y2,Color=0,Alpha=255,size=1)
; just line
flech = point_distance(x1,y1,x2,y2)
d.f = point_direction(x1,y1,x2,y2)
col = RGBA(Red(color),Green(color),Blue(color),alpha)
For i=0 To flech-1
i+pas
If oldsize< size
size - 1
ElseIf oldsize< size
size + 1
EndIf
x_result = x1 + Cos(d*#PI/180)*i
y_result = y1 - (Sin(d*#PI/180)*i)
Circle(x_result,y_result,size/500,col)
Next i
EndProcedure
Procedure DrawBrush(x1,y1,x2,y2,Color=0,Alpha=255,size=1)
; old technic, don't work pretty well...
flech = point_distance(x1,y1,x2,y2)
d.d = point_direction2(x1,y1,x2,y2)
col = RGBA(Red(color),Green(color),Blue(color),alpha)
oldsiz.d = oldsize/500
newsiz.d = size/500
sind.d = Sin(d)
cosd.d = Cos(d)
Debug "Start : "+Str(newsiz) + "/" + Str(oldsiz)
;Circle(x2,y2,size/250,RGBA(0,255,0,255)) ; to see the first dot
For i = 0 To flech-1
; it's a test to have a "smoother" line, when the pressure is different, the stroke are not "smoothed"
; If newsiz < oldsiz
; oldsiz - 1
; newsiz = oldsiz-1
; ElseIf newsiz > oldsiz
; oldsiz + 1
; newsiz = oldsiz+1
; EndIf
; Debug Str(newsiz) + "/" + Str(oldsiz)
i+pas
x_result = x1 + sind *i
y_result = y1 + cosd *i
Circle(x_result,y_result,newsiz,col)
Next i
; Circle(x1,y1,size/120,RGBA(255,0,0,255)) to see the last dot
EndProcedure
;}
it's strange.- At least half of the GUI is french with german translation selected. I can only guess or try what it is.
Have you tried to restart the software ?
When We change the langage, some of the menu and panel are changed, but not all (tooltip, gadget..) for the moment.
I will change that for a next version, but if you re-start the application, you should have it in the langage you have selected.
Are you interesting in participating/improving Animatoon ?- Is the source still available?
it would be great !
If you want the source, please PM me with your email, and I'll send it to you .
The sources are not very great, because, I'm not a good coder (I'm graphist). And the sources are very simple (and not optimised for the moment).
Thanks again for your comment