cellular-automata/lib/src/Render.dart

122 lines
4.1 KiB
Dart

import 'dart:html' as html;
import 'dart:math';
import 'package:stagexl/stagexl.dart' as sxl;
class ColorScheme {
//TODO make iterable (perhaps through backing list which gets accesses by the variables)
final int ON;
final int EXPANSION;
final int CORE;
final int OFF;
const ColorScheme(this.ON, this.EXPANSION, this.CORE,
[this.OFF = sxl.Color.Transparent]);
}
class Render {
final sxl.Stage _stage;
final sxl.RenderLoop _renderLoop = sxl.RenderLoop();
Map<int, sxl.BitmapData> _colorMap;
final sxl.BitmapContainer _renderContainer = sxl.BitmapContainer();
bool transparentBG = false;
bool _renderEdges = false;
bool get renderEdges => _renderEdges;
void set renderEdges(bool value) {
_renderEdges = value;
_colorMap = _getColorMap(_cellSize, _colorScheme);
}
Point<int> _gridSize;
Point<int> get _cellSize => Point(
_stage.stageWidth ~/ _gridSize.x, _stage.stageHeight ~/ _gridSize.y);
final ColorScheme _colorScheme;
//TODO replace with scheme data structure to enable different color scheme injection
static const defaultScheme =
ColorScheme(sxl.Color.Blue, 1, 1, sxl.Color.Black);
// TODO gridSize rendering can only be scaled uniformly currently - switch to Point(w,h)?
Render(html.CanvasElement canvas, Point<int> gridSize,
[ColorScheme colorScheme = defaultScheme])
: _stage = _createStage(canvas),
_colorScheme = colorScheme,
_gridSize = gridSize {
_colorMap = _getColorMap(_cellSize, colorScheme);
_initRenderGrid(_cellSize, gridSize).forEach((sxl.Bitmap bm) {
_renderContainer.addChild(bm);
});
_renderLoop.addStage(_stage);
_stage.addChild(_renderContainer);
setDirty();
}
static sxl.Stage _createStage(html.CanvasElement canvas) {
sxl.StageXL.stageOptions.renderEngine = sxl.RenderEngine.WebGL;
sxl.StageXL.stageOptions.stageRenderMode = sxl.StageRenderMode.AUTO_INVALID;
// sxl.StageXL.stageOptions.backgroundColor = sxl.Color.Yellow;
return sxl.Stage(canvas);
}
Map<int, sxl.BitmapData> _getColorMap(Point<int> size, ColorScheme scheme) {
print("${size.toString()}, ${scheme.toString()}");
// Creates a shape with color of each quad in scheme
sxl.Shape shape = sxl.Shape();
// ON
shape.graphics.beginPath();
shape.graphics.rect(0 * size.x, 0, size.x, size.y);
shape.graphics.fillColor(scheme.ON ?? sxl.Color.Transparent);
shape.graphics
.strokeColor(renderEdges ? sxl.Color.DarkGray : sxl.Color.Transparent);
shape.graphics.closePath();
// OFF
shape.graphics.beginPath();
shape.graphics.rect(1 * size.x, 0, size.x, size.y);
shape.graphics.fillColor(scheme.OFF ?? sxl.Color.Transparent);
shape.graphics
.strokeColor(renderEdges ? sxl.Color.DarkGray : sxl.Color.Transparent);
shape.graphics.closePath();
// creates one texture out of shape
sxl.BitmapData texture = sxl.BitmapData(2 * size.x, size.y);
texture.draw(shape);
// re-slice texture into individual BitmapDatas
Map<int, sxl.BitmapData> colorMap = Map();
List<sxl.BitmapData> colorBitmaps = texture.sliceIntoFrames(size.x, size.y);
print("Found ${colorBitmaps.length} colors.");
// TODO more elegant way through iterables etc; also include EXPANSION, CORE functionality
colorMap[scheme.ON] = colorBitmaps[0];
colorMap[scheme.OFF] = colorBitmaps[1];
return colorMap;
}
List<sxl.Bitmap> _initRenderGrid(Point<int> cellSize, Point<int> gridSize) {
List<sxl.Bitmap> grid = List();
for (int y = 0; y < gridSize.y; y++) {
for (int x = 0; x < gridSize.x; x++) {
sxl.Bitmap bm = sxl.Bitmap();
bm.bitmapData = _colorMap[_colorScheme.OFF];
bm.x = x * cellSize.x;
bm.y = y * cellSize.y;
grid.add(bm);
}
}
return grid;
}
void setDirty() => _stage.invalidate();
void mergeChanges(Map<int, bool> stateChanges) {
if (stateChanges.length == 0) return;
stateChanges.forEach((int i, bool state) {
_renderContainer.getChildAt(i).bitmapData =
(state ? _colorMap[_colorScheme.ON] : _colorMap[_colorScheme.OFF]);
});
setDirty();
}
}