Animation 2D

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:

Animation 2D

Post by [blendman] »

Hi

For my open-source software animatoon, I will add some animation functions.

So, I have created a little application to test the animation, and when it will be ok, I will add it in animatoon.

For the moment, it's an "independant" application ;).

version 0.4

Image

Code: Select all

; 2D Animation programm 
; blendman July 2021 - licence MIT
;{ changes
; 6.7.2021 0.4
; // new
; - add own toolbar (with some tools : paint, move)
; - Zoom canvas, movecanvas
; - we can draw on zoomed and moved canvas
; - now, the canvas use the vectordrawinglib (for zoom)
; // changes
; - layeranim : some modifications in UI (GUI colors, position of alpha)
; - layeranim : dble clic on layeranim alpha->set the alpha of layeranim.
; - canvasdrawing : add space to move the canvas
; 5.7.2021 0.3
; - panel tool : size, alpha, color
; - set layeranim name$, add layeranim alpha (display), image import on currentframe
; - layeranim add butons : visible, lock, up, down
; - display layeranim if visible
; - draw on layeranim if not lock and visible
; - layeranim improved
; - GUi add icones
; //fixes
; - clear layeranim frame doesn't all drawing
; - canvas doesn't draw correctly layeranim if frame hasn't image
; - canvas draw image of another layeranim if no image at frame current
; 2.7.2021 0.2
; - add stroke, ognion skinning, export (all images), bugfixes
; 1.7.2021 0.1
; - we can play animation
; - When draw, if not keyframe, it add image
; - Canvas draw
; - gadgets timeline (addlayeranim, addkeyframe, frame start, end, current, fps, speed, button play/stop)
; - timeline (keyframe, start, end)
;}

; init the image lib
UsePNGImageDecoder() : UsePNGImageEncoder() : UseJPEGImageDecoder() : UseJPEGImageEncoder()
#ProgramVersionAnim ="0.4"
Enumeration 
  ; images & icones
  #ico_visible=0 : #ico_Lock : #ico_Up : #ico_Down : #ico_brush : #ico_eraser : #ico_shape : #ico_Line : #ico_move : #ico_Scale : #ico_Rotate
  #img_brushcolor
  #Img_Final
  #img_last ; the last image, to not erase an image before it
  ; gadgets
  #G_Toolbar=0
  #G_TB_Brush : #G_TB_Shape : #G_TB_Line : #G_TB_Eraser : #G_TB_Clear
  #G_TB_Move : #G_TB_Scale : #G_TB_Rotate
  #G_canvasDrawing
  #G_cont_CanvasDrawing
  #G_cont_CanvasDrawingInside
  #G_ContPanelTool
  #G_PanelTool
  #G_ToolColor
  #G_ToolSizeTB : #G_ToolSizeSG
  #G_ToolAlphaTB : #G_ToolAlphaSG
  #G_ToolShape ; image, circle.
  #G_ToolType ; brush=0, eraser=1
  ; layeranim
  #G_LayerAnimVisible
  #G_LayerAnimLock
  #G_LayerAnimAlpha
  #G_LayerAnimAdd : #G_LayerAnimDel : #G_LayerAnimUp : #G_LayerAnimDown :
  ; timeline
  #G_cont_Timeline
  #G_AddFrame : #G_DelFrame
  #G_OgnionPrevious : #G_OgnionNext
  #G_FrameStart : #G_FrameEnd : #G_FrameCurrent :
  #G_FrameSpeed : #G_FrameFPS :
  #G_PlayAnim : #G_StopAnim
  #G_TimeLine
  #G_AnimProperties
  ; menu
  #menu_FileOpen=0
  #menu_FileSave
  #menu_FileExport
  #Menu_LayerClear
  #Menu_LayerClearLayerAnim
  #Menu_LayerImportImage
  #Menu_Edit_CopyKeyframe
  #Menu_Edit_Pastekeyframe
  ; action
  #action_brush=0
  #action_eraser
