extractMeshData method

MeshData extractMeshData()

Copies this geometry's retained CPU vertex/index data out as an isolate-transferable MeshData snapshot.

The snapshot is always a copy (never a view of engine memory) with structure-of-arrays attributes regardless of how the data is stored internally, so it is safe to send to a background isolate and derive new geometry from (see MeshData.unweld, MeshData.extractEdges). Attributes the engine did not retain come back null; skinned geometry returns bind-pose positions and no joint data.

Throws a StateError when isReadable is false.

Implementation

MeshData extractMeshData() {
  final interleaved = _cpuVertices;
  final soaPositions = _cpuPositions;
  if (interleaved == null && soaPositions == null) {
    throw StateError(
      'This geometry retains no CPU vertex data to extract '
      '(isReadable is false). Caller-managed vertex buffers are not '
      'readable.',
    );
  }

  Float32List positions;
  Float32List? normals;
  Float32List? texCoords;
  Float32List? colors;
  if (interleaved != null) {
    // Interleaved unskinned (12 floats) or skinned (20 floats, of which
    // the leading 12 match the unskinned layout) vertices.
    final stride = this is SkinnedGeometry ? 20 : 12;
    final floats = Float32List.sublistView(interleaved);
    positions = Float32List(_vertexCount * 3);
    normals = Float32List(_vertexCount * 3);
    texCoords = Float32List(_vertexCount * 2);
    colors = Float32List(_vertexCount * 4);
    for (var v = 0; v < _vertexCount; v++) {
      final base = v * stride;
      positions[v * 3] = floats[base];
      positions[v * 3 + 1] = floats[base + 1];
      positions[v * 3 + 2] = floats[base + 2];
      normals[v * 3] = floats[base + 3];
      normals[v * 3 + 1] = floats[base + 4];
      normals[v * 3 + 2] = floats[base + 5];
      texCoords[v * 2] = floats[base + 6];
      texCoords[v * 2 + 1] = floats[base + 7];
      colors[v * 4] = floats[base + 8];
      colors[v * 4 + 1] = floats[base + 9];
      colors[v * 4 + 2] = floats[base + 10];
      colors[v * 4 + 3] = floats[base + 11];
    }
  } else {
    positions = Float32List.fromList(soaPositions!);
    final n = _cpuNormals;
    final t = _cpuTexCoords;
    final c = _cpuColors;
    normals = n == null ? null : Float32List.fromList(n);
    texCoords = t == null ? null : Float32List.fromList(t);
    colors = c == null ? null : Float32List.fromList(c);
  }

  List<int>? indices;
  final indexBytes = _cpuIndices;
  if (indexBytes != null && _indexCount > 0) {
    indices = _indexType == gpu.IndexType.int32
        ? Uint32List.fromList(Uint32List.sublistView(indexBytes))
        : Uint16List.fromList(Uint16List.sublistView(indexBytes));
  }

  return MeshData(
    positions: positions,
    vertexCount: _vertexCount,
    normals: normals,
    texCoords: texCoords,
    colors: colors,
    indices: indices,
    primitiveType: primitiveType,
    customAttributes: {
      for (final entry in _customAttributes.entries)
        entry.key: MeshAttributeData(
          Float32List.fromList(entry.value.data),
          components: entry.value.components,
        ),
    },
  );
}