dunge 0.1.0

Simple and portable 3d render library
Documentation
# Dunge
Simple and portable 3d render based on [WGPU](https://github.com/gfx-rs/wgpu).

## Getting Started
Let's render a colorful triangle for example. First, we need to add the dependency of dunge in the `Cargo.toml`:
```
cargo add dunge
```

Then, let's create a new window to draw something in it:
```rust
use dunge::*;

fn main() {
    dunge::make_window(InitialState::default())
        .run_blocking(App::new);
}
```

`make_window` creates a new instance of `Canvas` type and sets up window properties, it allows us to handle an input from users. `run_blocking` runs our application by calling the constructor of it and passes the `Context` object there. Context uses for creation and updating of meshes, textures, views, instances etc.

The `App` is our application type, we need to create it:
```rust
struct App {
    instance: InstanceHandle,
    mesh: MeshHandle<ColorVertex>,
    view: ViewHandle,
}

impl App {
    fn new(context: &mut Context) -> Self {
        // Create a model instance
        let instance = context.create_instances([Position::default()]);

        // Create a mesh
        let mesh = {
            // Vertex data describes a position in XYZ coordinates and color in RGB per vertex:
            const VERTICES: [ColorVertex; 3] = [
                ColorVertex { pos: [-0.5, -0.5, 0.], col: [1., 0., 0.] },
                ColorVertex { pos: [0.5,  -0.5, 0.], col: [0., 1., 0.] },
                ColorVertex { pos: [0.,    0.5, 0.], col: [0., 0., 1.] },
            ];
            // Indices of triangle vetrices:
            const INDICES: [u16; 3] = [0, 1, 2];

            let data = MeshData::new(&VERTICES, &[INDICES]).unwrap();
            context.create_mesh(data)
        };

        // Create the view
        let view = context.create_view::<Perspective>(View::default());
        Self { instance, mesh, view }
    }
}
```

To be able to pass the `App` in `run_blocking` we need to implement a `Loop` trait for it:
```rust
impl Loop for App {
    type Error = Error; // Define the error type

    // This calls once before every `render`
    fn update(&mut self, context: &mut Context, input: &Input) -> Result<(), Self::Error> {
        // You can update the context here. For example create and delete meshes.
        // Also you may want to handle an user's input here.
        Ok(())
    }

    // This calls every time the application needs to draw something in the window
    fn render(&self, frame: &mut Frame) -> Result<(), Self::Error> {
        // Draw a new layer. Use `color_layer` for this since our triangle has color vertices
        let mut layer = frame
            .color_layer()
            .with_clear_color(Srgba([0, 0, 0, 255]))
            .with_clear_depth()
            .start();

        layer.bind_view(self.view)?;
        layer.bind_instance(self.instance)?;
        layer.draw(self.mesh)
    }
}
```

Finally, let's run our code:
```
cargo run
```

Now you should see something like this:

![the triangle](./examples/triangle/screen.png)

## Examples
See [examples](https://github.com/nanoqsh/dunge/tree/main/examples) directory for more examples.
To build and run an example do:
```
cargo r -p <example_name>
```