flutter3d
Showcase Changelog 38 packages API reference

The .f3d container: the source

since 0.1.0 Formats and I/O

Regions the guide quotes: write (line 30), read (line 36), report (line 55), check (line 80).

1/// `.f3d`: the engine's own container, built to load without parsing.
2///
3/// Quoted by `f3d.md` and shown whole in the Source tab.
4library;
5
6import 'package:flutter/widgets.dart';
7import 'package:flutter3d/flutter3d.dart';
8import 'package:flutter3d_showcase/src/demo/demo.dart';
9import 'package:vector_math/vector_math.dart';
11final class F3dDemo extends ShowcaseDemo {
12 late final F3dDocument _decoded;
13 late final int _fileBytes;
14 late final int _glbBytes;
16 final _document = PlainModelDocument(
17 surfaces: <ModelSurface>[
18 ModelSurface(
19 mesh: SphereShape(segments: 32, rings: 16).build(),
20 materialIndex: 0,
21 ),
22 ],
23 materials: <SurfaceMaterial>[
24 SurfaceMaterial(baseColor: Vector4(0.4, 0.7, 0.5, 1.0)),
25 ],
26 );
28 @override
29 Scene build(DemoContext context) {
30 // `F3dWriter.write` is the offline half, run once by
31 // `dart run flutter3d_build:convert`. Nothing here is on a frame path.
32 final bytes = F3dWriter(_document).write();
33 _fileBytes = bytes.length;
34 _glbBytes = GltfWriter(_document).writeGlb().length;
36 // Parsing reads the header and the section directory; every array the
37 // engine asks for afterwards, `surfaces` included, is a view over these
38 // same bytes rather than a copy.
39 _decoded = F3dDocument.parse(bytes);
41 return Scene()
42 ..add(
43 MeshNode(
44 DeviceMesh.upload(context.device, _decoded.surfaces.single.mesh),
45 Material(baseColor: Vector4(0.4, 0.7, 0.5, 1.0)),
46 name: 'ball',
47 ),
48 )
49 ..add(
50 LightNode(name: 'sun', intensity: 3.0)
51 ..setLocalForward(Vector3(-0.4, -1.0, -0.3)),
52 );
53 }
55 String _report() =>
56 '.f3d bytes: $_fileBytes\n'
57 '.glb bytes (for comparison): $_glbBytes\n'
58 'surfaces: ${_decoded.surfaces.length}\n'
59 'vertices: ${_decoded.vertexCount}\n'
60 'triangles: ${_decoded.triangleCount}';
62 @override
63 Widget? customBody(BuildContext buildContext, DemoContext context) =>
64 Container(
65 color: const Color(0xFF14161A),
66 padding: const EdgeInsets.all(24),
67 alignment: Alignment.topLeft,
68 child: DefaultTextStyle(
69 style: const TextStyle(
70 color: Color(0xFFE8E8EC),
71 fontSize: 16,
72 fontFamily: 'monospace',
73 ),
74 child: Text(_report()),
75 ),
76 );
78 @override
79 void verify(Scene scene, FrameResult frame) {
80 final differences = compareModelDocuments(_document, _decoded);
81 if (differences.isNotEmpty) {
82 throw StateError(
83 'the round trip through .f3d changed something: '
84 '$differences',
85 );
86 }
87 if (_decoded.surfaces.isEmpty) {
88 throw StateError('the file decoded to no surfaces');
89 }
90 if (frame.drawCalls < 1) {
91 throw StateError('the ball was not drawn');
92 }
93 }