2023-09-11 02:00:06 +00:00
|
|
|
part of '../terminal.dart';
|
2023-09-06 03:11:15 +00:00
|
|
|
|
|
|
|
class TerminalCustomPainter extends CustomPainter {
|
|
|
|
Terminal t;
|
|
|
|
double scalingFactor;
|
|
|
|
|
2023-09-10 00:36:37 +00:00
|
|
|
static const int cellW = 8;
|
|
|
|
static const int cellH = 8;
|
|
|
|
|
2023-09-06 03:11:15 +00:00
|
|
|
TerminalCustomPainter(this.t, this.scalingFactor);
|
|
|
|
|
|
|
|
@override
|
|
|
|
bool shouldRepaint(TerminalCustomPainter oldDelegate) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void paint(Canvas canvas, Size size) {
|
2023-09-11 02:00:06 +00:00
|
|
|
var pr = ui.PictureRecorder();
|
2023-09-10 00:36:37 +00:00
|
|
|
|
|
|
|
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()
|
2023-09-11 02:18:51 +00:00
|
|
|
.toImageSync(cellW * Terminal.width, cellH * Terminal.height);
|
2023-09-10 01:58:31 +00:00
|
|
|
|
|
|
|
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);
|
2023-09-10 03:26:30 +00:00
|
|
|
notifyScreenDimensions(
|
|
|
|
ScreenDimensions(x0: x0, y0: y0, xSz: xSz, ySz: ySz));
|
|
|
|
|
|
|
|
image.dispose();
|
2023-09-10 00:36:37 +00:00
|
|
|
}
|
2023-09-06 03:11:15 +00:00
|
|
|
|
2023-09-10 00:36:37 +00:00
|
|
|
void virtualPaint(Canvas canvas, Size size) {
|
2023-09-11 02:00:06 +00:00
|
|
|
// == 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-10 00:36:37 +00:00
|
|
|
final paint = Paint();
|
2023-09-06 03:11:15 +00:00
|
|
|
|
|
|
|
var todos = Todos();
|
|
|
|
|
|
|
|
// == Draw the background and foreground of every tile ==
|
|
|
|
for (var i = 0; i < nTiles; i++) {
|
2023-09-11 02:00:06 +00:00
|
|
|
final (pcxDst, pcyDst) = t._toXY(i) ?? (0, 0);
|
2023-09-10 00:36:37 +00:00
|
|
|
final (pxDst, pyDst) = (pcxDst * cellW, pcyDst * cellH);
|
|
|
|
final rectDst = Rect.fromLTWH(pxDst.toDouble(), pyDst.toDouble(),
|
|
|
|
cellW.toDouble(), cellH.toDouble());
|
2023-09-06 03:11:15 +00:00
|
|
|
|
2023-09-11 02:00:06 +00:00
|
|
|
final tile = t._tiles[i];
|
|
|
|
|
|
|
|
var (bg, fg) = (tile.bg, tile.fg);
|
|
|
|
if (tile.highlightGroup != null &&
|
|
|
|
tile.highlightGroup == activeHighlightGroup) {
|
|
|
|
(fg, bg) = (bg, fg);
|
|
|
|
}
|
2023-09-06 03:11:15 +00:00
|
|
|
|
|
|
|
var bgRect = Rect.fromLTWH(0, 0, cellW.toDouble(), cellH.toDouble());
|
2023-09-11 02:00:06 +00:00
|
|
|
todos.add(Font.bg.imageName, bgRect, rectDst, bg);
|
2023-09-06 03:11:15 +00:00
|
|
|
|
|
|
|
var c = tile.content;
|
|
|
|
if (c != null) {
|
|
|
|
var fgRect = Rect.fromLTWH(c.sourceCx.toDouble() * cellW,
|
|
|
|
c.sourceCy.toDouble() * cellH, cellW.toDouble(), cellH.toDouble());
|
2023-09-11 02:00:06 +00:00
|
|
|
todos.add(c.sourceImage, fgRect, rectDst, fg);
|
2023-09-06 03:11:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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> imageTodos = [];
|
|
|
|
Map<String, int> 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<RSTransform> transforms = [];
|
|
|
|
List<Rect> rects = [];
|
|
|
|
List<Color> colors = [];
|
|
|
|
|
|
|
|
ImageTodos(this.atlas);
|
|
|
|
|
|
|
|
void add(Rect src, Rect dst, Color color) {
|
|
|
|
transforms.add(RSTransform.fromComponents(
|
|
|
|
rotation: 0.0,
|
2023-09-10 00:36:37 +00:00
|
|
|
scale: 1.0,
|
2023-09-06 03:11:15 +00:00
|
|
|
anchorX: 0.0,
|
|
|
|
anchorY: 0.0,
|
|
|
|
translateX: dst.left,
|
|
|
|
translateY: dst.top,
|
|
|
|
));
|
|
|
|
rects.add(src);
|
|
|
|
colors.add(color);
|
|
|
|
}
|
|
|
|
}
|