Files
TPSchedule/mobile/test/widgets/refraction_shader_test.dart

121 lines
4.3 KiB
Dart

import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test(
'glass samples and bends background pixels while keeping the centre stable',
() async {
const width = 160, height = 100;
final sourceRecorder = ui.PictureRecorder();
final sourceCanvas = ui.Canvas(sourceRecorder);
for (var x = 0; x < width; x++) {
sourceCanvas.drawRect(
ui.Rect.fromLTWH(x.toDouble(), 0, 1, height.toDouble()),
ui.Paint()..color = ui.Color.fromARGB(255, 40 + x, 70, 90),
);
}
final sourcePicture = sourceRecorder.endRecording();
final source = await sourcePicture.toImage(width, height);
final program = await ui.FragmentProgram.fromAsset(
'shaders/liquid_glass.frag',
);
final shader = program.fragmentShader()
..setFloat(0, width.toDouble())
..setFloat(1, height.toDouble())
..setFloat(2, 0)
..setFloat(3, 0)
..setFloat(4, width.toDouble())
..setFloat(5, height.toDouble())
..setImageSampler(0, source);
Future<ui.Image> draw(double strength) async {
shader.setFloat(6, strength);
final recorder = ui.PictureRecorder();
ui.Canvas(recorder).drawRect(
ui.Rect.fromLTWH(0, 0, width.toDouble(), height.toDouble()),
ui.Paint()..shader = shader,
);
final picture = recorder.endRecording();
final image = await picture.toImage(width, height);
picture.dispose();
return image;
}
final plain = await draw(0), refracted = await draw(1);
final a = (await plain.toByteData())!,
b = (await refracted.toByteData())!;
int red(ByteData data, int x) => data.getUint8((50 * width + x) * 4);
expect(red(a, 12), closeTo(52, 1));
expect((red(b, 12) - red(a, 12)).abs(), greaterThan(3));
expect(red(b, 80), closeTo(red(a, 80), 1));
expect(b.getUint8((50 * width + 12) * 4 + 3), 255);
shader.dispose();
plain.dispose();
refracted.dispose();
source.dispose();
sourcePicture.dispose();
},
);
test(
'glass rim reflects nearby backdrop light outside its transmitted ray',
() async {
const width = 160, height = 100;
final program = await ui.FragmentProgram.fromAsset(
'shaders/liquid_glass.frag',
);
Future<ByteData> draw(bool brightEdge) async {
final sourceRecorder = ui.PictureRecorder();
final sourceCanvas = ui.Canvas(sourceRecorder);
sourceCanvas.drawRect(
const ui.Rect.fromLTWH(0, 0, 160, 100),
ui.Paint()..color = const ui.Color(0xFF28465A),
);
if (brightEdge) {
sourceCanvas.drawRect(
const ui.Rect.fromLTWH(0, 0, 5, 100),
ui.Paint()..color = const ui.Color(0xFF28E65A),
);
}
final sourcePicture = sourceRecorder.endRecording();
final source = await sourcePicture.toImage(width, height);
final shader = program.fragmentShader()
..setFloat(0, width.toDouble())
..setFloat(1, height.toDouble())
..setFloat(2, 0)
..setFloat(3, 0)
..setFloat(4, width.toDouble())
..setFloat(5, height.toDouble())
..setFloat(6, 1)
..setImageSampler(0, source);
final recorder = ui.PictureRecorder();
ui.Canvas(recorder).drawRect(
const ui.Rect.fromLTWH(0, 0, 160, 100),
ui.Paint()..shader = shader,
);
final picture = recorder.endRecording();
final image = await picture.toImage(width, height);
final data = (await image.toByteData())!;
image.dispose();
picture.dispose();
shader.dispose();
source.dispose();
sourcePicture.dispose();
return data;
}
final plain = await draw(false), reflected = await draw(true);
final rimGreen = (50 * width + 8) * 4 + 1;
final centreGreen = (50 * width + 80) * 4 + 1;
expect(
reflected.getUint8(rimGreen) - plain.getUint8(rimGreen),
greaterThan(2),
);
expect(reflected.getUint8(centreGreen), plain.getUint8(centreGreen));
expect(reflected.getUint8(rimGreen + 2), 255);
},
);
}