move asciilib2 -> asciilib for naming clarity

This commit is contained in:
2021-07-31 22:09:27 -06:00
parent e36e05cf98
commit 72d54c39b4
36 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
package;
import kiss.Kiss;
import kiss.Prelude;
import asciilib.Surface;
@:build(kiss.Kiss.build())
class Main {}

View File

@@ -0,0 +1 @@
(print "Hello world!")

View File

@@ -0,0 +1,4 @@
package asciilib;
@:build(kiss.Kiss.build())
class Assets {}

View File

@@ -0,0 +1,12 @@
(defNew [&prop :AssetsBackend backend]
[:Map<String,Surface> _surfaces (new Map)])
// TODO don't allow overriding a key -- use a macro so all load___() calls check their maps first
(method loadSurface [key path]
(dictSet _surfaces key (Surface.fromString (backend.loadText path))))
// TODO runtime-assert that the key exists. Use a macro so all get___() calls check their maps first
(method getSurface [key]
(dictGet _surfaces key))
// TODO freeSurface() etc.

View File

@@ -0,0 +1,5 @@
package asciilib;
interface AssetsBackend {
function loadText(filePath:String):String;
}

View File

@@ -0,0 +1,15 @@
package asciilib;
import haxe.io.Bytes;
typedef Color = {
r:Int,
g:Int,
b:Int,
}
/**
* The Colors class represents a 2D grid of colors. Under the hood, it's byte channels
*/
@:build(kiss.Kiss.build())
class Colors {}

View File