EndEnumeration
;{ structures& globals
Structure sImageFrame
  x.w
  y.w
  Frame.w
  image.i
EndStructure
Structure sLayerAnim
  Array Image.sImageFrame(0)
  position.w ; position in Y, in the layeranima list
  x.w : y.w
  visible.a : lock.a : alpha.a
  selected.a
  color.i
  type.a
  name$
EndStructure
Global Dim LayerAnim.sLayerAnim(0)
Global NbFrame=-1, NblayerAnim=-1, NBlayerTotal, ImageCurrent, LayerAnimID
Structure sAnimationParameters
  FPS.w
  Speed.f
  FrameCurrent.w
  FrameStart.w
  FrameEnd.w
  OgnionPrevious.a
  OgnionNext.a
EndStructure
Global Anim.sAnimationParameters
With Anim
  \fps = 12
  \Speed=1.0
  \FrameCurrent=0
  \FrameStart=0
  \FrameEnd=12
EndWith
Structure sPoint
  x.f : y.f
EndStructure
Structure sStroke
  Array Dot.sPoint(0)
EndStructure
Global Dim Stroke.sStroke(0), StrokeID, nbStroke=-1, DotCurrent, nbdot=0
Global previousx, previousy, canvasX, canvasY,Zoom,docW,docH
Structure sBrush
  alpha.a
  size.w
  ShapeType.a
  Color.i
EndStructure
Global Dim Brush.sBrush(1), action=#action_brush
brush(i)\alpha = 255
brush(i)\size = 10
;}
;{ macros & procedures
; distance, direction..
Macro GetDistance(x1,y1,x2,y2)   
  Int(Sqr((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) )       
EndMacro
Macro GetDirection(x1,y1,x2,y2)
  ATan2((y2- y1),(x2- x1))
EndMacro

Declare UpdateTimeLine()

Procedure FreeImage2(image)
  If IsImage(image) : FreeImage(image) : EndIf
EndProcedure
Procedure LoadImage2(image,file$)
 If LoadImage(image, GetCurrentDirectory()+"data\Theme\Animatoon\icones\"+file$) : EndIf
EndProcedure
Procedure AddSpinGadget(gad,x,y,w,h,min,max,tip$=#Empty$, val=0)
  SpinGadget(gad,x,y,w,h,min,max,#PB_Spin_Numeric) 
  SetGadgetState(gad,val)
  GadgetToolTip(gad,tip$)
EndProcedure
Procedure AddButtonGadget(gad,x,y,w,h,text$,tip$=#Empty$,image=-1,option=-1)
  If image=-1
    ButtonGadget(gad,x,y,w,h,text$)
    If option<>-1
      ButtonGadget(gad,x,y,w,h,text$,option)
    EndIf
  Else
    ButtonImageGadget(gad,x,y,w,h,ImageID(image))
    If option<>-1
      ButtonImageGadget(gad,x,y,w,h,ImageID(image),option)
    EndIf
  EndIf
  GadgetToolTip(gad,tip$)
EndProcedure
Procedure AddCheckBoxGadget(Gad,x,y,w,h,text$=#Empty$,name$=#Empty$,tip$=#Empty$,value=0)
  If name$<> #Empty$
    TextGadget(#PB_Any,x,y,50,h,name$)
    x+50
  EndIf
  CheckBoxGadget(gad,x,y,w,h,texte$)
  GadgetToolTip(gad,tip$)
  SetGadgetState(gad,value)
EndProcedure
Procedure AddSTringTBGadget(gadTB,gadSG,x,y,wtb,wsg,min,max,val=0,name$=#Empty$,tip$=#Empty$,wtg=30)
  ; string gadget, name and trackbar
  ; wtb = width for trackbar
  ; wsg = width of stringgagdet
  ; wtg = width for the text gadget
  ; to color the gadget
  ; color =  GetWindowColor(GetActiveWindow())
  ; To add a gadget Name+trackbar +stringgadget !! test pour ajouter un gadget "spécial : nom, trackbar et stringgadget
  h = 25
  If name$ <>#Empty$
     If TextGadget(#PB_Any, x+5, y, wtg, h, name$)
;       ;SetGadgetColor(gadName, #PB_Gadget_BackColor, color)       
     EndIf 
  Else
    wtg = 0
  EndIf  
  If TrackBarGadget(gadTB, x+2+wtg, y, wtb, h, min, max)
;     SetGadgetColor(gadTB, #PB_Gadget_BackColor, color)       
    SetGadgetState(gadTB, val)
    GadgetToolTip(gadTB, tip$)
    If StringGadget(GadSG,x+4+wtg+wtb, y, wsg, h, Str(val),#PB_String_Numeric)  
;       SetGadgetColor(GadSG, #PB_Gadget_BackColor, color)       
      SetGadgetText(GadSG, Str(val))
      GadgetToolTip(GadSG, tip$)
      ProcedureReturn 1
    EndIf
  EndIf
EndProcedure

Procedure AddKeyFrame()
  ;NbFrame+1
  ;Frame.sFrame(0)
EndProcedure  
Procedure LayerAnimAdd()
  NblayerAnim+1
  i = NblayerAnim
  NBlayerTotal+1
  ReDim LayerAnim.sLayerAnim(i)
  With LayerAnim(i)
    \name$="Layer"+NBlayerTotal
    \position = i
    \image(0)\image=-1
    \alpha = 255
    \visible = 1
  EndWith
EndProcedure    
Procedure LayerAnimMove(up=1)
  
  k = LayerAnimID
  s = ArraySize(LayerAnim())
  oldpos = LayerAnim(k)\position
  copy.sLayerAnim
  
  copy = LayerAnim(k)
  
  ; move up
  If up=1
    Newpos = oldpos+1
    If Newpos>s
       Newpos=s
    Else
      If k<s
        newpos = LayerAnim(k+1)\position
        LayerAnim(k) = LayerAnim(k+1)
        LayerAnim(k+1) = copy
        LayerAnim(k+1)\position = newpos
      EndIf
    EndIf
  ElseIf up = -1
    Newpos = oldpos-1
    If Newpos<0
      Newpos=0
    Else
      If k>0
        newpos = LayerAnim(k-1)\position
        LayerAnim(k) = LayerAnim(k-1)
        LayerAnim(k-1) = copy
        LayerAnim(k-1)\position = newpos
      EndIf
    EndIf
  EndIf
  LayerAnim(k)\position = oldpos
  
  UpdateTimeLine()
EndProcedure

Procedure PaintbrushLine(x1,y1,x2,y2)
  
  Shared UseFreeMouse
  If UseFreeMouse
    x2 = previousx 
    y2 = previousy 
  EndIf
  
  thesize = brush(action)\size
  pas.d = 30*0.01
  
  ; the distancebetween Two dots
  distBetween2dot.d = Thesize*Pas
  
  ;distance between two vectors
  Distance.d = GetDistance(x1,y1,x2,y2)
  
  ; number of dots to draw
  CountPoint = Distance/(Pas * Thesize)
  
  ; color
  r = Red(brush(action)\Color)
  g = Green(brush(action)\Color)
  b = Blue(brush(action)\Color)
  
  ; Draw  
  DrawingMode(#PB_2DDrawing_AlphaBlend)
  If distBetween2dot <= distance And CountPoint > 0
    
    direction.d = GetDirection(x1, y1, x2, y2)
    For N = 0 To CountPoint
      ; then draw the dots
      x3 = x1 + n * distBetween2dot * Sin(direction)
      y3 = y1 + n * distBetween2dot * Cos(direction)
      Circle(x3,y3,thesize/2,RGBA(r,g,b,brush(action)\alpha))
    Next
    
  Else
    Circle(x1,y1,thesize/2,RGBA(r,g,b,brush(action)\alpha))
    x3 = x1
    y3 = y1
  EndIf
  
  previousx = x3
  previousy = y3
  
EndProcedure
Procedure AddDot(x1,y1,size = 0)
  
  i = nbdot
  If i >0
    xx = x1
    yy = y1   
    StartX = Stroke(StrokeID)\Dot(i-1)\x
    StartY = Stroke(StrokeID)\Dot(i-1)\y
    dist  = GetDistance(xx,yy,StartX,StartY)
    If dist > size
      ok = 1
    EndIf 
  Else
    ok = 1
  EndIf
  
  If ok
    ReDim Stroke(StrokeID)\Dot(nbdot)
    Stroke(StrokeID)\Dot(nbdot)\x = x1
    Stroke(StrokeID)\Dot(nbdot)\y = y1
    nbdot+1
  EndIf
EndProcedure
Procedure BrushUpdate(event)
  Select event
    Case #G_ToolSizeSG, #G_ToolSizeTB
      If event=#G_ToolSizeSG
        size = Val(GetGadgetText(#G_ToolSizeSG))
      Else
        size = GetGadgetState(#G_ToolSizeTB)
      EndIf
      SetGadgetState(#G_ToolSizeTB,size)
      SetGadgetText(#G_ToolSizeSG,Str(size))
      brush(action)\size = size
    Case #G_ToolColor
      If EventType()= #PB_EventType_LeftClick       
        color=ColorRequester(brush(action)\Color)
        If color >-1
          brush(action)\color=color
          If StartDrawing(ImageOutput(#img_brushcolor))
            Box(0,0,OutputWidth(),OutputHeight(),color)
            StopDrawing()
          EndIf
          SetGadgetState(#G_ToolColor,ImageID(#img_brushcolor))
        EndIf
      EndIf
    Case #G_ToolAlphaTB, #G_ToolAlphaSG
      If event=#G_ToolAlphaSG
        a = Val(GetGadgetText(#G_ToolAlphaSG))
      Else
        a = GetGadgetState(#G_ToolAlphaTB)
      EndIf
      SetGadgetState(#G_ToolAlphaTB,a)
      SetGadgetText(#G_ToolAlphaSG,Str(a))
      brush(action)\alpha = a
  EndSelect
    
EndProcedure
Procedure UpdateCanvas(draw=0,x=-1,y=-1)
  Shared UseFreeMouse
  ; UseFreeMouse
  ; 0 : to use the stroke()\dot() and have undo.
  ; 1 : not use the dot, but a better free line
  UseFreeMouse = 1
  Define cx=0, cy=0, z.d=0
  z.d = Zoom * 0.01
  k = LayerAnimID
  j = anim\FrameCurrent
  w = docW
  h = docH
  
  If draw =2
  Else
    If j > ArraySize(LayerAnim(k)\Image())
      ReDim LayerAnim(k)\Image(j)
      LayerAnim(k)\Image(j)\image = -1
    EndIf
    ; create image if needed
    If draw = 1 And LayerAnim(k)\lock = 0 And LayerAnim(k)\visible = 1
      If Not IsImage(LayerAnim(k)\Image(j)\image) Or LayerAnim(k)\Image(j)\image< #img_last
        LayerAnim(k)\Image(j)\image = CreateImage(#PB_Any, w,h,32,#PB_Image_Transparent)
      EndIf
    EndIf
    ; draw on current image
    img = LayerAnim(k)\Image(j)\image
    If draw And LayerAnim(k)\lock = 0  And LayerAnim(k)\visible = 1
      If StartDrawing(ImageOutput(img))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        If UseFreeMouse = 1
          PaintbrushLine(x,y,previousx,previousy)
        Else
          If ArraySize(Stroke(StrokeID)\Dot())>DotCurrent+1
            With Stroke(StrokeID)
              If ArraySize(\Dot())=0
                PaintbrushLine(\Dot(0)\x,\Dot(0)\y,\Dot(0)\x,\Dot(0)\y)
              Else
                For i=DotCurrent To ArraySize(\Dot())-1
                  PaintbrushLine(\Dot(i+1)\x,\Dot(i+1)\y,\Dot(i)\x,\Dot(i)\y)
                Next
              EndIf
              DotCurrent = ArraySize(\Dot())
            EndWith
          EndIf
        EndIf
        StopDrawing()
      EndIf
    EndIf
  EndIf

  ; update the canvas
  c= 90 ; backgroundcolor of canvas
  If StartDrawing(ImageOutput(#Img_Final))
    ; Box(0,0,OutputWidth(), OutputHeight(), RGB(c,c,c))
    DrawingMode(#PB_2DDrawing_AllChannels)
    Box(0,0, OutputWidth(), OutputHeight(), RGBA(255,255,255,255))
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    
    ; ognion skining previous
    j = anim\FrameCurrent
    s = ArraySize(LayerAnim())
    For k= 0 To s
      If LayerAnim(k)\visible
        If (j-anim\OgnionPrevious)>=0
          For i =(j-anim\OgnionPrevious) To j
            If ArraySize(LayerAnim(k)\Image())>i
              If LayerAnim(k)\Image(i)\image >#img_last
                a = LayerAnim(k)\alpha*0.5
                img_2 = LayerAnim(k)\Image(i)\image
                DrawAlphaImage(ImageID(img_2),cx,cy, a)
              EndIf
            EndIf
          Next
        EndIf
      EndIf
    Next 
    
    ; draw the layeranim images for the current frame
    ;      j = anim\FrameCurrent
    For i=0 To s
      With LayerAnim(i)
        If \visible
          If ArraySize(\Image())>=J
            img = LayerAnim(i)\Image(j)\image
            If img >#img_last
              DrawAlphaImage(ImageID(img),cx,cy,\alpha)
              ok=1
            Else
              ;{
              ok = 0
              ;}
            EndIf
          EndIf
          If ok = 0
            ; check if we have an image before this frame
            For jj=j To 0 Step-1
              If ArraySize(\Image()) > =jj
                img = LayerAnim(i)\Image(jj)\image
                If img >#img_last
                  DrawAlphaImage(ImageID(img),cx,cy,\alpha)
                  Break
                EndIf
              EndIf
            Next
          EndIf
        EndIf
      EndWith
    Next 
    
    ; ognion skining next
    k=LayerAnimID
    If LayerAnim(k)\visible 
      For i =j To (j+anim\OgnionPrevious)
      Next
    EndIf
    StopDrawing()
  EndIf
  
  If StartVectorDrawing(CanvasVectorOutput(#G_canvasDrawing))
    AddPathBox(0, 0, GadgetWidth(#G_canvasDrawing), GadgetHeight(#G_canvasDrawing))
    VectorSourceColor(RGBA(c,c,c,255))
    FillPath()
    MovePathCursor(canvasX,canvasY) ; the canvas position
    ScaleCoordinates(z,z)
    DrawVectorImage(ImageID(#Img_Final))
    StopVectorDrawing()
  EndIf
EndProcedure
Procedure UpdateTimeLine()
  ; size of a layer and keyframe
  Shared LayerAnimH, LayerAnimW,LayerAnimAlphaX
  w = 20
  h = 20 : LayerAnimH = h
  w1=200 : LayerAnimW = w1; max
  w2=10
  w4=80
  LayerAnimAlphaX=6
  xtl = w1-w4-6
  
  
  If StartDrawing(CanvasOutput(#G_TimeLine))
    ; draw the background of the timeline and layeranim
    c = 90
    Box(0,0,OutputWidth(),OutputHeight(),RGB(c,c,c))
    ; DrawThe layer Animation
    For i=0 To ArraySize(LayerAnim())
      DrawingMode(#PB_2DDrawing_AllChannels)
      With LayerAnim(i)
        y = (2+h) * (ArraySize(LayerAnim())-i) 
        c= 120
        ; draw the background box
        Box(0,y, OutputWidth(), h, RGBA(c,c,c,255))
        c= 130
        ; draw the box for the layer anim
        Box(0,y, w1, h, RGBA(c,c,c,255))
        ; if selected, draw another color
        If LayerAnimID=i
          c=120
          Box(0,y, OutputWidth(), h, RGBA(c+30,c+20,c,255))
          c=170
          Box(0,y, w1, h, RGBA(c,c,c,255))
        EndIf
        x=3
         ; draw icone (visible, lock)
        If LayerAnim(i)\visible
          DrawAlphaImage(ImageID(#ico_visible),x,y)
        EndIf
        If LayerAnim(i)\lock
          DrawAlphaImage(ImageID(#ico_Lock),18+x,y)
        EndIf
        ;  name of the layeranim
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(40,y,\name$)
        ; alpha of the layeranim
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        Box(xtl,y+1,w4,h-2,RGBA(0,0,0,40))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        Box(xtl,y+1,(w4*\alpha)/255,h-2,RGBA(0,0,255,70))
      EndWith
      
    Next
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    ; draw the separation
    Box(w1,0,w2,OutputHeight(),RGBA(200,200,200,255))
    ; Draw the keyframe
    x1 = w1+w2+2
    w3 =OutputWidth() - w1-w2
    For i=0 To w3/w 
      LineXY(x1+i*w,0,x1+i*w,OutputHeight(),RGBA(255,255,255,180))
    Next
    ; Draw the utilities for anim (start /end cursor, current frame cursor)
    Box(x1+(Anim\FrameCurrent)*w,0,w,OutputHeight(),RGBA(200,150,150,140))
    Box(x1+(Anim\FrameStart)*w,0,2,OutputHeight(),RGBA(0,255,255,255))
    Box(x1+(Anim\FrameEnd+1)*w,0,2,OutputHeight(),RGBA(255,0,0,255))
    StopDrawing()
  EndIf
  UpdateCanvas()
EndProcedure
Procedure EventTimeLine() 
  Shared LayerAnimW, LayerAnimH, LayerAnimAlphaX
  
  If EventType()=#PB_EventType_LeftButtonDown Or EventType()=#PB_EventType_LeftDoubleClick Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(#G_TimeLine, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
    x = GetGadgetAttribute(#G_TimeLine, #PB_Canvas_MouseX)
    y = GetGadgetAttribute(#G_TimeLine, #PB_Canvas_MouseY)
    If EventType() = #PB_EventType_LeftButtonDown 
      ;Select the layer anim
      LayerAnimID = ArraySize(LayerAnim())- y/LayerAnimH
      If LayerAnimID> ArraySize(LayerAnim())
        LayerAnimID= ArraySize(LayerAnim())
      ElseIf LayerAnimID<0
        LayerAnimID=0
      EndIf
    EndIf
    
    If x < LayerAnimW
      If x<40 
        If EventType() = #PB_EventType_LeftButtonDown 
          id = ArraySize(LayerAnim())-y/LayerAnimH
          If id> ArraySize(LayerAnim())
            id= ArraySize(LayerAnim())
          EndIf
          If x<21
            LayerAnim(id)\visible = 1-LayerAnim(id)\visible
          Else
            LayerAnim(id)\lock = 1-LayerAnim(id)\lock
          EndIf
        EndIf
      Else
        ; set the alpha of layeranim
        If x > LayerAnimW-(82) And x<LayerAnimW-2
          If EventType()=#PB_EventType_LeftDoubleClick
            alpha = Val(InputRequester("Transparency",
                                       "Set the transparency For the layeranim", 
                                       Str(LayerAnim(LayerAnimID)\alpha)))
            If alpha>=0 And alpha <=255
              LayerAnim(LayerAnimID)\alpha = alpha
            EndIf
          Else
            LayerAnim(LayerAnimID)\alpha = (x-(LayerAnimW-82))*255/80
          EndIf
          
          If LayerAnim(LayerAnimID)\alpha<0
            LayerAnim(LayerAnimID)\alpha=0
          ElseIf LayerAnim(LayerAnimID)\alpha > 255
            LayerAnim(LayerAnimID)\alpha = 255
          EndIf
        Else
          If EventType() = #PB_EventType_LeftDoubleClick 
            name$ = InputRequester("LAyerAnim", "Name","");LayerAnim(LayerAnimID)\name$)
            If name$<>#Empty$
              LayerAnim(LayerAnimID)\name$ = name$
              UpdateTimeLine()  
            EndIf
          EndIf
        EndIf
      EndIf
    Else
      x = Round((x-LayerAnimW-15)/20,#PB_Round_Down)
      If x <0
        x=0
      EndIf
      Anim\FrameCurrent = x
      SetGadgetState(#G_FrameCurrent, Anim\FrameCurrent)
    EndIf
    UpdateTimeLine()  
  EndIf
EndProcedure
Procedure WindowLayerAnim()
  ;   If OpenWindow(#Win_LayerAnim,0,0,w,h,"LayerAnim properties",#PB_Window_SystemMenu)
  ;   EndIf
EndProcedure
;}

If ExamineDesktops()
  w=DesktopWidth(0)
  h=DesktopHeight(0)
EndIf
If OpenWindow(0, 0, 0, w, h, "Animatoon - animation v"+#programVersionAnim, #PB_Window_SystemMenu|#PB_Window_MaximizeGadget|#PB_Window_Maximize|#PB_Window_MinimizeGadget)
  ProjectName$ = "Project"+FormatDate("%dd%mm%yyyy%hh%ii%ss", Date())
  Zoom = 100 : z.d=zoom * 0.01 : c = 150 ; color theme
  SetWindowColor(0, RGB(c,c,c))
  ;{ menu
  CreateMenu(0,WindowID(0))
  MenuTitle("File")
  MenuItem(#menu_FileOpen, "Open")
  MenuItem(#menu_FileSave, "Save")
  MenuItem(#menu_FileExport, "Export")
  MenuTitle("View")
  MenuTitle("Layer")
  ;MenuItem(#Menu_LayerClearLayerAnim, "Clear LayerAnim (all frames)")
  MenuItem(#Menu_LayerClear, "Clear current frame on LayerAnim")
  MenuItem(#Menu_LayerImportImage, "Import image on current frame")
  CreateStatusBar(0,WindowID(0)) : AddStatusBarField(100) : AddStatusBarField(100)
  ;}
  ;{ load icone
  LoadImage2(#ico_visible,"view.png") : LoadImage2(#ico_Lock,"locked.png") 
  LoadImage2(#ico_Up,"up.png") : LoadImage2(#ico_Down,"down.png") 
  LoadImage2(#ico_brush,"brush.png") : LoadImage2(#ico_shape,"circle.png") 
  ;}
  ;{ gadgets
  w = 800 : h=600
  docW = w : docH = h
  If CreateImage(#Img_Final,docW,docH,32,#PB_Image_Transparent) : EndIf
  wp = 200 ; width panel tool
  x = wp
  h1=170 ; height of timeline
  tbh = 30 ; toobar height
  canvasW = WindowWidth(0)-wp-10
  canvasH = WindowHeight(0)-h1-MenuHeight()-StatusBarHeight(0)-tbh
  canvasX = canvasW/2-(z*docW)/2 : canvasY = canvasH/2-(z*docH)/2
  c = 150 ; color theme
  If ContainerGadget(#G_Toolbar,0,0,WindowWidth(0),tbh)
    SetGadgetColor(#G_Toolbar,#PB_Gadget_BackColor, RGB(c,c,c))
    x = 10 : y = 0 : h=28 : b = 3
    AddButtonGadget(#G_TB_Brush,x,y,h,h,"","",#ico_brush,#PB_Button_Toggle) : x+h+b
    AddButtonGadget(#G_TB_Shape,x,y,h,h,"","",#ico_shape,#PB_Button_Toggle) : x+h+b
    CloseGadgetList()
  EndIf
  y = tbh : c = 150 
  If ContainerGadget(#G_ContPanelTool,0,y,wp,CanvasH)
    SetGadgetColor(#G_ContPanelTool,#PB_Gadget_BackColor, RGB(c,c,c))
    If PanelGadget(#G_PanelTool,0,0,wp,CanvasH)
      SetGadgetColor(#G_PanelTool,#PB_Gadget_BackColor, RGB(c,c,c))
      AddGadgetItem(#G_PanelTool,0,"Tool")
       x=0 : y=10
       wtb = 100 : wsg = 50
       AddSTringTBGadget(#G_ToolSizeTB,#G_ToolSizeSG,x,y,wtb,wsg,1,100,brush(action)\size,"Size") : y+25
       AddSTringTBGadget(#G_ToolAlphaTB,#G_ToolAlphaSG,x,y,wtb,wsg,0,255,brush(action)\alpha,"Tra","Set the transparency of the Tool") : y+25
       If CreateImage(#img_brushcolor,50,50) 
         If ImageGadget(#G_ToolColor,x+10,y,50,50,ImageID(#img_brushcolor),#PB_Image_Border ) :EndIf
       EndIf
;   #G_ToolImage
;   #G_ToolType ; brush=0, eraser=1
      CloseGadgetList()
    EndIf
    CloseGadgetList()
  EndIf
  y = tbh : x = wp+5 : c = 90 
  If ContainerGadget(#G_cont_CanvasDrawing,x,y,canvasW,CanvasH) 
    SetGadgetColor(#G_cont_CanvasDrawing,#PB_Gadget_BackColor, RGB(c,c,c))
    CanvasGadget(#G_canvasDrawing, 0,0, canvasW, CanvasH,#PB_Canvas_Keyboard)
    CloseGadgetList()
  EndIf
  y=WindowHeight(0)-h1-MenuHeight()-StatusBarHeight(0)
  w=20 : h=20 : d=30 : b = 3: c = 150 
  If ContainerGadget(#G_cont_Timeline,0,y,WindowWidth(0),h1) 
    SetGadgetColor(#G_cont_Timeline,#PB_Gadget_BackColor, RGB(c,c,c))
    x=10 : y=10
    AddButtonGadget(#G_LayerAnimVisible,x,y,h,h,"","",#ico_visible,#PB_Button_Toggle) : x+h+b
    AddButtonGadget(#G_LayerAnimLock,x,y,h,h,"","",#ico_Lock,#PB_Button_Toggle) : x+h+b
    
    AddButtonGadget(#G_LayerAnimAdd,x,y,w,h,"+","Add a layerAnim") : x+w+b
    AddButtonGadget(#G_LayerAnimDel,x,y,w,h,"-","Delete the current layerAnim") : x+w+b
    AddButtonGadget(#G_LayerAnimUp,x,y,w,h,"-","Move the layerAnim up",#ico_Up) : x+w+b
    AddButtonGadget(#G_LayerAnimDown,x,y,w,h,"-","Move the layerAnim down",#ico_Down) : x+w+15
    
    
    x = 250
    AddButtonGadget(#G_AddFrame,x,y,w,h,"+","Add keyframe (and image on the selected layer)") : x+w+b
    AddButtonGadget(#G_DelFrame,x,y,w,h,"-","Delete the current keyframe (and delete all images for this keyframe on the layer)") : x+w+d
    w=60
    AddSpinGadget(#G_OgnionPrevious,x,y,w,h,0,5,"Ognion Skinning Previous",Anim\OgnionPrevious) : x+w+b
    AddSpinGadget(#G_OgnionNext,x,y,w,h,0,5,"Ognion Skinning Next",Anim\OgnionNext) : x+w+d
    
    AddSpinGadget(#G_FrameStart,x,y,w,h,0,1000,"Start of animation",Anim\FrameStart) : x+w+b
    AddSpinGadget(#G_FrameEnd,x,y,w,h,1,1000,"End of animation",Anim\FrameEnd) : x+w+b
    AddSpinGadget(#G_FrameCurrent,x,y,w,h,0,1000, "Current frame",Anim\FrameCurrent) : x+w+d
    AddSpinGadget(#G_FrameSpeed,x,y,w,h,0,100, "Speed of animation",Anim\Speed*10) : x+w+b
    AddSpinGadget(#G_FrameFPS,x,y,w,h,0,100, "FPS of animation",Anim\FPS) : x+w+d
    
    w= 70
    AddButtonGadget(#G_PlayAnim,x,y,w,h,"Play","",-1,#PB_Button_Toggle) : x+w+b
    AddButtonGadget(#G_StopAnim,x,y,w,h,"Stop") : x+w+d
    ; the timeline
    x=10 : y+h+5
    CanvasGadget(#G_TimeLine, 10, y, WindowWidth(0)-20, h1-40,#PB_Canvas_Border   )
    CloseGadgetList()
  EndIf
  
  LayerAnimAdd()
  UpdateTimeLine()
  ;}
  Repeat
    Event = WaitWindowEvent(1)
    EventGadget = EventGadget() 
    EventMenu = EventMenu() 
    z.d=zoom * 0.01
    mx = WindowMouseX(0) - GadgetX(#G_cont_CanvasDrawing)
    my = WindowMouseY(0) - GadgetY(#G_cont_CanvasDrawing)
    Select Event 
      Case #PB_Event_Menu
        Select EventMenu 
          Case #Menu_LayerClear
            If ArraySize(LayerAnim(LayerAnimID)\Image())>=anim\FrameCurrent
              img = LayerAnim(LayerAnimID)\Image(anim\FrameCurrent)\image
              If IsImage(img) And img > #img_last
;                 If StartDrawing(ImageOutput(LayerAnim(LayerAnimID)\Image(anim\FrameCurrent)\image))
;                   DrawingMode(#PB_2DDrawing_AllChannels)
;                   Box(0,0,OutputWidth(), OutputHeight(), RGBA(0,0,0,0))
;                 StopDrawing() : EndIf
                FreeImage2(LayerAnim(LayerAnimID)\Image(anim\FrameCurrent)\image)
                LayerAnim(LayerAnimID)\Image(anim\FrameCurrent)\image = -1
                updateCanvas(0)
              EndIf
            EndIf
          Case #Menu_LayerImportImage
            file$= OpenFileRequester("Import",GetCurrentDirectory(),"Images|*.png;*.jpg;*bmp",0)
            If file$ <>#Empty$  
              FreeImage2( LayerAnim(LayerAnimID)\Image(anim\FrameCurrent)\image )
              LayerAnim(LayerAnimID)\Image(anim\FrameCurrent)\image = LoadImage(#PB_Any,file$)
              UpdateCanvas(1)
            EndIf
            
          Case #menu_FileExport
            oldlayerANimId = LayerAnimID
            For k=0 To ArraySize(LayerAnim())
              For i=0 To ArraySize(LayerAnim(k)\Image())
                img = LayerAnim(k)\Image(i)\image
                If IsImage(img) And img > #img_last
                  If SaveImage(img, GetCurrentDirectory()+ProjectName$+"_Layer"+Str(k)+"_Image"+Str(i)+".png",#PB_ImagePlugin_PNG)
                  EndIf
                EndIf
              Next 
            Next
            LayerAnimID= oldlayerANimId
        EndSelect
      Case #PB_Event_Gadget 
        Select EventGadget
          Case #G_canvasDrawing 
            If EventType() = #PB_EventType_KeyUp 
              If GetGadgetAttribute(#G_canvasDrawing, #PB_Canvas_Key) & #PB_Shortcut_Space
                movecanvas  = 0
              EndIf
            ElseIf EventType() = #PB_EventType_KeyDown 
              If GetGadgetAttribute(#G_canvasDrawing, #PB_Canvas_Key) & #PB_Shortcut_Space
                movecanvas =1
              EndIf
            Else
              If movecanvas =1
                If EventType() = #PB_EventType_LeftButtonDown 
                  If move = 0
                    move = 1
                    startcanvasX = mx - canvasX
                    startcanvasY = my - canvasY
                    ; UpdateCanvas()
                  EndIf
                ElseIf EventType() = #PB_EventType_LeftButtonUp
                  move = 0
                  UpdateCanvas()
                ElseIf move And EventType() = #PB_EventType_MouseMove
                  canvasX = mx - startcanvasX
                  canvasY = my - startcanvasY
                  ; ResizeGadget(#G_canvasDrawing,canvasX,canvasY,#PB_Ignore,#PB_Ignore)
                  UpdateCanvas(2)
                EndIf
              Else
                If EventType() = #PB_EventType_Focus
                ElseIf EventType() = #PB_EventType_MouseWheel
                  zoom +10*GetGadgetAttribute(#G_canvasDrawing,#PB_Canvas_WheelDelta)
                  If zoom<10
                    zoom=10
                  ElseIf zoom> 500
                    zoom = 500
                  EndIf
                  StatusBarText(0,1,"Zoom : "+Str(Zoom)+"%")
                  UpdateCanvas(2)
                Else
                  x = GetGadgetAttribute(#G_canvasDrawing, #PB_Canvas_MouseX)/z -canvasX/z
                  y = GetGadgetAttribute(#G_canvasDrawing, #PB_Canvas_MouseY)/z -canvasY/z
                  If EventType() = #PB_EventType_LeftButtonUp
                    ; StrokeID+1 ; to get an undo ?
                    ReDim Stroke.sStroke(StrokeID)
                    DotCurrent=0
                    nbdot=0
                  ElseIf EventType() = #PB_EventType_LeftButtonDown 
                    AddDot(x,y)
                    previousx = x
                    previousY = y
                    updateCanvas(1,x,y)
                  ElseIf (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(#G_canvasDrawing, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
                    AddDot(x,y)
                    updateCanvas(1,x,y)
                    previousx = x
                    previousY = y
                  EndIf
                EndIf
              EndIf
            EndIf
          Case #G_ToolSizeTB, #G_ToolSizeSG, #G_ToolAlphaSG, #G_ToolAlphaTB,#G_ToolColor
            BrushUpdate(EventGadget)
          Case #G_OgnionPrevious,#G_OgnionNext
            Anim\OgnionPrevious = GetGadgetState(#G_OgnionPrevious)
            Anim\OgnionNext = GetGadgetState(#G_OgnionNext)
            updateCanvas(0)
          Case #G_LayerAnimUp
            LayerAnimMove(1)
          Case #G_LayerAnimDown
            LayerAnimMove(-1)
          Case #G_LayerAnimAdd
            LayerAnimAdd()
            UpdateTimeLine() 
          Case #G_FrameStart
            Anim\FrameStart = GetGadgetState(EventGadget)
            UpdateTimeLine() 
          Case #G_FrameEnd
            Anim\FrameEnd = GetGadgetState(EventGadget)
            UpdateTimeLine()  
          Case #G_FrameFPS, #G_FrameSpeed
            Anim\FPS = GetGadgetState(#G_FrameFPS)
            Anim\Speed = GetGadgetState(#G_FrameSpeed)/10
            UpdateTimeLine()
          Case #G_PlayAnim
            PlayANim=1 
            animtimer = ElapsedMilliseconds()
          Case #G_StopAnim
            PlayANim=0
            SetGadgetState(#G_PlayAnim,0)
          Case #G_FrameCurrent
            Anim\FrameCurrent = GetGadgetState(EventGadget)
            UpdateTimeLine()
          Case #G_TimeLine
            EventTimeLine()
        EndSelect
    EndSelect  
    
    If PlayAnim = 1
      If ElapsedMilliseconds() >animtimer  + (1000/(anim\FPS * anim\Speed))
        animtimer = ElapsedMilliseconds()
        Anim\FrameCurrent +1
        If Anim\FrameCurrent> Anim\FrameEnd
          Anim\FrameCurrent= Anim\FrameStart
        EndIf
        UpdateTimeLine()
        SetGadgetState(#G_FrameCurrent, Anim\FrameCurrent)
      EndIf
    EndIf
    
  Until Event = #PB_Event_CloseWindow
EndIf