vpaint.monkey2 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #Import "<std>"
  2. #Import "<mojo>"
  3. Using std..
  4. Using mojo..
  5. Global title:String="VPaint 0.1 Easter-Show-Spew Release"
  6. 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"
  7. Global ContactApp:=",,Latest Source: github.com/nitrologic/m2"
  8. Global instance:AppInstance
  9. Class VPane Extends Image
  10. Field canvas:Canvas
  11. Field pixmap:Pixmap
  12. Method New(w:Int,h:Int,bg:Color)
  13. Super.New(w,h,TextureFlags.Dynamic)
  14. canvas=New Canvas(Self)
  15. canvas.Clear(bg)
  16. canvas.Alpha=0.8
  17. canvas.Translate(w/2,h/2)
  18. Handle=New Vec2f(0.5,0.5)
  19. End
  20. Method Draw(display:Canvas)
  21. canvas.Flush()
  22. display.DrawImage(Self,0,0)
  23. End
  24. Method Clear(bg:Color)
  25. canvas.Clear(bg)
  26. End
  27. Field segcount:Int
  28. Field edge0:Vec2f
  29. Field edge1:Vec2f
  30. Method EndSegment()
  31. segcount=0
  32. End
  33. Method FatSegment(x:Float,y:Float,x1:Float,y1:Float,fat:Float)
  34. If Not canvas Return
  35. Local verts:=New Float[8]
  36. Local dy:Float=y1-y
  37. Local dx:Float=x1-x
  38. Local len:Float=Sqrt(dx*dx+dy*dy)
  39. Local q:Float=fat/len
  40. If segcount=0
  41. edge0=New Vec2f(x+dy*q,y-dx*q)
  42. edge1=New Vec2f(x-dy*q,y+dx*q)
  43. Endif
  44. segcount+=1
  45. Local v0:=edge0
  46. Local v1:=New Vec2f(x1+dy*q,y1-dx*q)
  47. Local v2:=New Vec2f(x1-dy*q,y1+dx*q)
  48. Local v3:=edge1
  49. canvas.DrawTriangle(v0,v1,v2)
  50. canvas.DrawTriangle(v0,v2,v3)
  51. edge0=v1
  52. edge1=v2
  53. End
  54. Function Curve:Float[](seg:Int,p0:Vec2f,p1:Vec2f,p2:Vec2f,p3:Vec2f)
  55. Local verts:=New Float[(seg+1)*2]
  56. For Local i:Int=0 To seg
  57. Local mu:Float=i*1.0/seg
  58. Local x:Float=CatmullInterpolate(p0.x,p1.x,p2.x,p3.x,mu)
  59. Local y:Float=CatmullInterpolate(p0.y,p1.y,p2.y,p3.y,mu)
  60. verts[i*2+0]=x
  61. verts[i*2+1]=y
  62. Next
  63. Return verts
  64. End
  65. Method OpenCurve(p0:Vec2f,p1:Vec2f,p2:Vec2f,p3:Vec2f,fat:Float)
  66. If Not canvas Return
  67. Local seg:Int=6
  68. Local verts:=Curve(seg,p0,p1,p2,p3)
  69. For Local i:Int=0 Until seg
  70. FatSegment(verts[i*2+0],verts[i*2+1],verts[i*2+2],verts[i*2+3],fat)
  71. Next
  72. End
  73. Method ClosedCurve(p0:Vec2f,p1:Vec2f,p2:Vec2f,p3:Vec2f,fat:Float)
  74. If Not canvas Return
  75. OpenCurve(p3,p0,p1,p2,fat)
  76. OpenCurve(p0,p1,p2,p3,fat)
  77. OpenCurve(p1,p2,p3,p0,fat)
  78. OpenCurve(p2,p3,p0,p1,fat)
  79. EndSegment()
  80. End
  81. Function CubicInterpolate:Float(y0:Float,y1:Float,y2:Float,y3:Float,mu:Float)
  82. Local a0:Float,a1:Float,a2:Float,a3:Float,mu2:Float
  83. mu2 = mu*mu
  84. a0 = y3 - y2 - y0 + y1
  85. a1 = y0 - y1 - a0
  86. a2 = y2 - y0
  87. a3 = y1
  88. Return(a0*mu*mu2+a1*mu2+a2*mu+a3)
  89. End
  90. Function CatmullInterpolate:Float(y0:Float,y1:Float,y2:Float,y3:Float,mu:Float)
  91. Local a0:Float,a1:Float,a2:Float,a3:Float,mu2:Float
  92. mu2 = mu*mu
  93. a0 = -0.5*y0 + 1.5*y1 - 1.5*y2 + 0.5*y3
  94. a1 = y0 - 2.5*y1 + 2*y2 - 0.5*y3
  95. a2 = -0.5*y0 + 0.5*y2
  96. a3 = y1
  97. Return(a0*mu*mu2+a1*mu2+a2*mu+a3)
  98. End
  99. Function CubicInterpolate2:Float(p0:Float,p1:Float,p2:Float,p3:Float,x:Float)
  100. 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)))
  101. End
  102. Method FatLine(x:Int,y:Int,x1:Int,y1:Int,fat:Float)
  103. If Not canvas Return
  104. Local dy:Int=y1-y
  105. Local dx:Int=x1-x
  106. Local len:Float=Sqrt(dx*dx+dy*dy)
  107. Local q:Float=fat/len
  108. Local v0:=New Vec2f(x+dy*q,y-dx*q)
  109. Local v1:=New Vec2f(x1+dy*q,y1-dx*q)
  110. Local v2:=New Vec2f(x1-dy*q,y1+dx*q)
  111. Local v3:=New Vec2f(x-dy*q,y+dx*q)
  112. canvas.DrawTriangle(v0,v1,v2)
  113. canvas.DrawTriangle(v0,v2,v3)
  114. End
  115. Method Smile(x:Float,y:Float,r:Float)
  116. Local v0:=New Vec2f(x-100,y+100)
  117. Local v1:=New Vec2f(x-100,y-20)
  118. Local v2:=New Vec2f(x+100,y-20)
  119. Local v3:=New Vec2f(x+100,y+100)
  120. EndSegment()
  121. OpenCurve(v0,v1,v2,v3,r)
  122. EndSegment()
  123. End
  124. Method Circle(x:Float,y:Float,r:Float)
  125. Local v0:=New Vec2f(x-100,y-100)
  126. Local v1:=New Vec2f(x+100,y-100)
  127. Local v2:=New Vec2f(x+100,y+100)
  128. Local v3:=New Vec2f(x-100,y+100)
  129. EndSegment()
  130. ClosedCurve(v0,v1,v2,v3,r)
  131. End
  132. End
  133. Class VBrowse
  134. End
  135. Enum AppState
  136. Title
  137. Draw
  138. Browse
  139. End
  140. Const TickMark:String=String.FromChar(65) '(0xE2 0x9C 0x93)
  141. Class VTool Extends Window
  142. Method New(title:String)
  143. Super.New(title,480,34,WindowFlags.Resizable)
  144. End
  145. End
  146. Class VPaint Extends Window
  147. Field appState:AppState
  148. ' Field tool:VTool
  149. Field pane:VPane
  150. Field browse:VBrowse
  151. Field zoom:Float
  152. Field ink:Color
  153. Field mousex:Int
  154. Field mousey:Int
  155. Field mousew:Int
  156. Field framecount:Int
  157. Field drawcount:Int
  158. Field mousecount:Int
  159. Field cx:Float
  160. Field cy:Float
  161. Field rot:Float
  162. Field rotSpeed:Float
  163. Field radius:Float
  164. Method ToggleTwo()
  165. End
  166. Method New(title:String)
  167. Super.New(title,720,560,WindowFlags.Resizable)
  168. zoom=2
  169. ' pane=New VPane(2048,2048,Color.Black)
  170. pane=New VPane(4096,4096,Color.Black)
  171. browse=New VBrowse()
  172. ink=New Color
  173. radius=1.0
  174. ' tool=New VTool("Tools")
  175. ' tool.Title="VPaint Pen : RGBCycle"
  176. End
  177. Method RefreshTitle()
  178. Local r:=rotSpeed*rotSpeed*rotSpeed
  179. Local rpm:Int=Abs(60*60*r/(Pi*2))
  180. Title="RPM "+rpm+" R="+Int(radius*100)
  181. End
  182. Method OnRender( display:Canvas ) Override
  183. App.RequestRender()
  184. Select appState
  185. Case AppState.Title
  186. Local cy:=40
  187. For Local line:=Eachin (AboutApp+","+ContactApp).Split(",")
  188. Local cx:=50
  189. For Local tab:=Eachin line.Split("=")
  190. display.DrawText(tab,cx,cy)
  191. cx+=120
  192. Next
  193. cy+=20
  194. Next
  195. Case AppState.Draw
  196. cx=Width/2
  197. cy=Height/2
  198. display.Translate(cx,cy)
  199. Local scale:=-1.0/zoom
  200. display.Scale(scale,scale)
  201. display.Rotate(rot)
  202. rot+=rotSpeed*rotSpeed*rotSpeed
  203. OnMouseEvent(recentMouseEvent)
  204. pane.Draw(display)
  205. framecount+=1
  206. ink=Color.FromHSV( framecount/100.0,1,1 )
  207. pane.canvas.Color=ink
  208. Case AppState.Browse
  209. End
  210. End
  211. Method OnKeyEvent( event:KeyEvent ) Override
  212. Select event.Type
  213. Case EventType.KeyDown
  214. Select event.Key
  215. Case Key.S
  216. pane.Smile(mousex,mousey,radius)
  217. pane.Circle(mousex,mousey,radius)
  218. Case Key.C
  219. pane.Clear(ink )
  220. Case Key.Escape
  221. instance.Terminate()
  222. Case Key.F1
  223. Fullscreen = Not Fullscreen
  224. Case Key.F2
  225. ToggleTwo()
  226. Case Key.Space
  227. rotSpeed=0
  228. Case Key.Left
  229. rotSpeed+=0.1
  230. Case Key.Right
  231. rotSpeed-=0.1
  232. Case Key.Down
  233. radius*=0.8
  234. Case Key.Up
  235. radius*=1.2
  236. Case Key.P
  237. Local pixmap:=pane.canvas.CopyPixmap( pane.canvas.Viewport )
  238. pixmap.Save( AppDir()+"vpaint_picture.png" )
  239. pixmap.Discard()
  240. End
  241. End
  242. RefreshTitle()
  243. End
  244. Field linetool:Bool=False
  245. Field history:=New Vec2f[4]
  246. Field recentMouseEvent:MouseEvent
  247. Method DrawMode()
  248. appState=AppState.Draw
  249. End
  250. Method OnMouseEvent(event:MouseEvent ) Override
  251. If appState=AppState.Title
  252. If event.Type=EventType.MouseDown
  253. DrawMode()
  254. Endif
  255. Return
  256. Endif
  257. If event=Null Return
  258. Local mx:Int=event.Location.X
  259. Local my:Int=event.Location.Y
  260. Local b:Int=event.Button
  261. mx=(mx-cx)*zoom
  262. my=(my-cy)*zoom
  263. Local x:=-Cos(rot)*mx+Sin(rot)*my
  264. Local y:=-Sin(rot)*mx-Cos(rot)*my
  265. Local w:Int
  266. If recentMouseEvent<>event w=event.Wheel.Y
  267. If mousex=x And mousey=y And mousew=w Return
  268. recentMouseEvent = event
  269. Select event.Type
  270. Case EventType.MouseWheel
  271. zoom-=w/8.0
  272. If zoom<1.0/8 zoom=1.0/8
  273. Case EventType.MouseDown
  274. pane.EndSegment()
  275. Case EventType.MouseMove
  276. history[0]=history[1]
  277. history[1]=history[2]
  278. history[2]=history[3]
  279. history[3]=New Vec2f(x,y)
  280. End
  281. If linetool
  282. If drawcount
  283. pane.FatLine(mousex,mousey,x,y,radius)
  284. Endif
  285. Else
  286. If drawcount>2 And Not b
  287. ' pane.FatCurve(mx[0],my[0],mx[1],my[1],mx[2],my[2],mx[3],my[3])
  288. pane.OpenCurve(history[0],history[1],history[2],history[3],radius)
  289. Endif
  290. Endif
  291. drawcount+=1
  292. mousex=x
  293. mousey=y
  294. mousew=w
  295. mousecount+=1
  296. End
  297. End
  298. Function Main()
  299. Print title
  300. instance = New AppInstance
  301. New VPaint(title)
  302. App.Run()
  303. End
  304. Function SaveTGA(path:String, pixmap:Pixmap)
  305. Local stream:=FileStream.Open(path,"w")
  306. Local buffer:=New Byte[18]
  307. Local w:=pixmap.Width
  308. Local h:=pixmap.Height
  309. buffer[2]=2
  310. buffer[12]=w & 255
  311. buffer[13]=w Shr 8
  312. buffer[14]=h & 255
  313. buffer[15]=h Shr 8
  314. buffer[16]=32
  315. buffer[17]=8
  316. stream.Write(Varptr buffer[0],18)
  317. stream.Write(pixmap.Data,w*h*4)
  318. stream.Close()
  319. End Function