[2D painting application] Animatoon

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: [2D painting application] Animatoon

Post by [blendman] »

Thank you for your answer :)

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 
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.
Hi Marc ;).
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.

kenmo wrote:This looks very cool! :shock: I will try it out.
Thanks

IdeasVacuum wrote:Luis coded a cross platform Rotate (and Mirror/Flip). It works very well: http://www.purebasic.fr/english/viewtop ... 12&t=38975
Thanks, I know Luis rotation and Djes/LSI rotation ;).
I will try Luis Solution for rotate the canvas.

Danilo 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?).
Hi

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 ^^.
- I would like image previews for the brushes (instead names only), there are too many brushes to remember names.
It's Ok in the next version.
- What is the "Nuancier" palette for? It does not work here if i select a color in this palette.
It's a swatch. It's not finished. For the moment, it's not working.
- Will you add support for Win8 Surface Pro tablets with pen input?
I would like to add support Tablet for Window/linux/mac if possible, but I don't know how I can do that :)

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

;}
- At least half of the GUI is french with german translation selected. I can only guess or try what it is.
it's strange.
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.

- Is the source still available?
Are you interesting in participating/improving Animatoon ? :D
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 ;)
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: [2D painting application] Animatoon

Post by IdeasVacuum »

I'm thinking that incorporating Undo Redo now will save you a big headache later.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
marc_256
Enthusiast
Enthusiast
Posts: 735
Joined: Thu May 06, 2010 10:16 am
Location: Belgium
Contact:

Re: [2D painting application] Animatoon

Post by marc_256 »

Hi blendman,

I just tested your program,
I changed a little bit the MouseWheel part:
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

by this part

Code: Select all

;---------------------------------------------------------------------------------------------------
;- CANVAS - MOUSE - WHEEL ACTION
;---------------------------------------------------------------------------------------------------
		Case #PB_EventType_MouseWheel
			doc\zoom = doc\zoom + (GetGadgetAttribute(#canvas,  PB_Canvas_WheelDelta) * 5)

			If doc\zoom < 10
				doc\zoom = 10
			ElseIf doc\zoom > 267			; (8000/3000 * 100)
				doc\zoom = 267
			EndIf

			If (ImageWidth(#img_final) * (doc\zoom / 100)) < 8000 And (ImageHeight(#img_final) * (doc\zoom / 100)) < 8000 And doc\zoom => 10
				Zoom()
			EndIf
Will look further on ...


Marc,
- every professional was once an amateur - greetings from Pajottenland - Belgium -
PS: sorry for my english I speak flemish ...
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: [2D painting application] Animatoon

Post by [blendman] »

Thanks Marc ;)

I have use your methode and change just :
ElseIf doc\zoom > 800000/doc\w ; or doc\h if doc\h> dow\w
doc\zoom = 800000/doc\w
And it works fine
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: [2D painting application] Animatoon

Post by [blendman] »

Hi

I have entierely recode Animatoon (with Screen, sprite and Image). It has now a good framerate, and I can continue to work on it (I have stoped because the software laged too much ^^).

Here is 2 new pictures made in my new version - screen :
Image

Image

I have updated the first post, and add a lot of new pictures, a video and new information about the dev ;).
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: [2D painting application] Animatoon

Post by [blendman] »

Hi

Here are two new videos, to show the new version of animatoon :

https://www.youtube.com/watch?v=A2MbJt1VhEE

https://www.youtube.com/watch?v=0pcLPx3zNYI

And some of my last drawing tests :
Image


And another :
http://www.dracaena-studio.com/animatoo ... Screen.jpg
User avatar
idle
Always Here
Always Here
Posts: 5019
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: [2D painting application] Animatoon

Post by idle »

That's looking really good, nice work. 8)
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
oreopa
Enthusiast
Enthusiast
Posts: 281
Joined: Sat Jun 24, 2006 3:29 am
Location: Edinburgh, Scotland.

Re: [2D painting application] Animatoon

Post by oreopa »

This looks like a great program. Well designed and highly functional. Do you plan to release it to the public at some point?

Furthermore, your art is very nice, I like it ;)
Proud supporter of PB! * Musician * C64/6502 Freak
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: [2D painting application] Animatoon

Post by [blendman] »

Thank you for your comments.
oreopa wrote:This looks like a great program. Well designed and highly functional. Do you plan to release it to the public at some point?
of course ;)
it will have two versions :
- a standard fully fonctionnal, free and probably open-source
- a "studio", with the new features (which will be in the standrad one or two year later).

