• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / vector_math.dart / 17181727464

04 Aug 2025 07:19PM UTC coverage: 26.702% (+0.3%) from 26.388%
17181727464

push

github

web-flow
Bump min SDK to 3.7, update dependencies, reformat (#348)

496 of 1182 new or added lines in 55 files covered. (41.96%)

18 existing lines in 8 files now uncovered.

4463 of 16714 relevant lines covered (26.7%)

1.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.05
/lib/src/vector_math_geometry/mesh_geometry.dart
1
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
2
// All rights reserved. Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
part of '../../vector_math_geometry.dart';
6

7
class VertexAttrib {
8
  final String name;
9
  final String type;
10
  final int size;
11
  final int stride;
12
  final int offset;
13

14
  VertexAttrib(this.name, this.size, this.type) : stride = 0, offset = 0;
1✔
15

16
  VertexAttrib.copy(VertexAttrib attrib)
×
NEW
17
    : name = attrib.name,
×
NEW
18
      size = attrib.size,
×
NEW
19
      type = attrib.type,
×
NEW
20
      stride = attrib.stride,
×
NEW
21
      offset = attrib.offset;
×
22

23
  VertexAttrib._internal(
×
24
    this.name,
25
    this.size,
26
    this.type,
27
    this.stride,
28
    this.offset,
29
  );
30

31
  VertexAttrib._resetStrideOffset(VertexAttrib attrib, this.stride, this.offset)
1✔
32
    : name = attrib.name,
1✔
33
      size = attrib.size,
1✔
34
      type = attrib.type;
1✔
35

36
  VectorList<Vector> getView(Float32List buffer) {
1✔
37
    final viewOffset = offset ~/ buffer.elementSizeInBytes;
3✔
38
    final viewStride = stride ~/ buffer.elementSizeInBytes;
3✔
39
    switch (size) {
1✔
40
      case 2:
1✔
41
        return Vector2List.view(buffer, viewOffset, viewStride);
1✔
42
      case 3:
1✔
43
        return Vector3List.view(buffer, viewOffset, viewStride);
1✔
44
      case 4:
1✔
45
        return Vector4List.view(buffer, viewOffset, viewStride);
1✔
46
      default:
47
        throw StateError('size of $size is not supported');
×
48
    }
49
  }
50

51
  String get format => '$type$size';
×
52

53
  int get elementSize {
1✔
54
    switch (type) {
1✔
55
      case 'float':
1✔
56
      case 'int':
×
57
        return 4;
58
      case 'short':
×
59
        return 2;
60
      case 'byte':
×
61
        return 1;
62
      default:
63
        return 0;
64
    }
65
  }
66

67
  Map<String, Object> toJson() => <String, Object>{
×
NEW
68
    'format': format,
×
NEW
69
    'name': name,
×
NEW
70
    'offset': offset,
×
NEW
71
    'stride': stride,
×
NEW
72
    'size': size,
×
NEW
73
    'type': type,
×
74
  };
75
}
76

77
class MeshGeometry {
78
  late final Float32List buffer;
79
  Uint16List? indices;
80
  final List<VertexAttrib> attribs;
81
  final int length;
82
  final int stride;
83

84
  factory MeshGeometry(int length, List<VertexAttrib> attributes) {
1✔
85
    var stride = 0;
86
    for (var a in attributes) {
2✔
87
      stride += a.elementSize * a.size;
4✔
88
    }
89
    var offset = 0;
90
    final attribs = <VertexAttrib>[];
1✔
91
    for (var a in attributes) {
2✔
92
      attribs.add(VertexAttrib._resetStrideOffset(a, stride, offset));
2✔
93
      offset += a.elementSize * a.size;
4✔
94
    }
95

96
    return MeshGeometry._internal(length, stride, attribs);
1✔
97
  }
98

99
  MeshGeometry._internal(
1✔
100
    this.length,
101
    this.stride,
102
    this.attribs, [
103
    Float32List? externBuffer,
104
  ]) {
105
    buffer =
1✔
106
        externBuffer ??
107
        Float32List((length * stride) ~/ Float32List.bytesPerElement);
5✔
108
  }
109

110
  MeshGeometry.copy(MeshGeometry mesh)
×
NEW
111
    : stride = mesh.stride,
×
NEW
112
      length = mesh.length,
×
NEW
113
      attribs = mesh.attribs {
×
114
    // Copy the buffer
115
    buffer = Float32List(mesh.buffer.length);
×
116
    buffer.setAll(0, mesh.buffer);
×
117

118
    // Copy the indices
119
    if (mesh.indices != null) {
×
120
      indices = Uint16List(mesh.indices!.length)..setAll(0, mesh.indices!);
×
121
    }
122
  }
123

124
  factory MeshGeometry.fromJson(Map<String, Object> json) {
×
125
    Float32List buffer;
126
    final jsonBuffer = json['buffer'];
×
127
    if (jsonBuffer is List<double>) {
×
128
      buffer = Float32List.fromList(jsonBuffer);
×
129
    } else {
130
      throw ArgumentError.value(
×
131
        jsonBuffer,
132
        'json["buffer"]',
133
        'Value type must be List<double>',
134
      );
135
    }
136

137
    final jsonAttribs = json['attribs'];
×
138
    Map<String, Object> jsonAttribsMap;
139
    if (jsonAttribs is Map<String, Object>) {
×
140
      jsonAttribsMap = jsonAttribs;
141
    } else {
NEW
142
      throw ArgumentError.value(
×
143
        jsonBuffer,
144
        'json["attribs"]',
145
        'Value type must be Map<String, Object>',
146
      );
147
    }
148
    final attribs = <VertexAttrib>[];
×
149
    var stride = 0;
150
    for (var key in jsonAttribsMap.keys) {
×
151
      VertexAttrib attrib;
152
      final jsonAttrib = jsonAttribsMap[key];
×
153
      if (jsonAttrib is Map<String, Object>) {
×
154
        attrib = attribFromJson(key, jsonAttrib);
×
155
        attribs.add(attrib);
×
156
        if (stride == 0) {
×
157
          stride = attrib.stride;
×
158
        }
159
      }
160
    }
161

162
    final mesh = MeshGeometry._internal(
×
NEW
163
      buffer.lengthInBytes ~/ stride,
×
164
      stride,
165
      attribs,
166
      buffer,
167
    );
168

169
    final jsonIndices = json['indices'];
×
170
    if (jsonIndices is List<int>) {
×
171
      mesh.indices = Uint16List.fromList(jsonIndices);
×
172
    }
173

174
    return mesh;
175
  }
176

177
  factory MeshGeometry.resetAttribs(
1✔
178
    MeshGeometry inputMesh,
179
    List<VertexAttrib> attributes,
180
  ) {
181
    final mesh = MeshGeometry(inputMesh.length, attributes)
2✔
182
      ..indices = inputMesh.indices;
2✔
183

184
    // Copy over the attributes that were specified
185
    for (var attrib in mesh.attribs) {
2✔
186
      final inputAttrib = inputMesh.getAttrib(attrib.name);
2✔
187
      if (inputAttrib != null) {
188
        if (inputAttrib.size != attrib.size ||
3✔
189
            inputAttrib.type != attrib.type) {
3✔
190
          throw Exception(
×
NEW
191
            'Attributes size or type is mismatched: ${attrib.name}',
×
192
          );
193
        }
194

195
        final inputView = inputAttrib.getView(inputMesh.buffer);
2✔
196

197
        // Copy [inputView] to a view from attrib
198
        attrib.getView(mesh.buffer).copy(inputView);
3✔
199
      }
200
    }
201

202
    return mesh;
203
  }
204

205
  factory MeshGeometry.combine(List<MeshGeometry> meshes) {
1✔
206
    if (meshes.length < 2) {
2✔
207
      throw Exception(
×
208
        'Must provide at least two MeshGeometry instances to combine.',
209
      );
210
    }
211

212
    // When combining meshes they must all have a matching set of VertexAttribs
213
    final firstMesh = meshes[0];
1✔
214
    var totalVerts = firstMesh.length;
1✔
215
    var totalIndices =
216
        firstMesh.indices != null ? firstMesh.indices!.length : 0;
3✔
217
    for (var i = 1; i < meshes.length; ++i) {
3✔
218
      final srcMesh = meshes[i];
1✔
219
      if (!firstMesh.attribsAreCompatible(srcMesh)) {
1✔
220
        throw Exception(
×
221
          'All meshes must have identical attributes to combine.',
222
        );
223
      }
224
      totalVerts += srcMesh.length;
2✔
225
      totalIndices += srcMesh.indices != null ? srcMesh.indices!.length : 0;
4✔
226
    }
227

228
    final mesh = MeshGeometry._internal(
1✔
229
      totalVerts,
230
      firstMesh.stride,
1✔
231
      firstMesh.attribs,
1✔
232
    );
233

234
    if (totalIndices > 0) {
1✔
235
      mesh.indices = Uint16List(totalIndices);
2✔
236
    }
237

238
    // Copy over the buffer data:
239
    var bufferOffset = 0;
240
    var indexOffset = 0;
241
    var vertexOffset = 0;
242
    for (var i = 0; i < meshes.length; ++i) {
3✔
243
      final srcMesh = meshes[i];
1✔
244
      mesh.buffer.setAll(bufferOffset, srcMesh.buffer);
3✔
245

246
      if (totalIndices > 0) {
1✔
247
        for (var j = 0; j < srcMesh.indices!.length; ++j) {
4✔
248
          mesh.indices![j + indexOffset] = srcMesh.indices![j] + vertexOffset;
6✔
249
        }
250
        vertexOffset += srcMesh.length;
2✔
251
        indexOffset += srcMesh.indices!.length;
3✔
252
      }
253

254
      bufferOffset += srcMesh.buffer.length;
3✔
255
    }
256

257
    return mesh;
258
  }
259

260
  int get triangleVertexCount => indices != null ? indices!.length : length;
4✔
261

262
  Map<String, dynamic> toJson() {
×
263
    final r = <String, dynamic>{};
×
264
    r['attributes'] = attribs;
×
265
    r['indices'] = indices;
×
266
    r['vertices'] = buffer;
×
267
    return r;
268
  }
269

270
  static VertexAttrib attribFromJson(String name, Map<String, Object> json) {
×
271
    final jsonSize = json['size'];
×
272
    final jsonType = json['type'];
×
273
    final jsonStride = json['stride'];
×
274
    final jsonOffset = json['offset'];
×
275
    if (jsonSize is int &&
×
276
        jsonType is String &&
×
277
        jsonStride is int &&
×
278
        jsonOffset is int) {
×
279
      return VertexAttrib._internal(
×
280
        name,
281
        jsonSize,
282
        jsonType,
283
        jsonStride,
284
        jsonOffset,
285
      );
286
    } else {
287
      throw UnimplementedError();
×
288
    }
289
  }
290

291
  VertexAttrib? getAttrib(String name) {
1✔
292
    for (var attrib in attribs) {
2✔
293
      if (attrib.name == name) {
2✔
294
        return attrib;
295
      }
296
    }
297
    return null;
298
  }
299

300
  VectorList<Vector>? getViewForAttrib(String name) {
1✔
301
    for (var attrib in attribs) {
2✔
302
      if (attrib.name == name) {
2✔
303
        return attrib.getView(buffer);
2✔
304
      }
305
    }
306
    return null;
307
  }
308

309
  bool attribsAreCompatible(MeshGeometry mesh) {
1✔
310
    if (mesh.attribs.length != attribs.length) {
5✔
311
      return false;
312
    }
313

314
    for (var attrib in attribs) {
2✔
315
      final otherAttrib = mesh.getAttrib(attrib.name);
2✔
316
      if (otherAttrib == null) {
317
        return false;
318
      }
319
      if (attrib.type != otherAttrib.type ||
3✔
320
          attrib.size != otherAttrib.size ||
3✔
321
          attrib.stride != otherAttrib.stride ||
3✔
322
          attrib.offset != otherAttrib.offset) {
3✔
323
        return false;
324
      }
325
    }
326

327
    if ((indices == null && mesh.indices != null) ||
1✔
328
        (indices != null && mesh.indices == null)) {
2✔
329
      return false;
330
    }
331

332
    return true;
333
  }
334
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc