Skip to content

Scratchpad Sink Source

Lukas Kalbertodt edited this page Dec 4, 2018 · 2 revisions

One main problem: sources and sinks have their own order of processing. E.g. a PLY file needs to write all vertices with properties first, then all faces with properties. An STL file writes all faces with vertices in one go. OBJ first writes all values of vertex property 1, then vertex property 2 and so on. So we have widely different data layouts. Similarly for the source: reading different file formats makes data available in a different order. Non-file sources, like shapes or ISO surfaces, also have their own algorithms which generate the mesh in a specific order.

In contrast to that are random access data structures where mesh data (including properties) can be accessed or created in any order (except for simple rules like "you have to create a face before adding properties to it"). These structures are completely in memory.

As a consequence, it's almost impossible (at all) to transfer from a source to a sink with only constant memory requirements. If the order of data processing is the same for source and sink, it's possible. But since this is rare (there are many different ways to process the data), it doesn't make sense to hope for that as a general solution. (It might be worthwhile adding a system to allow this streaming transfer; but it is low priority.) Thus, we need a temporary storage for transfers in general.




STL Configurations:

  • Mesh: Which type?
  • Positions:
    • yes/no?
  • Normals
    • yes/no?
  • Merge/unify vertices?

PLY Configurations:

  • Mesh: Which type?
  • Per property:
    • Yes/no?

Shape configurations:

  • Mesh: Which type?
  • Per property:
    • Yes/no?

  • MeshSource

    • potentially information about prop type, potentially not
  • MeshSink

    • Can have requirements (e.g. "need positions!")
      • Either very fixed requirements and additional fields ignored
      • Or no requirements and all fields are just used as provided (files)
      • Or in between
  • Two possibilities for PropSet:

    • visitor based (basically a visit(self, impl Visitor) method)
    • Poll based (methods like position(), ...)

What we want:

  • Create OpenGL Buffer directly from file
  • Create OpenGL buffer from a shape description

Sources:

  • Files
  • Shape descriptions

Sinks:

  • OpenGL Buffer
  • Files
// ========================================================================

trait MeshSource {
    type VertexInfo;
    type FaceInfo;

    fn build(self, sink: &mut impl MeshSink<Self::VertexInfo, Self::FaceInfo>);
}

trait MeshSink<VertexInfoT, FaceInfoT> {
    fn add_vertex(&mut self, info: VertexInfoT) -> VertexHandle;
    fn add_face(&mut self, info: FaceInfoT) -> FaceHandle;
}



// ========================================================================

trait MeshSource {
    type VertexInfo: PropSet;
    type FaceInfo: PropSet;

    fn build(self, sink: &mut impl MeshSink<Self::VertexInfo, Self::FaceInfo>);
}

trait MeshSink<VertexInfoT, FaceInfoT> {
    fn add_vertex(&mut self, info: VertexInfoT) -> Result<VertexHandle, _>;
    fn add_face(&mut self, info: FaceInfoT) -> Result<FaceHandle, _>;
}

trait PropSet {
    fn visit(self, visitor: &mut impl PropVisitor);
}

trait PropVisitor {
    fn visit_position(&mut self, )
    fn visit_normal(&mut self)
}


// ========================================================================

impl<VertexInfoT, FaceInfoT> MeshSink<VertexInfoT, FaceInfoT> for PlyWriter 
where
    VertexInfoT: HasPosition<Scalar = f32>, // or via `Into<f32>`
{
    if FaceInfoT::HAS_NORMAL {

    }
}

Create mesh from file

DSL via macro

build! {
    type: SharedVertexMesh,
    vertex_maps: [
        positions: |info| info.position,
        colors: |_| 3,
    ],
    face_maps: [
        normals: |info| info.normal,
    ],
}

Disadvantages:

  • New, surprising syntax

Advantages:

  • only specified what's necessary
  • could do error checking maybe?

Pass by mut ref

let positions = VecMap::empty();
let normals = VecMap::empty();

let mesh = my_disc.build::<SharedVertexMesh>()
    .add_vertex_prop(&mut positions, |info| info.position)
    .add_face_prop(&mut normals, |info| info.normal);

Disadvantages:

  • Map type specified while unimportant/redundant (or is it?)
  • API assumes maps are empty but no way to express that except for docs

Advantages:

  • Standard Rust syntax