| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- #Import "<std>"
- #Import "<mojo>"
- Using std..
- Using mojo..
- Global title:String="VPaint 0.1 Easter-Show-Spew Release"
- Global AboutApp:="VPaint Control,Mouse Button=Lift Pen,Mouse Wheel=Zoom,Space Key=Clear,S Key=Smile Box,C Key=Hold,Cursor Left=-RPM,Cursor Right=+RPM,Cursor Up=+Pen Radius,Cursor Down=+Pen Radius,Hold,F1=Toggle Fullscreen,Click To Start"
- Global ContactApp:=",,Latest Source: github.com/nitrologic/m2"
- Global instance:AppInstance
- Class VPane Extends Image
- Field canvas:Canvas
- Field pixmap:Pixmap
- Method New(w:Int,h:Int,bg:Color)
- Super.New(w,h,TextureFlags.Dynamic)
- canvas=New Canvas(Self)
- canvas.Clear(bg)
- canvas.Alpha=0.8
- canvas.Translate(w/2,h/2)
- Handle=New Vec2f(0.5,0.5)
- End
-
- Method Draw(display:Canvas)
- canvas.Flush()
- display.DrawImage(Self,0,0)
- End
-
- Method Clear(bg:Color)
- canvas.Clear(bg)
- End
-
- Field segcount:Int
- Field edge0:Vec2f
- Field edge1:Vec2f
-
- Method EndSegment()
- segcount=0
- End
- Method FatSegment(x:Float,y:Float,x1:Float,y1:Float,fat:Float)
- If Not canvas Return
-
- Local verts:=New Float[8]
-
- Local dy:Float=y1-y
- Local dx:Float=x1-x
-
- Local len:Float=Sqrt(dx*dx+dy*dy)
- Local q:Float=fat/len
-
- If segcount=0
- edge0=New Vec2f(x+dy*q,y-dx*q)
- edge1=New Vec2f(x-dy*q,y+dx*q)
- Endif
- segcount+=1
-
- Local v0:=edge0
- Local v1:=New Vec2f(x1+dy*q,y1-dx*q)
- Local v2:=New Vec2f(x1-dy*q,y1+dx*q)
- Local v3:=edge1
-
- canvas.DrawTriangle(v0,v1,v2)
- canvas.DrawTriangle(v0,v2,v3)
-
- edge0=v1
- edge1=v2
- End
-
- Function Curve:Float[](seg:Int,p0:Vec2f,p1:Vec2f,p2:Vec2f,p3:Vec2f)
- Local verts:=New Float[(seg+1)*2]
- For Local i:Int=0 To seg
- Local mu:Float=i*1.0/seg
- Local x:Float=CatmullInterpolate(p0.x,p1.x,p2.x,p3.x,mu)
- Local y:Float=CatmullInterpolate(p0.y,p1.y,p2.y,p3.y,mu)
- verts[i*2+0]=x
- verts[i*2+1]=y
- Next
- Return verts
- End
-
- Method OpenCurve(p0:Vec2f,p1:Vec2f,p2:Vec2f,p3:Vec2f,fat:Float)
- If Not canvas Return
- Local seg:Int=6
- Local verts:=Curve(seg,p0,p1,p2,p3)
- For Local i:Int=0 Until seg
- FatSegment(verts[i*2+0],verts[i*2+1],verts[i*2+2],verts[i*2+3],fat)
- Next
- End
-
- Method ClosedCurve(p0:Vec2f,p1:Vec2f,p2:Vec2f,p3:Vec2f,fat:Float)
- If Not canvas Return
- OpenCurve(p3,p0,p1,p2,fat)
- OpenCurve(p0,p1,p2,p3,fat)
- OpenCurve(p1,p2,p3,p0,fat)
- OpenCurve(p2,p3,p0,p1,fat)
- EndSegment()
- End
- Function CubicInterpolate:Float(y0:Float,y1:Float,y2:Float,y3:Float,mu:Float)
- Local a0:Float,a1:Float,a2:Float,a3:Float,mu2:Float
- mu2 = mu*mu
- a0 = y3 - y2 - y0 + y1
- a1 = y0 - y1 - a0
- a2 = y2 - y0
- a3 = y1
- Return(a0*mu*mu2+a1*mu2+a2*mu+a3)
- End
-
- Function CatmullInterpolate:Float(y0:Float,y1:Float,y2:Float,y3:Float,mu:Float)
- Local a0:Float,a1:Float,a2:Float,a3:Float,mu2:Float
- mu2 = mu*mu
- a0 = -0.5*y0 + 1.5*y1 - 1.5*y2 + 0.5*y3
- a1 = y0 - 2.5*y1 + 2*y2 - 0.5*y3
- a2 = -0.5*y0 + 0.5*y2
- a3 = y1
- Return(a0*mu*mu2+a1*mu2+a2*mu+a3)
- End
-
- Function CubicInterpolate2:Float(p0:Float,p1:Float,p2:Float,p3:Float,x:Float)
- Return p1 + 0.5 * x*(p2-p0+x*(2.0*p0-5.0*p1+4.0*p2-p3+x*(3.0*(p1-p2)+p3-p0)))
- End
- Method FatLine(x:Int,y:Int,x1:Int,y1:Int,fat:Float)
- If Not canvas Return
- Local dy:Int=y1-y
- Local dx:Int=x1-x
- Local len:Float=Sqrt(dx*dx+dy*dy)
- Local q:Float=fat/len
- Local v0:=New Vec2f(x+dy*q,y-dx*q)
- Local v1:=New Vec2f(x1+dy*q,y1-dx*q)
- Local v2:=New Vec2f(x1-dy*q,y1+dx*q)
- Local v3:=New Vec2f(x-dy*q,y+dx*q)
- canvas.DrawTriangle(v0,v1,v2)
- canvas.DrawTriangle(v0,v2,v3)
- End
- Method Smile(x:Float,y:Float,r:Float)
- Local v0:=New Vec2f(x-100,y+100)
- Local v1:=New Vec2f(x-100,y-20)
- Local v2:=New Vec2f(x+100,y-20)
- Local v3:=New Vec2f(x+100,y+100)
- EndSegment()
- OpenCurve(v0,v1,v2,v3,r)
- EndSegment()
- End
-
- Method Circle(x:Float,y:Float,r:Float)
- Local v0:=New Vec2f(x-100,y-100)
- Local v1:=New Vec2f(x+100,y-100)
- Local v2:=New Vec2f(x+100,y+100)
- Local v3:=New Vec2f(x-100,y+100)
- EndSegment()
- ClosedCurve(v0,v1,v2,v3,r)
- End
-
- End
- Class VBrowse
- End
- Enum AppState
- Title
- Draw
- Browse
- End
- Const TickMark:String=String.FromChar(65) '(0xE2 0x9C 0x93)
- Class VTool Extends Window
- Method New(title:String)
- Super.New(title,480,34,WindowFlags.Resizable)
- End
- End
- Class VPaint Extends Window
- Field appState:AppState
- ' Field tool:VTool
- Field pane:VPane
- Field browse:VBrowse
-
- Field zoom:Float
- Field ink:Color
- Field mousex:Int
- Field mousey:Int
- Field mousew:Int
- Field framecount:Int
- Field drawcount:Int
- Field mousecount:Int
- Field cx:Float
- Field cy:Float
- Field rot:Float
- Field rotSpeed:Float
- Field radius:Float
-
- Method ToggleTwo()
- End
-
- Method New(title:String)
- Super.New(title,720,560,WindowFlags.Resizable)
- zoom=2
- ' pane=New VPane(2048,2048,Color.Black)
- pane=New VPane(4096,4096,Color.Black)
- browse=New VBrowse()
- ink=New Color
- radius=1.0
- ' tool=New VTool("Tools")
- ' tool.Title="VPaint Pen : RGBCycle"
- End
-
- Method RefreshTitle()
- Local r:=rotSpeed*rotSpeed*rotSpeed
- Local rpm:Int=Abs(60*60*r/(Pi*2))
- Title="RPM "+rpm+" R="+Int(radius*100)
- End
-
- Method OnRender( display:Canvas ) Override
- App.RequestRender()
- Select appState
- Case AppState.Title
- Local cy:=40
- For Local line:=Eachin (AboutApp+","+ContactApp).Split(",")
- Local cx:=50
- For Local tab:=Eachin line.Split("=")
- display.DrawText(tab,cx,cy)
- cx+=120
- Next
- cy+=20
- Next
- Case AppState.Draw
- cx=Width/2
- cy=Height/2
- display.Translate(cx,cy)
- Local scale:=-1.0/zoom
- display.Scale(scale,scale)
- display.Rotate(rot)
- rot+=rotSpeed*rotSpeed*rotSpeed
- OnMouseEvent(recentMouseEvent)
- pane.Draw(display)
- framecount+=1
-
- ink=Color.FromHSV( framecount/100.0,1,1 )
- pane.canvas.Color=ink
- Case AppState.Browse
- End
- End
- Method OnKeyEvent( event:KeyEvent ) Override
- Select event.Type
- Case EventType.KeyDown
- Select event.Key
- Case Key.S
- pane.Smile(mousex,mousey,radius)
- pane.Circle(mousex,mousey,radius)
- Case Key.C
- pane.Clear(ink )
- Case Key.Escape
- instance.Terminate()
- Case Key.F1
- Fullscreen = Not Fullscreen
- Case Key.F2
- ToggleTwo()
- Case Key.Space
- rotSpeed=0
- Case Key.Left
- rotSpeed+=0.1
- Case Key.Right
- rotSpeed-=0.1
- Case Key.Down
- radius*=0.8
- Case Key.Up
- radius*=1.2
- Case Key.P
- Local pixmap:=pane.canvas.CopyPixmap( pane.canvas.Viewport )
- pixmap.Save( AppDir()+"vpaint_picture.png" )
- pixmap.Discard()
- End
- End
- RefreshTitle()
- End
-
- Field linetool:Bool=False
- Field history:=New Vec2f[4]
- Field recentMouseEvent:MouseEvent
-
- Method DrawMode()
- appState=AppState.Draw
- End
-
- Method OnMouseEvent(event:MouseEvent ) Override
-
- If appState=AppState.Title
- If event.Type=EventType.MouseDown
- DrawMode()
- Endif
- Return
- Endif
-
- If event=Null Return
-
- Local mx:Int=event.Location.X
- Local my:Int=event.Location.Y
- Local b:Int=event.Button
-
- mx=(mx-cx)*zoom
- my=(my-cy)*zoom
- Local x:=-Cos(rot)*mx+Sin(rot)*my
- Local y:=-Sin(rot)*mx-Cos(rot)*my
-
- Local w:Int
-
- If recentMouseEvent<>event w=event.Wheel.Y
-
- If mousex=x And mousey=y And mousew=w Return
-
- recentMouseEvent = event
-
- Select event.Type
-
- Case EventType.MouseWheel
- zoom-=w/8.0
- If zoom<1.0/8 zoom=1.0/8
-
- Case EventType.MouseDown
- pane.EndSegment()
-
- Case EventType.MouseMove
- history[0]=history[1]
- history[1]=history[2]
- history[2]=history[3]
- history[3]=New Vec2f(x,y)
- End
-
- If linetool
- If drawcount
- pane.FatLine(mousex,mousey,x,y,radius)
- Endif
- Else
- If drawcount>2 And Not b
- ' pane.FatCurve(mx[0],my[0],mx[1],my[1],mx[2],my[2],mx[3],my[3])
- pane.OpenCurve(history[0],history[1],history[2],history[3],radius)
- Endif
- Endif
- drawcount+=1
- mousex=x
- mousey=y
- mousew=w
-
- mousecount+=1
- End
- End
- Function Main()
- Print title
- instance = New AppInstance
- New VPaint(title)
- App.Run()
- End
- Function SaveTGA(path:String, pixmap:Pixmap)
- Local stream:=FileStream.Open(path,"w")
- Local buffer:=New Byte[18]
- Local w:=pixmap.Width
- Local h:=pixmap.Height
- buffer[2]=2
- buffer[12]=w & 255
- buffer[13]=w Shr 8
- buffer[14]=h & 255
- buffer[15]=h Shr 8
- buffer[16]=32
- buffer[17]=8
- stream.Write(Varptr buffer[0],18)
- stream.Write(pixmap.Data,w*h*4)
- stream.Close()
- End Function
|