v0.17.0
===

LÖVR v0.17.0, codename TBD, is currently **not released**.  This version has been X days in the
making, with X commits from X authors.

This version includes tons of bugfixes and usability improvements for the new graphics module, along
with the following new features:

- Passthrough, enabling mixed reality experiences
- `TerrainShape`, for 3D heightfields in physics simulations
- Blend shapes, for facial animation and making meshes squishy
- HTTP, with support for HTTPS
- Frustum culling, a quick way to improve rendering performance
- Rounded rectangles with thickness, great for VR UI
- Mouse input

This is a massive release with lots to chew on, so let's try to break things down into atomic,
bite-sized pieces!

Passthrough
---

With passthrough, you can now layer a view of the real world underneath whatever your project
renders.  This is great for mixed reality experiences, or just as a way to avoid tripping over
furniture and punching walls.  To enable it, just call `lovr.headset.setPassthrough(true)`.

LÖVR also sets OpenXR blend modes now, which means projects will render properly on AR devices like
the the Magic Leap and Holo Lens.

Blend Shapes
---

`Model` now supports blend shapes!  These are great for facial animation or other types of mesh
squishing, which is difficult to implement with skeletal animation.  `Model:setBlendShapeWeight`
sets the weight of a blend shape, and weights can be animated with keyframe animations as well.

They also use compute shaders instead of vertex shaders.  This means:

- There's no limit on the number of active blend shapes
- They won't be evaluated multiple times when there are multiple cameras
- Extra style points

Roundrect
---

Thick rounded rectangles are a very common shape to use for UI in VR.  Previously we all had to
generate meshes, import them as models, use SDF shaders, or piece them together with cylinders and
boxes.  Now, `Pass:roundrect` is built in!

TerrainShape
---

`TerrainShape` is a new physics shape that lets you add heightfields to physics simulations. Terrain
can be provided as an `Image`, or as a Lua function for procedural terrain.

Frustum Culling
---

Frustum culling is an optimization that skips rendering objects that are out of view.  For 3D scenes
with content surrounding the player, this is a quick way to reduce GPU overhead, especially when
objects have lots of vertices.

Frustum culling can be enabled using `Pass:setViewCull(true)`, which will cull objects that have
bounding boxes.  `Model` objects and most shape primitives have bounding boxes, and a `Mesh` can
compute its bounds using `Mesh:computeBoundingBox`.

Plugins
---

There are 2 new builtin plugins and a new module:

- The `http` plugin does HTTP requests, with support for HTTPS.
- The `enet` plugin is a UDP networking library (back as a plugin).
- The `utf8` module backports the `utf8` library from Lua 5.3.

The cool part about having these as plugins is that they are 100% optional -- you can delete the
library files if you don't need them and LÖVR will still work fine.

Universal APK
---

Previously, APK downloads were only compatible with the Oculus Quest.  In v0.17.0 LÖVR switched to a
"universal" APK system where multiple OpenXR loaders are bundled in a single APK.  As a result, APKs
will now work on most if not all Android-based headsets.  This does increase file size a bit, but
it should be alleviated as more vendors converge on the standard OpenXR loader.

Buffer Format Improvements
---

There's a handy new `Shader:getBufferFormat` method which will parse the format of a buffer from
shader code.  This means you don't need to type out the buffer's format again in Lua and keep it in
sync with the shader code:

    format = shader:getBufferFormat('mybuffer')
    buffer = lovr.graphics.newBuffer(format, data)

Buffer formats and shader constants now support nested structure and array types.  Buffer fields can
also have names, and buffer data can be given as key-value pairs instead of only lists of numbers.

Finally, you can also send a table directly to a uniform buffer variable instead of needing to
create a buffer first.

Graphics Improvements
---

The graphics module has been streamlined a bit as we shake out the new Vulkan renderer.

### No more temporary objects

Temporary Buffer/Pass objects were really tricky due to the way they got invalidated whenever
`lovr.graphics.submit` was called:

    pass = lovr.graphics.getPass('render', canvas)
    -- do stuff with pass
    lovr.graphics.submit(pass)
    pass:cube() --> Error!  Can't use the pass after it's submitted!

This version, `lovr.graphics.getBuffer` and `lovr.graphics.getPass` have been deprecated and
replaced by `lovr.graphics.newBuffer` and `lovr.graphics.newPass`.  These "permanent" types behave
like all other objects, and you can call `lovr.graphics.submit` without messing them up.

For passes, instead of getting a new one every frame, you can create it once and call `Pass:reset`
at the beginning of a frame to reset it to a fresh state.  There's also the option of recording its
draws once and submitting it over and over again, to reduce the Lua overhead of recording draws.

### No more pass types

