part of '../terminal.dart'; class TerminalCustomPainter extends CustomPainter { Terminal t; double scalingFactor; static const int cellW = 8; static const int cellH = 8; TerminalCustomPainter(this.t, this.scalingFactor); @override bool shouldRepaint(TerminalCustomPainter oldDelegate) { return true; } @override void paint(Canvas canvas, Size size) { var pr = ui.PictureRecorder(); var smallSize = Size((cellW * Terminal.width).toDouble(), (cellH * Terminal.height).toDouble()); var virtualCanvas = Canvas(pr, const Offset(0, 0) & smallSize); virtualPaint(virtualCanvas, smallSize); var image = pr .endRecording() // Renderer does something bizarre if I don't multiply by something greater than 1 .toImageSync(cellW * Terminal.width * 1, cellH * Terminal.height * 1); double x0, y0, xSz, ySz; (x0, y0) = (0.0, 0.0); (xSz, ySz) = (size.width, size.height); for (var multiplierBase = 16.0; multiplierBase >= 1; multiplierBase -= 1) { final multiplier = multiplierBase / scalingFactor; final candidateXSz = (multiplier * cellW * Terminal.width).toDouble(); final candidateYSz = (multiplier * cellH * Terminal.height).toDouble(); if (candidateXSz <= size.width && candidateYSz <= size.height) { xSz = candidateXSz; ySz = candidateYSz; x0 = (size.width - xSz) / 2; y0 = (size.height - ySz) / 2; x0 = (x0 * scalingFactor).floor() / scalingFactor; y0 = (y0 * scalingFactor).floor() / scalingFactor; break; } } canvas.drawImageRect( image, const Offset(0, 0) & smallSize, Offset(x0, y0) & Size(xSz, ySz), Paint()..filterQuality = FilterQuality.none); notifyScreenDimensions( ScreenDimensions(x0: x0, y0: y0, xSz: xSz, ySz: ySz)); image.dispose(); } void virtualPaint(Canvas canvas, Size size) { // == Figure out where the mouse is == var lsm = t._lastSeenMouse; int? activeHighlightGroup; if (t._state == _State.waitMenu && lsm != null) { final (x, y) = lsm; final ti = t._fromXY(x, y); if (ti != null) { activeHighlightGroup = t._tiles[ti].highlightGroup; } } final paint = Paint(); var todos = Todos(); // == Draw the background and foreground of every tile == for (var i = 0; i < nTiles; i++) { final (pcxDst, pcyDst) = t._toXY(i) ?? (0, 0); final (pxDst, pyDst) = (pcxDst * cellW, pcyDst * cellH); final rectDst = Rect.fromLTWH(pxDst.toDouble(), pyDst.toDouble(), cellW.toDouble(), cellH.toDouble()); final tile = t._tiles[i]; var (bg, fg) = (tile.bg, tile.fg); if (tile.highlightGroup != null && tile.highlightGroup == activeHighlightGroup) { (fg, bg) = (bg, fg); } var bgRect = Rect.fromLTWH(0, 0, cellW.toDouble(), cellH.toDouble()); todos.add(Font.bg.imageName, bgRect, rectDst, bg); var c = tile.content; if (c != null) { var fgRect = Rect.fromLTWH(c.sourceCx.toDouble() * cellW, c.sourceCy.toDouble() * cellH, cellW.toDouble(), cellH.toDouble()); todos.add(c.sourceImage, fgRect, rectDst, fg); } } for (var t in todos.imageTodos) { final atlas = t.atlas; if (atlas != null) { canvas.drawAtlas(atlas, t.transforms, t.rects, t.colors, BlendMode.modulate, null, paint); } } } } class Todos { List imageTodos = []; Map imageTodoIx = {}; void add(String source, Rect src, Rect dst, Color color) { var ix = imageTodoIx[source]; if (ix == null) { ix = imageTodos.length; var image = assets.getImageIfAvailable(source); imageTodos.add(ImageTodos(image)); imageTodoIx[source] = ix; } imageTodos[ix].add(src, dst, color); } } class ImageTodos { ui.Image? atlas; List transforms = []; List rects = []; List colors = []; ImageTodos(this.atlas); void add(Rect src, Rect dst, Color color) { transforms.add(RSTransform.fromComponents( rotation: 0.0, scale: 1.0, anchorX: 0.0, anchorY: 0.0, translateX: dst.left, translateY: dst.top, )); rects.add(src); colors.add(color); } }