sprite.lua 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. local eapi = select(1,...) --The editor library is provided as an argument
  2. local se = {} --Sprite Editor
  3. local imgw, imgh = 8, 8 --The sprite size (MUST NOT CHANGE)
  4. local fw, fh = fontSize() --A font character size
  5. local swidth, sheight = screenSize() --The screen size
  6. local sheetW, sheetH = math.floor(swidth/imgw), math.floor(sheight/imgh) --The size of the spritessheet in cells (sprites)
  7. local bankH = sheetH/4 --The height of each bank in cells (sprites)
  8. local bsizeH = bankH*imgh --The height of each bank in pixels
  9. local sizeW, sizeH = sheetW*imgw, sheetH*imgh --The size of the spritessheet in pixels
  10. se.SpriteMap = SpriteSheet(imagedata(sizeW,sizeH):image(),sheetW,sheetH) --The spritemap
  11. local mflag = false
  12. local flagsData = "" --A string contain each flag (byte) as a char
  13. for i=1, sheetW*sheetH do flagsData = flagsData..string.char(0) end
  14. --[[The configuration tables scheme:
  15. draw: spriteID, x,y, w,h, spritesheet| OR: x,y, 0, w,h (marked by IMG_DRAW)
  16. rect: x,y, w,h, isline, colorid
  17. grid: gridX,gridY, gridW,gridH, cellW, cellH
  18. slider: x,y, steps, vertical, icon
  19. ]]
  20. --SpriteSheet Sprite Selection--
  21. local sprsrecto = {0,sheight-(8+bsizeH+1+1), swidth,bsizeH+2, false, 0} --SpriteSheet Outline Rect
  22. local sprsdraw = {0,sheight-(8+bsizeH+1), 0, 1,1} --SpriteSheet Draw Location; IMG_DRAW
  23. local sprsgrid = {sprsdraw[1],sprsdraw[2], sizeW,bsizeH, sheetW,bankH} --The SpriteSheet selection grid
  24. local sprssrect = {sprsrecto[1]-1,sprsrecto[2], imgw+2,imgh+2, true, 7} --SpriteSheet Select Rect (that white box on the selected sprite)
  25. local sprsbanksgrid = {swidth-(4*8+2),sprsrecto[2]-8, 8*4,8, 4,1} --The grid of banks selection buttons
  26. local sprsid = 1 --Selected Sprite ID
  27. local sprsmflag = false --Sprite selection mouse flag
  28. local sprsbquads = {} --SpriteSheets 4 BanksQuads
  29. local sprsbank = 1 --Current Selected Bank
  30. for i = 1, 4 do --Create the banks quads
  31. sprsbquads[i] = se.SpriteMap:image():quad(0,(i*bsizeH-bsizeH),sizeW,bsizeH)
  32. end
  33. local maxSpriteIDCells = tostring(sheetW*sheetH):len() --The number of digits in the biggest sprite id.
  34. local sprsidrect = {sprsbanksgrid[1]-(1+maxSpriteIDCells*(fw+1)+3),sprsbanksgrid[2], 1+maxSpriteIDCells*(fw+1),fh+2, false, 6, 13} --The rect of sprite id; The extra argument is the color of number print
  35. local revdraw = {sprsidrect[1]-(imgw+1),sprsrecto[2]-(imgh+1), imgw, imgh} --The small image at the right of the id with the actual sprite size
  36. --The current sprite flags--
  37. local flagsgrid = {swidth-(8*7+1),revdraw[2]-8-1, 8*7,6, 8,1} --The sprite flags grid
  38. local flagsdraw = {flagsgrid[1]-1,flagsgrid[2]-1} --The position of the first (leftmost) flag
  39. --Tools Selection--
  40. local toolsdraw = {104, 2,revdraw[2]-1, 5,1, 1,1,false, eapi.editorsheet} --Tools draw arguments
  41. local toolsgrid = {toolsdraw[2],toolsdraw[3], toolsdraw[4]*8,toolsdraw[5]*8, toolsdraw[4],toolsdraw[5]} --Tools Selection Grid
  42. local stool = 1 --Current selected tool id
  43. local tbtimer = 0 --Tool selection blink timer
  44. local tbtime = 0.1125 --The blink time
  45. local tbflag = false --Is the blink timer activated ?
  46. --Transformations Selection--
  47. local transdraw = {109, toolsdraw[2] + toolsdraw[4]*8 + 3,toolsdraw[3], 5,1, 1,1,false, eapi.editorsheet} --Transformations draw arguments
  48. local transgrid = {transdraw[2],transdraw[3], transdraw[4]*8, transdraw[5]*8, transdraw[4], transdraw[5]} --Transformations Selection Grid
  49. local strans --Selected Transformation
  50. local transtimer --The transformation blink timer
  51. local transtime = 0.1125 --The blink time
  52. --The Sprite (That you are editing--
  53. --Temp is a variables used to hold values while calculating positions
  54. local psize = 8--Zoomed pixel size
  55. local imgdraw = {2,8+2, 0, psize,psize} --Image Location; IMG_DRAW
  56. local imgrecto = {imgdraw[1]-1,imgdraw[2]-1,psize*imgw+2,psize*imgh+2, false,0} --The image outline rect position
  57. local imggrid = {imgdraw[1],imgdraw[2], psize*imgw,psize*imgh, imgw,imgh} --The image drawing grid
  58. local imgquad = se.SpriteMap.img:quad(0,0,imgw,imgh) --The sprite quad
  59. --The Color Selection Pallete--
  60. temp = {col=-1,height=flagsdraw[2]-(8+3+3)} --Temporary Variable
  61. local palpsize = math.floor(temp.height/4) --The size of each color box in the color selection pallete
  62. local palimg = imagedata(4,4):map(function() temp.col = temp.col + 1 return temp.col end ):image() --The image of the color selection pallete
  63. local palrecto = {swidth-(palpsize*4+3+1),8+3-1, palpsize*4+2,palpsize*4+2, false, 0} --The outline rectangle of the color selection pallete
  64. local paldraw = {palrecto[1]+1,palrecto[2]+1,0,palpsize,palpsize} --The color selection pallete draw arguments; IMG_DRAW
  65. local palgrid = {paldraw[1],paldraw[2],palpsize*4,palpsize*4,4,4} --The color selection pallete grid
  66. local colsrectL = {palrecto[1],palrecto[2],palpsize+2,palpsize+2, true, 7} --The color select box for the left mouse button (The black one)
  67. local colsrectR = {paldraw[1],paldraw[2],palpsize,palpsize, true, 0} --The color select box for the right mouse button (The white one)
  68. local colsL = 0 --Selected Color for the left mouse
  69. local colsR = 0 --Selected Color for the right mouse
  70. --Zoom Slider--
  71. local zoom = 1 --The current zoom level
  72. local zscale = 1 --The current zoom scaling factor
  73. local zflag = "none" --Zoom mouse flag
  74. local zslider = {(transdraw[2] + transdraw[4]*8 + revdraw[1])/2 - (4*8)/2, transdraw[3]+1, 3, false, 186} --The Zoom Slider Draw
  75. local zgrid = {zslider[1]+8,zslider[2]+2,8*zslider[3],4,zslider[3],1} --The Zoom Slider Mouse Grid
  76. --Size Slider
  77. local size = 1 --The current zoom level
  78. local sscale = 1 --The current zoom scaling factor
  79. local sflag = "none" --Zoom mouse flag
  80. local sslider = {(imgrecto[1]+imgrecto[3]+palrecto[1])/2 - (8*5)/2, paldraw[2], 4, false, 120} --The Size Slider Draw
  81. local sgrid = {sslider[1]+8,sslider[2]+2,8*sslider[3],4,sslider[3],1} --The Size Slider Mouse Grid
  82. local sizes = {1,2,3,5} --Brush sizes
  83. --The tools code--
  84. local toolshold = {true,true,false,false,false} --Is it a button (Clone, Stamp, Delete) or a tool (Pencil, fill)
  85. local tools = {
  86. function(self,cx,cy,b) --Pencil (Default)
  87. local data = self.SpriteMap:data()
  88. local qx,qy = self.SpriteMap:rect(sprsid)
  89. local col = (b == 2) and colsR or colsL
  90. local s = sizes[size]
  91. for x=-math.floor(s/2),math.ceil(s/2-1) do
  92. for y=-math.floor(s/2),math.ceil(s/2-1) do
  93. if cx+x >= 1 and cx+x <= 8*zscale and cy+y >= 1 and cy+y <= 8*zscale then
  94. data:setPixel(qx+cx-1+x,qy+cy-1+y,col)
  95. end
  96. end
  97. end
  98. self.SpriteMap.img = data:image()
  99. end,
  100. function(self,cx,cy,b) --Fill (Bucket)
  101. local data = self.SpriteMap:data()
  102. local qx,qy = self.SpriteMap:rect(sprsid)
  103. local col = (b == 2) and colsR or colsL
  104. local size = 8*zscale - 1
  105. ImageUtils.queuedFill(data, qx+cx-1,qy+cy-1, col, qx,qy, qx+size,qy+size)
  106. self.SpriteMap.img = data:image()
  107. end,
  108. function(self) --Clone (Copy)
  109. self:copy()
  110. end,
  111. function(self) --Stamp (Paste)
  112. self:paste()
  113. end,
  114. function(self) --Delete (Erase)
  115. local data = self.SpriteMap:data()
  116. local qx,qy = self.SpriteMap:rect(sprsid)
  117. local size = 8*zscale - 1
  118. for px = 0, size do for py = 0, size do
  119. data:setPixel(qx+px,qy+py,0)
  120. end end
  121. self.SpriteMap.img = data:image()
  122. _systemMessage("DELETED SPRITE "..sprsid, 2)
  123. end
  124. }
  125. local function extractSprite()
  126. local quadx, quady, quadw, quadh = imgquad:getViewport()
  127. return imagedata(quadw, quadh):paste(se.SpriteMap.img:data(),0,0,quadx,quady,quadw,quadh)
  128. end
  129. --The transformations code--
  130. local transformations = {
  131. function(x,y,c,w,h) return h-y-1,x end, --Rotate right
  132. function(x,y,c,w,h) return y, w-x-1 end, --Rotate left
  133. function(x,y,c,w,h) return w-x-1,y end, --Flip horizental
  134. function(x,y,c,w,h) return x,h-y-1 end, --Flip vertical
  135. function(x,y,c,w,h) return w-x-1,h-y-1 end --Flip horizentaly + verticaly
  136. }
  137. local function transform(tnum)
  138. local tfunc = transformations[tnum]; transtimer, strans = 0, tnum
  139. local current = extractSprite()
  140. local new = imagedata(current:width(),current:height())
  141. current:map(function(x,y,c)
  142. local nx,ny,nc = tfunc(x,y,c,current:width(),current:height())
  143. new:setPixel(nx or x,ny or y,nc or c)
  144. end)
  145. local x,y = se.SpriteMap:rect(sprsid)
  146. local data = se.SpriteMap:data()
  147. data:paste(new,x,y)
  148. se.SpriteMap.img = data:image()
  149. se:redrawSPRS() se:redrawSPR() se:redrawTOOLS()
  150. end
  151. local function drawSlider(pos,x,y,steps,vertical,icon)
  152. palt(0,false)
  153. pos = math.floor(pos)
  154. if icon then eapi.editorsheet:draw(icon,x,y) end
  155. if vertical then
  156. else
  157. for sx=1,steps do
  158. local sprite = 188
  159. if sx == 1 then sprite = 187 elseif sx == steps then sprite = 189 end
  160. eapi.editorsheet:draw(sprite,x+sx*8,y)
  161. end
  162. palt()
  163. eapi.editorsheet:draw(185,x+pos*8,y)
  164. end
  165. end
  166. function se:entered()
  167. eapi:drawUI()
  168. self:_redraw()
  169. end
  170. function se:leaved()
  171. end
  172. function se:getSheet()
  173. return self.SpriteMap
  174. end
  175. function se:getFlags()
  176. return flagsData
  177. end
  178. function se:exportImage()
  179. return self.SpriteMap:data():encode()
  180. end
  181. function se:exportFlags()
  182. local fdata = ""
  183. for char in string.gmatch(flagsData,".") do
  184. fdata = fdata..";"..string.format("%X",string.byte(char))
  185. end
  186. return fdata
  187. end
  188. function se:export(imageonly)
  189. local data = self:exportImage()
  190. if imageonly then return data else
  191. local fdata = self:exportFlags()
  192. return data.."\n"..fdata
  193. end
  194. end
  195. function se:encode()
  196. return BinUtils.imgToBin(self.SpriteMap:data())..flagsData
  197. end
  198. function se:import(data)
  199. if data then
  200. data = data:gsub("\n","")
  201. local w,h,imgdata, fdata = string.match(data,"LK12;GPUIMG;(%d+)x(%d+);(.-);(.+)")
  202. flagsData, fdata = "", ";"..fdata:gsub(";",";;")..";"
  203. for flag in fdata:gmatch(";(%x+);") do
  204. flagsData = flagsData..string.char(tonumber(flag,16))
  205. end
  206. if flagsData:len() < sheetW*sheetH then
  207. local missing = sheetW*sheetH - flagsData:len()
  208. local zerochar = string.char(0)
  209. for i=1,missing do
  210. flagsData = flagsData..zerochar
  211. end
  212. end
  213. imgdata = imgdata:sub(0,w*h)
  214. imgdata = "LK12;GPUIMG;"..w.."x"..h..";"..imgdata
  215. self.SpriteMap = SpriteSheet(imagedata(imgdata):image(),sheetW,sheetH)
  216. else
  217. local flagsData = ""
  218. for i=1, sheetW*sheetH do flagsData = flagsData..string.char(0) end
  219. self.SpriteMap = SpriteSheet(imagedata(sizeW,sizeH):image(),sheetW,sheetH)
  220. end
  221. end
  222. function se:decode(data)
  223. local imgbin = data:sub(1,(swidth*sheight)/2)
  224. flagsData = data:sub((swidth*sheight)/2+1,-1)
  225. BinUtils.binToImg(self.SpriteMap:data(),imgbin)
  226. self.SpriteMap:image():refresh()
  227. end
  228. function se:copy()
  229. local headerlen = 15 + (tostring(8*zscale):len()*2)
  230. clipboard(string.lower(extractSprite():encode():gsub("\n",""):sub(headerlen,-1)))
  231. _systemMessage("COPIED SPRITE "..sprsid,2)
  232. end
  233. function se:paste()
  234. local ok, err = pcall(function()
  235. local dx,dy,dw,dh = self.SpriteMap:rect(sprsid)
  236. local sheetdata = self.SpriteMap:data()
  237. local data = clipboard()
  238. if data:sub(1,5) == "[gfx]" then -- PICO-8 Paste
  239. data = data:sub(6,-7) --Remove the start and end tags
  240. local width = tonumber(data:sub(1,2),16)
  241. local height = tonumber(data:sub(3,4),16)
  242. data = string.upper(data:sub(5,-1))
  243. data = "LK12;GPUIMG;" .. width.."x"..height ..";".. string.upper(data)
  244. else
  245. data = data:gsub("%X","")
  246. local size = math.sqrt(data:len())
  247. if math.floor(size) ~= size then error("Invalid Data") end
  248. if size == 0 then error("Empty Data") end
  249. if size < 8 then error("Too small to paste") end
  250. data = "LK12;GPUIMG;" .. size.."x"..size ..";".. string.upper(data)
  251. end
  252. local sprdata = imagedata(data)
  253. sheetdata:paste(sprdata,dx,dy)
  254. self.SpriteMap.img = sheetdata:image()
  255. self:_redraw()
  256. end)
  257. if not ok then
  258. _systemMessage("PASTE ERR: "..(err or "nil"),5)
  259. cprint("PASTE ERR: "..(err or "nil"))
  260. else
  261. _systemMessage("PASTED TO SPRITE "..sprsid,2)
  262. end
  263. end
  264. --Redraw color pallete
  265. function se:redrawCP()
  266. rect(palrecto)
  267. palimg:draw(unpack(paldraw))
  268. rect(colsrectR)
  269. rect(colsrectL)
  270. end
  271. --Redraw sprite selection
  272. function se:redrawSPRS() _ = nil
  273. rect(sprsrecto)
  274. self.SpriteMap:image():draw(sprsdraw[1],sprsdraw[2], sprsdraw[3], sprsdraw[4],sprsdraw[5], sprsbquads[sprsbank])
  275. clip(sprsrecto) rect(sprssrect) clip()
  276. rect(sprsidrect)
  277. color(sprsidrect[7])
  278. local id = ""; for i=1, maxSpriteIDCells-(tostring(sprsid):len()) do id = id .. "0" end; id = id .. tostring(sprsid)
  279. print(id,sprsidrect[1]+1,sprsidrect[2]+1)
  280. SpriteGroup(97,sprsbanksgrid[1],sprsbanksgrid[2],sprsbanksgrid[5],sprsbanksgrid[6],1,1,false,eapi.editorsheet)
  281. eapi.editorsheet:draw(sprsbank+72,sprsbanksgrid[1]+(sprsbank-1)*8,sprsbanksgrid[2])
  282. end
  283. --Redraw the sprite editing rectangle
  284. function se:redrawSPR()
  285. rect(imgrecto)
  286. self.SpriteMap:image():draw(imgdraw[1],imgdraw[2],imgdraw[3],imgdraw[4],imgdraw[5],imgquad)
  287. rect(revdraw[1],revdraw[2], revdraw[3],revdraw[4] ,false,0)
  288. self.SpriteMap:image():draw(revdraw[1],revdraw[2], 0, 1,1, self.SpriteMap:quad(sprsid))
  289. end
  290. --Redraw the zooming slider
  291. function se:redrawZSlider()
  292. drawSlider(zoom,unpack(zslider))
  293. end
  294. --Redraw the size slider
  295. function se:redrawSSlider()
  296. sslider[5] = 120 + size
  297. drawSlider(size,unpack(sslider))
  298. end
  299. --Redraw the tools selection bar
  300. function se:redrawTOOLS()
  301. --Tools
  302. SpriteGroup(unpack(toolsdraw))
  303. eapi.editorsheet:draw((toolsdraw[1]+(stool-1))-24, toolsdraw[2]+(stool-1)*8,toolsdraw[3], 0, toolsdraw[6],toolsdraw[7])
  304. --Transformations
  305. SpriteGroup(unpack(transdraw))
  306. if strans then eapi.editorsheet:draw((transdraw[1]+(strans-1))-24, transdraw[2]+(strans-1)*8,transdraw[3], 0, transdraw[6],transdraw[7]) end
  307. end
  308. --Redraw the flag byte circles
  309. function se:redrawFLAG()
  310. local flags = string.byte(flagsData:sub(sprsid,sprsid))
  311. for i=1,8 do --Bit number
  312. if bit.band(bit.rshift(flags,i-1),1) == 1 then
  313. eapi.editorsheet:draw(125+i,flagsdraw[1]+(i-1)*7,flagsdraw[2]) --It's ON
  314. else
  315. eapi.editorsheet:draw(125,flagsdraw[1]+(i-1)*7,flagsdraw[2])--It's OFF
  316. end
  317. end
  318. end
  319. --Redraw all the screen
  320. function se:_redraw()
  321. self:redrawCP()
  322. self:redrawSPR()
  323. self:redrawSPRS()
  324. self:redrawZSlider()
  325. self:redrawSSlider()
  326. self:redrawFLAG()
  327. self:redrawTOOLS()
  328. end
  329. --Update some timers
  330. function se:update(dt)
  331. if tbflag then
  332. tbtimer = tbtimer + dt
  333. if tbtime <= tbtimer then
  334. stool = tbflag
  335. tbflag = false
  336. self:redrawTOOLS()
  337. end
  338. end
  339. if transtimer then
  340. transtimer = transtimer + dt
  341. if transtimer > transtime then
  342. transtimer, strans = nil, nil
  343. self:redrawTOOLS()
  344. end
  345. end
  346. end
  347. function se:updateZoom()
  348. zscale = 2^(zoom-1)
  349. --Update the selection box size
  350. sprssrect[3] = zscale*8 + 2
  351. sprssrect[4] = zscale*8 + 2
  352. --Update the selection box position
  353. local cx, cy = (sprssrect[1]+1)/8 +1, (sprssrect[2]-sprsrecto[2])/8 +1
  354. cx, cy = math.min(cx-1,sprsgrid[5]-zscale), math.min(cy-1,sprsgrid[6]-zscale)
  355. sprsid = cy*sheetW+cx+1+(sprsbank*sheetW*bankH-sheetW*bankH)
  356. sprssrect[1] = cx*8-1
  357. sprssrect[2] = sprsrecto[2]+cy*8
  358. --Update the quad
  359. imgquad:setViewport(cx*8,cy*8 + (sprsbank-1)*bsizeH,imgw*zscale,imgh*zscale)
  360. --Update the drawing box
  361. imgdraw[4], imgdraw[5] = psize/zscale, psize/zscale
  362. imggrid[5], imggrid[6] = imgw*zscale, imgh*zscale
  363. end
  364. --Mouse function of ImageDrawing
  365. function se:mouseImageDrawing(x,y,b,it,state)
  366. if state ~= "hover" then
  367. local cx, cy = whereInGrid(x,y,imggrid)
  368. if cx then
  369. if (not it) and state == "pressed" then mflag = true end
  370. tools[stool](self,cx,cy,b)
  371. self:redrawSPR() self:redrawSPRS()
  372. end
  373. end
  374. --Cursor
  375. if true then
  376. if whereInGrid(x,y,imggrid) and stool < 3 then
  377. if stool == 1 then
  378. if isKDown("lshift","rshift") or isMDown(2) then
  379. cursor("eraser")
  380. else
  381. cursor("pencil")
  382. end
  383. elseif stool == 2 then
  384. cursor("bucket")
  385. end
  386. else
  387. local cur = cursor()
  388. if cur == "pencil" or cur == "bucket" or cur == "eraser" then cursor("normal") end
  389. end
  390. end
  391. end
  392. function se:mouseSpriteSelection(x,y,b,it,state)
  393. local cx, cy = whereInGrid(x,y,sprsgrid)
  394. if cx then
  395. local cx, cy = math.min(cx-1,sprsgrid[5]-zscale), math.min(cy-1,sprsgrid[6]-zscale)
  396. sprsid = cy*sheetW+cx+1+(sprsbank*sheetW*bankH-sheetW*bankH)
  397. sprssrect[1] = cx*8 -1
  398. sprssrect[2] = sprsrecto[2]+cy*8
  399. imgquad:setViewport(cx*8,cy*8 + (sprsbank-1)*bsizeH,imgw*zscale,imgh*zscale)
  400. self:redrawSPRS() self:redrawSPR() self:redrawFLAG()
  401. if state == "pressed" then sprsmflag = true end
  402. end
  403. end
  404. function se:mouseZoomSlider(x,y,b,it,state)
  405. local cx, cy = whereInGrid(x,y,zgrid)
  406. if state == "pressed" then
  407. if cx then
  408. zflag = "down"
  409. zoom = cx; self:updateZoom()
  410. cursor("handpress")
  411. self:redrawSPRS() self:redrawSPR() self:redrawFLAG() self:redrawZSlider()
  412. end
  413. elseif state == "moved" then
  414. if cx then
  415. if zflag == "down" then
  416. zoom = cx; self:updateZoom()
  417. self:redrawSPRS() self:redrawSPR() self:redrawFLAG() self:redrawZSlider()
  418. else
  419. zflag = "hover"
  420. cursor("handrelease")
  421. end
  422. elseif zflag == "hover" then
  423. cursor("normal")
  424. zflag = "none"
  425. end
  426. elseif state == "released" then
  427. if cx then
  428. if zflag == "down" then
  429. zoom = cx; self:updateZoom()
  430. zflag = "hover"
  431. cursor("handrelease")
  432. self:redrawSPRS() self:redrawSPR() self:redrawFLAG() self:redrawZSlider()
  433. else
  434. zflag = "hover"
  435. cursor("handrelease")
  436. end
  437. elseif zflag ~= "none" then
  438. cursor("normal")
  439. zflag = "none"
  440. end
  441. end
  442. end
  443. function se:mouseSizeSlider(x,y,b,it,state)
  444. local cx, cy = whereInGrid(x,y,sgrid)
  445. if state == "pressed" then
  446. if cx then
  447. sflag = "down"
  448. size = cx; self:updateZoom()
  449. cursor("handpress")
  450. self:redrawSPRS() self:redrawSPR() self:redrawFLAG() self:redrawSSlider()
  451. end
  452. elseif state == "moved" then
  453. if cx then
  454. if sflag == "down" then
  455. size = cx; self:updateZoom()
  456. self:redrawSPRS() self:redrawSPR() self:redrawFLAG() self:redrawSSlider()
  457. else
  458. sflag = "hover"
  459. cursor("handrelease")
  460. end
  461. elseif sflag == "hover" then
  462. cursor("normal")
  463. sflag = "none"
  464. end
  465. elseif state == "released" then
  466. if cx then
  467. if sflag == "down" then
  468. size = cx; self:updateZoom()
  469. sflag = "hover"
  470. cursor("handrelease")
  471. self:redrawSPRS() self:redrawSPR() self:redrawFLAG() self:redrawSSlider()
  472. else
  473. sflag = "hover"
  474. cursor("handrelease")
  475. end
  476. elseif sflag ~= "none" then
  477. cursor("normal")
  478. sflag = "none"
  479. end
  480. end
  481. end
  482. function se:mousepressed(x,y,b,it)
  483. if isKDown("lshift","rshift") or isMDown(2) then b = 2 end
  484. --Pallete Color Selection (Only in mousepressed)
  485. local cx, cy = whereInGrid(x,y,palgrid)
  486. if cx then
  487. if b == 1 then
  488. colsL = ((cy-1)*4+cx)-1
  489. local cx, cy = cx-1, cy-1
  490. colsrectL[1] = palrecto[1] + cx*palpsize
  491. colsrectL[2] = palrecto[2] + cy*palpsize
  492. elseif b == 2 then
  493. colsR = ((cy-1)*4+cx)-1
  494. local cx, cy = cx-1, cy-1
  495. colsrectR[1] = paldraw[1] + cx*palpsize
  496. colsrectR[2] = paldraw[2] + cy*palpsize
  497. end
  498. self:redrawCP()
  499. end
  500. --Bank selection (Only in mousepressed)
  501. local cx = whereInGrid(x,y,sprsbanksgrid)
  502. if cx then
  503. sprsbank = cx
  504. local idbank = math.floor((sprsid-1)/(sheetW*bankH))+1
  505. if idbank > sprsbank then sprsid = sprsid-(idbank-sprsbank)*sheetW*bankH elseif sprsbank > idbank then sprsid = sprsid+(sprsbank-idbank)*sheetW*bankH end
  506. self:updateZoom() self:redrawSPRS() self:redrawSPR() self:redrawFLAG()
  507. end
  508. --Tool Selection (Only in mousepressed)
  509. local cx, cy = whereInGrid(x,y,toolsgrid)
  510. if cx then
  511. if toolshold[cx] then
  512. stool = cx
  513. self:redrawTOOLS()
  514. self:redrawSPRS() self:redrawSPR()
  515. else
  516. tools[cx](self)
  517. tbflag, tbtimer = stool, 0
  518. stool = cx
  519. self:redrawSPRS() self:redrawSPR() self:redrawTOOLS()
  520. end
  521. end
  522. --Transformation Selection (Only in mousepressed)
  523. local cx, cy = whereInGrid(x,y,transgrid)
  524. if cx and transformations[cx] then
  525. transform(cx)
  526. end
  527. --Setting Flags (Only in mousepressed)
  528. local cx, cy = whereInGrid(x,y,flagsgrid)
  529. if cx then
  530. local flags = string.byte(flagsData:sub(sprsid))
  531. flags = bit.bxor(flags,bit.lshift(1,cx-1))
  532. flagsData = flagsData:sub(0,sprsid-1)..string.char(flags)..flagsData:sub(sprsid+1,-1)
  533. self:redrawFLAG()
  534. end
  535. --Zoom Slider
  536. self:mouseZoomSlider(x,y,b,it,"pressed")
  537. --Size Slider
  538. self:mouseSizeSlider(x,y,b,it,"pressed")
  539. --Sprite Selection
  540. self:mouseSpriteSelection(x,y,b,it,"pressed")
  541. --Image Drawing
  542. self:mouseImageDrawing(x,y,b,it,"pressed")
  543. end
  544. function se:mousemoved(x,y,dx,dy,it)
  545. local b = 1; if isKDown("lshift","rshift") or isMDown(2) then b = 2 end
  546. --Image Drawing
  547. if (not it and mflag) or it then
  548. self:mouseImageDrawing(x,y,b,it,"moved")
  549. else --For the cursor to update
  550. self:mouseImageDrawing(x,y,b,it,"hover")
  551. end
  552. --Sprite Selection
  553. if (not it and sprsmflag) or it then
  554. self:mouseSpriteSelection(x,y,b,it,"moved")
  555. end
  556. --Zoom Slider
  557. self:mouseZoomSlider(x,y,b,it,"moved")
  558. --Size Slider
  559. self:mouseSizeSlider(x,y,b,it,"moved")
  560. end
  561. function se:mousereleased(x,y,b,it)
  562. if isKDown("lshift","rshift") then b = 2 end
  563. --Image Drawing
  564. if (not it and mflag) or it then
  565. self:mouseImageDrawing(x,y,b,it,"released")
  566. end
  567. mflag = false
  568. --Sprite Selection
  569. if (not it and sprsmflag) or it then
  570. self:mouseSpriteSelection(x,y,b,it,"released")
  571. end
  572. sprsmflag = false
  573. --Zoom Slider
  574. self:mouseZoomSlider(x,y,b,it,"released")
  575. --Size Slider
  576. self:mouseSizeSlider(x,y,b,it,"released")
  577. end
  578. function se:keypressed(key,sc)
  579. --Palette Switching
  580. if sc == "q" or sc == "e" then
  581. if isKDown("lshift","rshift") then
  582. if sc == "e" then
  583. colsR = colsR + 1
  584. if colsR > 15 then colsR = 0 end
  585. else
  586. colsR = colsR - 1
  587. if colsR < 0 then colsR = 15 end
  588. end
  589. local cx = colsR % 4
  590. local cy = math.floor(colsR/4)
  591. colsrectR[1] = paldraw[1] + cx*palpsize
  592. colsrectR[2] = paldraw[2] + cy*palpsize
  593. else
  594. if sc == "e" then
  595. colsL = colsL + 1
  596. if colsL > 15 then colsL = 0 end
  597. else
  598. colsL = colsL - 1
  599. if colsL < 0 then colsL = 15 end
  600. end
  601. local cx = colsL % 4
  602. local cy = math.floor(colsL/4)
  603. colsrectL[1] = palrecto[1] + cx*palpsize
  604. colsrectL[2] = palrecto[2] + cy*palpsize
  605. end
  606. self:redrawCP()
  607. elseif sc == "w" or sc == "a" or sc == "s" or sc == "d" then
  608. local function setBank(bank)
  609. local idbank = math.floor((sprsid-1)/(sheetW*bankH))+1
  610. sprsbank = bank
  611. if idbank > sprsbank then
  612. sprsid = sprsid-(idbank-sprsbank)*sheetW*bankH
  613. elseif sprsbank > idbank then
  614. sprsid = sprsid+(sprsbank-idbank)*sheetW*bankH
  615. end
  616. end
  617. --Update the selection box position
  618. local cx, cy = (sprssrect[1]+1)/8, (sprssrect[2]-sprsrecto[2])/8
  619. if sc == "a" then --Left
  620. cx = cx - zscale
  621. elseif sc == "d" then --Right
  622. cx = cx + zscale
  623. elseif sc == "w" then --Up
  624. cy = cy - zscale
  625. elseif sc == "s" then --Down
  626. cy = cy + zscale
  627. end
  628. if cx < 0 then cx, cy = ((cy == 0 and sprsbank == 1) and 0 or sheetW-1), cy-zscale elseif cx >= sheetW then cx, cy = ((cy == bankH-zscale and sprsbank == 4) and sheetW-1 or 0), cy+zscale end
  629. if cy < 0 then
  630. if sprsbank > 1 then
  631. setBank(sprsbank-1)
  632. cy = bankH-1
  633. else
  634. cy = 0
  635. end
  636. elseif cy > bankH-1 then
  637. if sprsbank < 4 then
  638. setBank(sprsbank+1)
  639. cy = 0
  640. else
  641. cy = bankH-1
  642. end
  643. end
  644. cx, cy = math.min(cx,sprsgrid[5]-zscale), math.min(cy,sprsgrid[6]-zscale)
  645. sprsid = cy*sheetW+cx+1+(sprsbank*sheetW*bankH-sheetW*bankH)
  646. sprssrect[1] = cx*8-1
  647. sprssrect[2] = sprsrecto[2]+cy*8
  648. imgquad:setViewport(cx*8,cy*8 + (sprsbank-1)*bsizeH,imgw*zscale,imgh*zscale)
  649. self:redrawSPRS() self:redrawSPR()
  650. end
  651. end
  652. local bank = function(bank)
  653. return function()
  654. local idbank = math.floor((sprsid-1)/(sheetW*bankH))+1
  655. sprsbank = bank
  656. if idbank > sprsbank then
  657. sprsid = sprsid-(idbank-sprsbank)*sheetW*bankH
  658. elseif sprsbank > idbank then
  659. sprsid = sprsid+(sprsbank-idbank)*sheetW*bankH
  660. end
  661. se:redrawSPRS() se:redrawSPR()
  662. end
  663. end
  664. se.keymap = {
  665. ["ctrl-c"] = se.copy,
  666. ["ctrl-v"] = se.paste,
  667. ["1"] = bank(1), ["2"] = bank(2), ["3"] = bank(3), ["4"] = bank(4),
  668. ["z"] = function() stool=1 se:redrawTOOLS() end,
  669. ["x"] = function() stool=2 se:redrawTOOLS() end,
  670. ["delete"] = function() tools[5](se) se:redrawSPRS() se:redrawSPR() end,
  671. --Transformations
  672. ["r"] = function() transform(1) end,
  673. ["shift-r"] = function() transform(2) end,
  674. ["f"] = function() transform(3) end,
  675. ["shift-f"] = function() transform(4) end,
  676. ["i"] = function() transform(5) end
  677. }
  678. return se