@@ -0,0 +1,40 @@
(defNew [_width _height &opt :Color fillColor]
[:Int width _width
:Int height _height
:Int area (* width height)
:Bytes red (Bytes.alloc area)
:Bytes green (Bytes.alloc area)
:Bytes blue (Bytes.alloc area)]
(fill (or fillColor Black)))
(method fill [:Color color]
(red.fill 0 area color.r)
(green.fill 0 area color.g)
(blue.fill 0 area color.b))
(method _index [x y]
(+ x (* y width)))
(defmacro withIndex [idxName xName yName &body body]
`(let [,idxName (_index ,xName ,yName)]
,@body))
(method getPixel [x y]
(withIndex idx x y
(object r (red.get idx) g (green.get idx) b (blue.get idx))))
(method setPixel [x y color]
(withIndex idx x y
(red.set idx color.r)
(green.set idx color.g)
(blue.set idx color.b)))
(function equal [c1 c2]
(and (= c1.r c2.r) (= c1.g c2.g) (= c1.b c2.b)))
(var Black (object r 0 g 0 b 0))
(var Red (object r 255 g 0 b 0))
(var Green (object r 0 g 255 b 0))
(var Blue (object r 0 g 0 b 255))
(var White (object r 255 g 255 b 255))

View File

@@ -0,0 +1,4 @@
package asciilib;
@:build(kiss.Kiss.build())
class Game {}

View File

@@ -0,0 +1,25 @@
(defNew [title
width
height
letterWidth
letterHeight
_gameLogic
assetsBackend
_graphicsBackend]
// TODO the type annotation on this line feels like a bit much, but is necessary:
[:Graphics graphics (new Graphics width height)
:GameLogic gameLogic _gameLogic
:Assets assets (new Assets assetsBackend)
:GraphicsBackend graphicsBackend _graphicsBackend]
(graphicsBackend.initialize title width height letterWidth letterHeight)
(gameLogic.initialize assets))
(method update [:Float deltaSeconds]
(gameLogic.update this deltaSeconds))
(method draw []
(let [&mut changedGraphics false]
(gameLogic.draw (lambda [] (set changedGraphics true) graphics) assets)
(when changedGraphics (graphicsBackend.draw graphics))))

View File

@@ -0,0 +1,10 @@
package asciilib;
// Your game's logic is an interface contained in Game instead of a class that extends Game.
// This allows ASCIILib to support libraries like HaxeFlixel where your main class is expected
// to extend another class already.
interface GameLogic {
public function initialize(assets:Assets):Void;
public function update(game:Game, deltaSeconds:Float):Void;
public function draw(graphicsHandle:() -> Graphics, assets:Assets):Void;
}

View File

@@ -0,0 +1,4 @@
package asciilib;
@:build(kiss.Kiss.build())
class Graphics extends Surface {}

View File

@@ -0,0 +1,2 @@
(method new [width height]
(super width height))

View File

@@ -0,0 +1,6 @@
package asciilib;
interface GraphicsBackend {
function initialize(title:String, width:Int, height:Int, letterWidth:Int, letterHeight:Int):Void;
function draw(graphics:Graphics):Void;
}

View File

@@ -0,0 +1,4 @@
package asciilib;
@:build(kiss.Kiss.build())
class Grid<T> {}

View File

@@ -0,0 +1,7 @@
(defNew [_width _height :T defaultValue]
[:Int width _width
:Int height _height
:Array<Array<T>> rows (for _ (range height) (for _ (range width) defaultValue))])
(method getCell [x y] (nth (nth rows y) x))
(method setCell [x y value] (setNth (nth rows y) x value))

View File

@@ -0,0 +1,4 @@
package asciilib;
@:build(kiss.Kiss.build())
class Letters {}

View File

@@ -0,0 +1,13 @@
(defNew [_width _height &opt :String letter]
[:Int width _width
:Int height _height
:Array<String> rows (for _ (range height) (* (or letter " ") width))])
(method getChar [x y]
(.charAt (nth rows y) x))
(method setChar [x y char]
(let [row (nth rows y)
left (row.substr 0 x)
right (row.substr (+ x 1))]
(setNth rows y "${left}${char}${right}")))

View File

@@ -0,0 +1,13 @@
package asciilib;
import asciilib.Colors;
import kiss.Stream;
import haxe.ds.Option;
typedef Letter = {
char:String,
color:Color
};
@:build(kiss.Kiss.build())
class Surface {}

View File

@@ -0,0 +1,98 @@
(defNew [_width _height &opt :Color backgroundColor :String letter :Color letterColor]
[:Int width _width
:Int height _height
:Colors backgroundColors (new Colors width height (or backgroundColor Colors.Black))
:Letters letters (new Letters width height (or letter " "))
:Colors letterColors (new Colors width height (or letterColor Colors.White))
:Grid<Bool> opacity (new Grid width height true)
:Grid<String> specialInfo (new Grid width height "")])
(method getBackgroundColor [x y]
(backgroundColors.getPixel x y))
(method setBackgroundColor [x y color]
(backgroundColors.setPixel x y color))
(method getLetter [x y]
(object char (letters.getChar x y) color (letterColors.getPixel x y)))
(method setLetter [x y letter]
(letters.setChar x y letter.char)
(letterColors.setPixel x y letter.color))
(method isCellOpaque [x y]
(opacity.getCell x y))
(method setCellOpacity [x y value]
(opacity.setCell x y value))
(method getSpecialInfo [x y]
(specialInfo.getCell x y))
(method setSpecialInfo [x y value]
(specialInfo.setCell x y value))
// TODO rectangle type
// TODO optional source rectangle argument
(method blitSurface [:Surface surface x y]
(doFor [srcX destX] (the kiss.List<kiss.List<Int>> (zipDrop (range surface.width) (range x (+ x surface.width))))
(when (< -1 destX width)
(doFor [srcY destY] (the kiss.List<kiss.List<Int>> (zipDrop (range 0 surface.height) (range y (+ y surface.height))))
(when (< -1 destY height)
(when (surface.isCellOpaque srcX srcY)
(setBackgroundColor destX destY (surface.getBackgroundColor srcX srcY))
(setLetter destX destY (surface.getLetter srcX srcY))
(setSpecialInfo destX destY (surface.getSpecialInfo srcX srcY))
// Cover transparent cells in the lower surface with opaque ones
(setCellOpacity destX destY true)))))))
(function fromString [text]
(let [stream (Stream.fromString text)
:Map<String,Color> colors (new Map)
:Map<String,String> infoCodes (new Map)
:Map<String,Bool> opacityCodes [=>"0" false =>"1" true]]
(stream.dropString "COLORS\n")
(loop
(case (stream.takeLine)
((Some "INFO CODES") (break))
((Some colorLine)
(let [[symbol _r _g _b] (colorLine.split " ")]
(dictSet colors symbol (object r (Std.parseInt _r) g (Std.parseInt _g) b (Std.parseInt _b)))))
(None (throw "Expected INFO CODES in Surface"))))
(loop
(case (stream.takeLine)
((Some "SIZE") (break))
((Some infoLine)
(let [infoTokens (infoLine.split " ")]
(dictSet infoCodes (infoTokens.shift) (infoTokens.join " "))))
(None (throw "Expected SIZE in Surface"))))
(case (stream.takeLine)
(None (throw "expected [width] [height] in Surface"))
((Some sizeLine)
(let [[width height] (.map (sizeLine.split " ") Std.parseInt)
surface (new Surface width height)]
(stream.dropString "CHARACTERS\n")
(doFor row (range height)
(setNth surface.letters.rows row (stream.expect "line of characters" ->{(stream.takeLine)})))
(stream.dropString "BACKGROUND COLORS\n")
(doFor y (range height)
(doFor x (range width)
(surface.setBackgroundColor x y (dictGet colors (stream.expect "a color code" ->{(stream.takeChars 1)}))))
(stream.dropString "\n"))
(stream.dropString "CHARACTER COLORS\n")
(doFor y (range height)
(doFor x (range width)
(surface.letterColors.setPixel x y (dictGet colors (stream.expect "a color code" ->{(stream.takeChars 1)}))))
(stream.dropString "\n"))
(stream.dropString "OPACITY\n")
(doFor y (range height)
(doFor x (range width)
(surface.opacity.setCell x y (dictGet opacityCodes (stream.expect "0 or 1" ->{(stream.takeChars 1)}))))
(stream.dropString "\n"))
(stream.dropString "SPECIAL INFO\n")
(doFor y (range height)
(doFor x (range width)
(surface.specialInfo.setCell x y (dictGet infoCodes (stream.expect "a special info code" ->{(stream.takeChars 1)}))))
(stream.dropString "\n"))
surface)))))

View File

@@ -0,0 +1,7 @@
package asciilib.backends.flixel;
import asciilib.AssetsBackend;
import openfl.Assets;
@:build(kiss.Kiss.build())
class FlxAssetsBackend implements AssetsBackend {}

View File

@@ -0,0 +1,3 @@
(defNew [])
(method loadText [filePath] (Assets.getText filePath))

View File

@@ -0,0 +1,16 @@
package asciilib.backends.flixel;
import asciilib.GraphicsBackend;
import asciilib.Graphics;
import flixel.FlxState;
import flixel.group.FlxGroup;
import flixel.FlxSprite;
import flixel.util.FlxColor;
import flixel.system.FlxAssets;
import flixel.graphics.frames.FlxBitmapFont;
import flixel.math.FlxRect;
import flixel.math.FlxPoint;
import flixel.text.FlxBitmapText;
@:build(kiss.Kiss.build())
class FlxGraphicsBackend implements GraphicsBackend {}

View File

@@ -0,0 +1,45 @@
(prop &mut :FlxGroup backgroundColors null)
(prop &mut :FlxGroup letters null)
(prop &mut :Int letterWidth 0)
(prop &mut :Int letterHeight 0)
(prop &mut :FlxBitmapFont font null)
(defNew [_state
_fontAsset
&opt _letters _region _spacing]
[:FlxState state _state
:FlxBitmapFontGraphicAsset fontAsset _fontAsset
:String fontLetters _letters
:FlxRect region _region
:FlxPoint spacing _spacing])
(method :Void initialize [:String title :Int width :Int height :Int _letterWidth :Int _letterHeight]
(set letterWidth _letterWidth)
(set letterHeight _letterHeight)
(set font (FlxBitmapFont.fromMonospace fontAsset fontLetters (new FlxPoint letterWidth letterHeight) region spacing))
(set backgroundColors (new FlxGroup))
(set letters (new FlxGroup)))
(method :Void draw [:Graphics graphics]
(backgroundColors.kill)
(set backgroundColors (new FlxGroup))
(letters.kill)
(set letters (new FlxGroup))
(for x (range graphics.width)
(for y (range graphics.height)
(let [bgc (graphics.getBackgroundColor x y)]
(unless (Colors.equal bgc Colors.Black)
(let [sprite (new FlxSprite (* letterWidth x) (* letterHeight y))]
(backgroundColors.add (sprite.makeGraphic letterWidth letterHeight (FlxColor.fromRGB bgc.r bgc.g bgc.b))))))
(let [letter (graphics.getLetter x y)]
(unless (= letter.char " ")
(let [color letter.color
text (new FlxBitmapText font)]
(set text.text letter.char)
(set text.x (* letterWidth x))
(set text.y (* letterHeight y))
(set text.useTextColor true)
(set text.textColor (FlxColor.fromRGB color.r color.g color.b))
(letters.add text))))))
(state.add backgroundColors)
(state.add letters))

View File

@@ -0,0 +1,7 @@
package asciilib.backends.test;
import asciilib.AssetsBackend;
import sys.io.File;
@:build(kiss.Kiss.build())
class TestAssetsBackend implements AssetsBackend {}

View File

@@ -0,0 +1,3 @@
(defNew [])
(method loadText [filePath] (File.getContent filePath))

View File

@@ -0,0 +1,7 @@
package asciilib.backends.test;
import asciilib.GraphicsBackend;
import asciilib.Graphics;
@:build(kiss.Kiss.build())
class TestGraphicsBackend implements GraphicsBackend {}

View File

@@ -0,0 +1,12 @@
(prop &mut :Int letterWidth 0)
(prop &mut :Int letterHeight 0)
(prop &mut :Int drawCalled 0)
(defNew [])
(method :Void initialize [:String title :Int width :Int height :Int _letterWidth :Int _letterHeight]
(set letterWidth _letterWidth)
(set letterHeight _letterHeight))
(method :Void draw [:Graphics graphics]
(+= drawCalled 1))

View File

@@ -0,0 +1 @@
import kiss.Prelude;