If you are interested, I can send you a WIP version but in this version some features won't be finished (and it will have perhap's some bugs) ^^.
Furthermore, your art is very nice, I like it ;)
thank. Most of the images are just tests.

In fact, I'm looking for a way to have beautiful AA strokes (http://www.purebasic.fr/english/viewtop ... 13&t=62511). It's my priority ^^.
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: [2D painting application] Animatoon

Post by [blendman] »

Hi

After 6 years, I continue to work on my 2D painting software "Animatoon", to improve it :).


OPEN Source
Animatoon is Free and Open-source since 2017.
You can find the sources (and other files) here :
https://github.com/blendman/Purebasic/t ... /animatoon


If you make a compilation for mac or linux, could you provide a link, so I could post it on github, for mac and linux users ?
Thanks :)

If you want to help me to improve this cool application, please let me know ;)



Here is some painting/drawings made with Animatoon (last version 0.58x) :


Lines are a scan from a drawing I have made with Crayon, colors are made in animatoon :
Image
Bigger format :
http://dracaena-studio.com/animatoon/im ... rwald2.jpg

Completely made in animatoon (drawing and colors : )
Image

Image

Image

Image

Vidéos (screencast) :
https://youtu.be/KCLMt8qpA70

https://youtu.be/gdz407dRBIw

Cheers !
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: [2D painting application] Animatoon

Post by Keya »

wow, SUPER COOL work blendman! very impressive :) :)
Nituvious
Addict
Addict
Posts: 998
Joined: Sat Jul 11, 2009 4:57 am
Location: United States

Re: [2D painting application] Animatoon

Post by Nituvious »

I'm not sure what is more impressive. The artwork, or the editor! This is really, really cool! I love seeing new art applications!
▓▓▓▓▓▒▒▒▒▒░░░░░
Mr.L
Enthusiast
Enthusiast
Posts: 104
Joined: Sun Oct 09, 2011 7:39 am

Re: [2D painting application] Animatoon

Post by Mr.L »

Very well done, thank you very much! Unfortunately I dont have a graphic tablet (yet).
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: [2D painting application] Animatoon

Post by [blendman] »

Hello, friends of the purebasic :D

I have made other paintings with Animatoon. And I continue to improve and fixe it ^^.

The images & videos (timelapse) :

A drawing made in April/may 2020 (on A4 paper with criterium/crayon), and colorised with animatoon yesterday :
Image

And the video/timelapse :
https://www.youtube.com/watch?v=yJ53QH3yxfQ


A drawing created in may 2020 (on A4 paper with criterium( crayon)), painting with animatoon yesterday :
Image

The video timelapse/screencast :
https://youtu.be/ie56IOsYFuA


Another drawing made in may 2020 (On A4 paper, with criteirum/crayon), and painted in animatoon yesterday, but not finished :
Image


And this drawing is entierely made in animatoon this morning (1h30) :
Image

And the video timelapse :
https://youtu.be/xYa1CHhZmi0

Keya wrote:wow, SUPER COOL work blendman! very impressive :) :)
Thanks a lot :)
I'm not sure what is more impressive. The artwork, or the editor! This is really, really cool!
Thank you. I think the art AND the editor are great :D (lol ^^). But I have to improve the editor.
Very well done, thank you very much! Unfortunately I dont have a graphic tablet (yet).
Thanks. It's great with a graphic tablet :)
User avatar
IceSoft
Addict
Addict
Posts: 1616
Joined: Thu Jun 24, 2004 8:51 am
Location: Germany

Re: [2D painting application] Animatoon

Post by IceSoft »

[blendman] wrote:Hello, friends of the purebasic :D
I have made other paintings with Animatoon. And I continue to improve and fixe it ^^.
Zip is from 2017:
[blendman] wrote: OPEN Source
Animatoon is Free and Open-source since 2017.
You can find the sources (and other files) here :
https://github.com/blendman/Purebasic/t ... /animatoon

If you make a compilation for mac or linux, could you provide a link, so I could post it on github, for mac and linux users ?
Thanks :)
If you want to help me to improve this cool application, please let me know ;)
Maybe you create a githup repository with "raw" source (not zip).
So an easier work on it is possible. Also send pull requests back to you.
Belive!
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
Post Reply