Passes no longer have a "type" that defines what commands can be recorded on them.  Instead, all
`Pass` objects can receive both graphics and compute work, with computes running before the draws
whenever the pass is submitted.

For transfers, these methods have been moved onto `Buffer` and `Texture` objects themselves.  So if
you want to change the data in a Buffer, call `Buffer:setData`.  Uploading to a Texture is
`Texture:setPixels`.  There's no need for a dedicated transfer pass.  The transfers happen in order
and finish before subsequent graphics submissions.

    -- Old
    local pass = lovr.graphics.getPass('transfer')
    pass:copy(image, texture)
    lovr.graphics.submit(pass)

    -- New
    texture:setPixels(image)

Compute Barriers
---

This is a small change, but there's a new `Pass:barrier` function that lets you sequence multiple
compute shader dispatches within a pass.  Since computes within a pass all ran at the same time, you
previously had to use multiple Pass objects to get computes to wait for each other, which is costly.
With `Pass:barrier`, all computes before the barrier will finish before further compute work starts.

Headless VR
---

The headset module can now be used in headless mode (spooky!).  This means it will still work even
when the graphics module is disabled.  The intended use case is for console applications that don't
need to render anything but still want to use pose data.  Note that this only works on certain XR
runtimes -- currently monado and SteamVR are known to work.

New Headset Simulator
---

The headset simulator incorporated changes from the
[`lovr-mousearm`](https://github.com/jmiskovic/lovr-mousearm) library.  The virtual hand is now
placed at the projected mouse position, and the scroll wheel can be used to control the hand
distance.  The shift key can also be used to "sprint", which is great for moving through large
worlds.

Mouse Input
---

Mouse input has been added to `lovr.system`.  You'll find the following new methods and callbacks:

- `lovr.system.getMouseX`
- `lovr.system.getMouseY`
- `lovr.system.getMousePosition`
- `lovr.system.isMouseDown`
- `lovr.mousepressed`
- `lovr.mousereleased`
- `lovr.mousemoved`
- `lovr.wheelmoved`

You might not need the `lovr-mouse` library anymore!

Tally Changes
---

Recording GPU timing info is now as simple as calling `lovr.graphics.setTimingEnabled`.  Stats will
be made available via `Pass:getStats`, with a frame or two of delay.  Timing stats are also active
by default when `t.graphics.debug` is set.

Pixel tallies (occlusion queries) also have a new revamped API.  Instead of using a `Tally` object
and a transfer pass, `Pass:beginTally` and `Pass:finishTally` will start and stop an occlusion
query.  The results for tallies can be copied to a Buffer after the Pass with `Pass:setTallyBuffer`.

Quality of Life
---

There are also a bunch of small improvements worth mentioning.

Drawing a texture on a plane no longer requires a call to `Pass:setMaterial`.  Instead, `Pass:draw`
can take a `Texture`:

    -- Old
    pass:setMaterial(texture)
    pass:plane(x, y, z, w, h)
    pass:setMaterial()

    -- New
    pass:draw(texture, x, y, z, w)

All objects now have the `Object:type` method to return their type name as a string.

There's a new `Image:mapPixel` function which is an easier way to set all the pixels of an Image.

Shaders now support `#include` to load shader code from LÖVR's filesystem.

When `t.graphics.debug` is set, shaders include debug info now.  This allows graphics debugging
tools like RenderDoc to inspect variables in a shader and step through each line interactively.

Vectors have capitalized constructors to create permanent vectors, e.g. `Vec3` can be used in
addition to `vec3`.

Vectors also have named constants: `vec3.up`, `vec4.one`, etc.

Physics has `World:queryBox` and `World:querySphere` to query all the Shapes that intersect a
volume.

Community
---

LÖVR's Slack is now deprecated because it held our messages hostage!  We migrated all the chat
history over to a [Matrix](https://matrix.org) homeserver hosted on `#community:lovr.org` and
bridged everything to a new Discord server.  Keeping the source of truth for chat on a self-hosted,
open source platform ensures the community is hopefully a bit more resilient to future corporate
monkey business.

Speaking of corporate monkey business, LÖVR has entrenched itself further into the GitHub ecosystem
by adding continuous releases via GitHub Actions!  This means us mere mortals can have up-to-date
builds for all platforms without needing to touch CMake or anything related to Android Studio.

For the remaining masochists among us who choose to build LÖVR from source, there has been a change
to the branching system.  The `dev` branch is now the default branch, and `master` has been renamed
to `stable`.  The development workflow otherwise remains the same, where new features go into `dev`
and bugfixes are made on `stable`.  The following commands will update a local clone:

    $ git branch -m master stable
    $ git fetch origin
    $ git branch -u origin/stable stable
    $ git remote set-head origin -a

Changelog
---
