honeylisp/editor/screenedit.fnl

97 lines
3.8 KiB
Fennel

(local GraphicsEditView (require :editor.gfxedit))
(local util (require :lib.util))
(local lume (require :lib.lume))
(local style (require :core.style))
(local {: char-to-sprite : scanline-to-sprite : screen-y-to-offset} (util.require :editor.tiledraw))
(local {: mouse-inside : activate : active? : checkbox : textfield : textbutton} (util.require :editor.imstate))
(local ScreenEditView (GraphicsEditView:extend))
(local screen-scale 4)
(local screenw 280)
(local screenh 192)
(fn ScreenEditView.new [self filename]
(ScreenEditView.super.new self)
(set self.screenfilename filename)
(set self.scanlines [])
(self:reload))
(fn gfxshift [byte offset]
(local pixels (bit.band (string.byte byte) 0x7f))
(local color (bit.band (string.byte byte) 0x80))
(bit.bor color
(if (> offset 0) (bit.band (bit.lshift pixels offset) 0x7f)
(bit.rshift pixels (- offset)))))
(fn brush-mask-at [brush xoffset y]
(values (gfxshift (brush.gfx:sub y y) xoffset) (gfxshift (brush.mask:sub y y) xoffset)))
(fn paint-byte [src brush mask]
(if (not= (bit.band mask 0x7f) 0)
(-> src
(bit.band (bit.bxor 0xff mask))
(bit.bor brush))
src))
(fn paint-byte-at [screen brush y xbyte xoffset yoffset]
(if (and (>= xbyte 0) (< xbyte 40) (>= y 0) (< y screenh))
(let [ibyte (+ (screen-y-to-offset y) xbyte)
srcbyte (screen:sub (+ ibyte 1) (+ ibyte 1))
painted (paint-byte (string.byte srcbyte) (brush-mask-at brush xoffset yoffset))]
(util.splice screen ibyte (string.char painted)))
screen))
(fn paint [screen brush x y]
(var result screen)
(for [row y (+ y 7)]
(local xbyte (math.floor (/ x 7)))
(local xoffset-left (% x 7))
(local xoffset-right (- xoffset-left 7))
(local yoffset (+ (- row y) 1))
(set result (paint-byte-at result brush row xbyte xoffset-left yoffset))
(set result (paint-byte-at result brush row (+ xbyte 1) xoffset-right yoffset)))
result)
(fn ScreenEditView.draw-screen-editor [self x y]
(local (w h) (values (* screenw screen-scale) (* screenh screen-scale)))
(activate self :screen x y w h)
(var screen self.screen)
(when (and self.itile (mouse-inside x y w h))
(local mx (math.floor (/ (- (love.mouse.getX) x) screen-scale)))
(local my (math.floor (/ (- (love.mouse.getY) y) screen-scale)))
(set screen (paint screen (. self.tilecache.tiles self.itile) (bit.band (- mx 3) 0xfffe) (- my 4)))
(when (active? self :screen) (set self.screen screen)))
(for [scany 0 (- screenh 1)]
(local scanline (or (. self.scanlines scany) {}))
(local ibyte (screen-y-to-offset scany))
(local linehash (screen:sub (+ ibyte 1) (+ ibyte 40)))
(when (not= scanline.linehash linehash)
(set scanline.linehash linehash)
(set scanline.sprite (scanline-to-sprite screen scany))
(tset self.scanlines scany scanline))
(love.graphics.draw scanline.sprite x (+ y (* scany screen-scale)) 0 screen-scale screen-scale)))
(fn ScreenEditView.reload [self]
(ScreenEditView.super.reload self)
(local (loaded screen) (pcall #(util.readjson self.screenfilename)))
(set self.screen
(if (not loaded) (string.rep "\0" 0x2000)
(screen:fromhex))))
(fn ScreenEditView.save [self]
(util.writejson self.screenfilename (self.screen:tohex)))
(fn ScreenEditView.draw [self]
(self:draw_background style.background)
(love.graphics.setColor 1 1 1 1)
(self:draw-screen-editor (+ self.position.x 10) (+ self.position.y 10))
(self:draw-tile-selector (+ self.position.x 10) (+ self.position.y 20 (* screenh screen-scale)) (- self.size.x 20)))
(fn ScreenEditView.filename [self] "editor/brushes.json")
(fn ScreenEditView.spritegen [self] char-to-sprite)
(fn ScreenEditView.tilesize [self] (values 8 8))
(fn ScreenEditView.get_name [self] (.. "Screen: " self.screenfilename))
ScreenEditView