// Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
//
// SPDX-License-Identifier: CC-BY-4.0

include::{generated}/meta/XR_FB_triangle_mesh.adoc[]

*Contributors*::
    Anton Vaneev, Facebook +
    Cass Everitt, Facebook +
    Federico Schliemann, Facebook +
    Johannes Schmid, Facebook


*Overview*

Meshes may be useful in XR applications when representing parts of the
environment.
In particular, application may provide the surfaces of real-world objects
tagged manually to the runtime, or obtain automatically detected environment
contents.

This extension allows:

* An application to create a triangle mesh and specify the mesh data.
* An application to update mesh contents if a mesh is mutable.

In order to enable the functionality of this extension, the application
must: pass the name of the extension into flink:xrCreateInstance via the
slink:XrInstanceCreateInfo::pname:enabledExtensionNames parameter as
indicated in the <<fundamentals-extensions>> section.

*New Object Types*

[open,refpage='XrTriangleMeshFB',type='handles',desc='Triangle mesh']
--
include::{generated}/api/handles/XrTriangleMeshFB.adoc[]

slink:XrTriangleMeshFB represents a triangle mesh with its corresponding
mesh data: a vertex buffer and an index buffer.
--

*New Flag Types*

[open,refpage='XrTriangleMeshFlagsFB',type='flags',desc='XrTriangleMeshFlagsFB',xrefs='XrTriangleMeshFlagBitsFB']
--
include::{generated}/api/flags/XrTriangleMeshFlagsFB.adoc[]
--

[open,refpage='XrTriangleMeshFlagBitsFB',type='enums',desc='XrTriangleMeshFlagBitsFB',xrefs='XrTriangleMeshFlagsFB']
--
include::{generated}/api/enums/XrTriangleMeshFlagBitsFB.adoc[]
include::{generated}/api/enums/XrTriangleMeshFlagBitsFB.comments.adoc[]
--

*New Enum Constants*

elink:XrStructureType enumeration is extended with:

* ename:XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB

*New Enums*

[open,refpage='XrWindingOrderFB',desc='Triangle winding order',type='enums']
--
Applications may specify the triangle winding order of a mesh - whether the
vertices of an outward-facing side of a triangle appear in clockwise or
counter-clockwise order - using elink:XrWindingOrderFB enumeration.

include::{generated}/api/enums/XrWindingOrderFB.adoc[]
include::{generated}/api/enums/XrWindingOrderFB.comments-box.adoc[]
--

*New Structures*

[open,refpage='XrTriangleMeshCreateInfoFB',type='structs',desc='The information to create a triangle mesh',xrefs='']
--

slink:XrTriangleMeshCreateInfoFB must: be provided when calling
flink:xrCreateTriangleMeshFB.

The slink:XrTriangleMeshCreateInfoFB structure is defined as:

include::{generated}/api/structs/XrTriangleMeshCreateInfoFB.adoc[]

.Member Descriptions
****
* pname:type is the elink:XrStructureType of this structure.
* pname:next is code:NULL or a pointer to the next structure in a structure
  chain.
  No such structures are defined in core OpenXR or this extension.
* pname:flags is a bitmask of elink:XrTriangleMeshFlagBitsFB that specify
  behavior.
* pname:windingOrder is the elink:XrWindingOrderFB value defining the
  winding order of the mesh triangles.
* pname:vertexCount is the number of vertices in the mesh.
  In the case of the mutable mesh, the value is treated as the maximum
  number of vertices the mesh will be able to represent at any time in its
  lifecycle.
  The actual number of vertices can vary and is defined when
  flink:xrTriangleMeshEndUpdateFB is called.
* pname:vertexBuffer is a pointer to the vertex data.
  The size of the array must be pname:vertexCount elements.
  When the mesh is mutable (`(pname:flags &
  ename:XR_TRIANGLE_MESH_MUTABLE_BIT_FB) != 0`), the pname:vertexBuffer
  parameter must: be code:NULL and mesh data must: be populated separately.
* pname:triangleCount is the number of triangles in the mesh.
  In the case of the mutable mesh, the value is treated as the maximum
  number of triangles the mesh will be able to represent at any time in its
  lifecycle.
  The actual number of triangles can vary and is defined when
  flink:xrTriangleMeshEndUpdateFB is called.
* pname:indexBuffer the triangle indices.
  The size of the array must be pname:triangleCount elements.
  When the mesh is mutable (`(pname:flags &
  ename:XR_TRIANGLE_MESH_MUTABLE_BIT_FB) != 0`), the pname:indexBuffer
  parameter must: be code:NULL and mesh data must: be populated separately.
****

Mesh buffers can: be updated between flink:xrTriangleMeshBeginUpdateFB and
flink:xrTriangleMeshEndUpdateFB calls.

If the mesh is non-mutable, pname:vertexBuffer must: be a pointer to an
array of pname:vertexCount slink:XrVector3f structures.
If the mesh is non-mutable, pname:indexBuffer must: be a pointer to an array
of 3 * pname:triangleCount code:uint32_t vertex indices.

include::{generated}/validity/structs/XrTriangleMeshCreateInfoFB.adoc[]
--

*Mutable Mesh Update States*

Mutable meshes have a state machine controlling how they may be updated.

image::images/fb_trimesh_states.svg[opts=inline, align="center", title="Mutable Triangle Mesh States"]

The states are as follows:

[[fb_triangle_mesh_state_undefined_topology]]Undefined Topology::
  The default state immediately after creation of a mutable mesh.
  Move to <<fb_triangle_mesh_state_defining_topology>> by calling
  flink:xrTriangleMeshBeginUpdateFB.

[[fb_triangle_mesh_state_defining_topology]]Defining Topology::
  The application must: set the initial vertex buffer and index buffer
  before moving to <<fb_triangle_mesh_state_ready>> by calling
  flink:xrTriangleMeshEndUpdateFB.

[[fb_triangle_mesh_state_ready]]Ready::
  In this state, the buffer contents/size must: not be modified.
  To move to <<fb_triangle_mesh_state_updating_mesh>> call
  flink:xrTriangleMeshBeginUpdateFB.
  To move to <<fb_triangle_mesh_state_updating_vertices>> call
  flink:xrTriangleMeshBeginVertexBufferUpdateFB.

[[fb_triangle_mesh_state_updating_mesh]]Updating Mesh::
  The application may: modify the vertex buffer contents and/or the vertex
  count.
  The application may: modify the index buffer contents and/or the index
  buffer element count.
  Move to <<fb_triangle_mesh_state_ready>> and commit changes by calling
  flink:xrTriangleMeshEndUpdateFB.

[[fb_triangle_mesh_state_updating_vertices]]Updating Vertices::
  The application may: modify the vertex buffer contents, but not the vertex
  count.
  Move to <<fb_triangle_mesh_state_ready>> and commit changes by calling
  flink:xrTriangleMeshEndVertexBufferUpdateFB.

*New Functions*

[open,refpage='xrCreateTriangleMeshFB',desc='Create a triangle mesh',type='protos',xrefs='XrTriangleMeshFB XrTriangleMeshCreateInfoFB']
--
The flink:xrCreateTriangleMeshFB function is defined as:

include::{generated}/api/protos/xrCreateTriangleMeshFB.adoc[]

.Parameter Descriptions
****
* pname:session is the slink:XrSession to which the mesh will belong.
* pname:createInfo is a pointer to an slink:XrTriangleMeshCreateInfoFB
  structure containing parameters to be used to create the mesh.
* pname:outTriangleMesh is a pointer to a handle in which the created
  slink:XrTriangleMeshFB is returned.
****

This creates an slink:XrTriangleMeshFB handle.
The returned triangle mesh handle may: be subsequently used in API calls.

When the mesh is mutable (the ename:XR_TRIANGLE_MESH_MUTABLE_BIT_FB bit is
set in slink:XrTriangleMeshCreateInfoFB::pname:flags), the created triangle
mesh starts in the <<fb_triangle_mesh_state_undefined_topology>> state.

Immutable meshes have no state machine; they may be considered to be in
state <<fb_triangle_mesh_state_ready>> with no valid edges leaving that
state.

include::{generated}/validity/protos/xrCreateTriangleMeshFB.adoc[]
--

[open,refpage='xrDestroyTriangleMeshFB',desc='Destroy a triangle mesh',type='protos',xrefs='XrTriangleMeshFB']
--
The flink:xrDestroyTriangleMeshFB function is defined as:

include::{generated}/api/protos/xrDestroyTriangleMeshFB.adoc[]

.Parameter Descriptions
****
* pname:mesh is the slink:XrTriangleMeshFB to destroy.
****

slink:XrTriangleMeshFB handles and their associated data are destroyed by
flink:xrDestroyTriangleMeshFB.
The mesh buffers retrieved by flink:xrTriangleMeshGetVertexBufferFB and
flink:xrTriangleMeshGetIndexBufferFB must: not be accessed anymore after
their parent mesh object has been destroyed.

include::{generated}/validity/protos/xrDestroyTriangleMeshFB.adoc[]
--

[open,refpage='xrTriangleMeshGetVertexBufferFB',desc='Obtain the vertex buffer of a triangle mesh',type='protos',xrefs='xrTriangleMeshGetIndexBufferFB']
--
The flink:xrTriangleMeshGetVertexBufferFB function is defined as:

include::{generated}/api/protos/xrTriangleMeshGetVertexBufferFB.adoc[]

.Parameter Descriptions
****
* pname:mesh is the slink:XrTriangleMeshFB to get the vertex buffer for.
* pname:outVertexBuffer is a pointer to return the vertex buffer into.
****

Retrieves a pointer to the vertex buffer.
The vertex buffer is structured as an array of slink:XrVector3f.
The size of the buffer is
slink:XrTriangleMeshCreateInfoFB::pname:vertexCount elements.
The buffer location is guaranteed to remain constant over the lifecycle of
the mesh object.

A mesh must: be mutable and in a specific state for the application to
**modify** it through the retrieved vertex buffer.

* A mutable triangle mesh must: be in state
  <<fb_triangle_mesh_state_defining_topology>>,
  <<fb_triangle_mesh_state_updating_mesh>>, or
  <<fb_triangle_mesh_state_updating_vertices>> to modify the *contents* of
  the vertex buffer retrieved by this function.
* A mutable triangle mesh must: be in state
  <<fb_triangle_mesh_state_defining_topology>> or
  <<fb_triangle_mesh_state_updating_mesh>> to modify the *count* of elements
  in the vertex buffer retrieved by this function.
  The new count is passed as a parameter to flink:xrTriangleMeshEndUpdateFB.

include::{generated}/validity/protos/xrTriangleMeshGetVertexBufferFB.adoc[]
--

[open,refpage='xrTriangleMeshGetIndexBufferFB',desc='Obtain the index buffer of a triangle mesh',type='protos',xrefs='xrTriangleMeshGetVertexBufferFB']
--
The flink:xrTriangleMeshGetIndexBufferFB function is defined as:

include::{generated}/api/protos/xrTriangleMeshGetIndexBufferFB.adoc[]

.Parameter Descriptions
****
* pname:mesh is the slink:XrTriangleMeshFB to get the index buffer for.
* pname:outIndexBuffer is a pointer to return the index buffer into.
****

Retrieves a pointer to the index buffer that defines the topology of the
triangle mesh.
Each triplet of consecutive elements points to three vertices in the vertex
buffer and thus form a triangle.
The size of the index buffer is [eq]#3 *
slink:XrTriangleMeshCreateInfoFB::pname:triangleCount# elements.
The buffer location is guaranteed to remain constant over the lifecycle of
the mesh object.

A triangle mesh must: be mutable and in state
<<fb_triangle_mesh_state_defining_topology>> or
<<fb_triangle_mesh_state_updating_mesh>> for the application to **modify**
the contents and/or triangle count in the index buffer retrieved by this
function.

include::{generated}/validity/protos/xrTriangleMeshGetIndexBufferFB.adoc[]
--

[open,refpage='xrTriangleMeshBeginUpdateFB',desc='Begin an update of the mesh data',type='protos',xrefs='xrTriangleMeshEndUpdateFB']
--
The flink:xrTriangleMeshBeginUpdateFB function is defined as:

include::{generated}/api/protos/xrTriangleMeshBeginUpdateFB.adoc[]

.Parameter Descriptions
****
* pname:mesh is the slink:XrTriangleMeshFB to update.
****

Begins updating the mesh buffer data.
The application must: call this function before it makes any modifications
to the buffers retrieved by flink:xrTriangleMeshGetVertexBufferFB and
flink:xrTriangleMeshGetIndexBufferFB.
If only the vertex buffer contents need to be updated, and the mesh is in
state <<fb_triangle_mesh_state_ready>>,
flink:xrTriangleMeshBeginVertexBufferUpdateFB may: be used instead.
To commit the modifications, the application must: call
flink:xrTriangleMeshEndUpdateFB.

The triangle mesh pname:mesh must: be mutable.
The runtime must: return ename:XR_ERROR_VALIDATION_FAILURE if the mesh is
immutable.

The triangle mesh pname:mesh must: be in state
<<fb_triangle_mesh_state_undefined_topology>> or
<<fb_triangle_mesh_state_ready>>.

* If the triangle mesh is in state
  <<fb_triangle_mesh_state_undefined_topology>> before this call, a
  successful call moves it to state
  <<fb_triangle_mesh_state_defining_topology>>.
* If the triangle mesh is in state <<fb_triangle_mesh_state_ready>> before
  this call, a successful call moves it to state
  <<fb_triangle_mesh_state_updating_mesh>>.

include::{generated}/validity/protos/xrTriangleMeshBeginUpdateFB.adoc[]
--

[open,refpage='xrTriangleMeshEndUpdateFB',desc='End an update of the mesh data',type='protos',xrefs='xrTriangleMeshBeginUpdateFB']
--
The flink:xrTriangleMeshEndUpdateFB function is defined as:

include::{generated}/api/protos/xrTriangleMeshEndUpdateFB.adoc[]

.Parameter Descriptions
****
* pname:mesh is the slink:XrTriangleMeshFB to update.
* pname:vertexCount is the vertex count after the update.
* pname:triangleCount is the triangle count after the update.
****

Signals to the runtime that the application has finished initially
populating or updating the mesh buffers.
pname:vertexCount and pname:triangleCount specify the actual number of
primitives that make up the mesh after the update.
They must: be larger than zero but smaller or equal to the maximum counts
defined at create time.
The runtime must: return ename:XR_ERROR_VALIDATION_FAILURE if an invalid
count is passed.

The triangle mesh pname:mesh must: be mutable.
The runtime must: return ename:XR_ERROR_VALIDATION_FAILURE if the mesh is
immutable.

The triangle mesh pname:mesh must: be in state
<<fb_triangle_mesh_state_defining_topology>> or
<<fb_triangle_mesh_state_updating_mesh>>.

A successful call moves pname:mesh to state
<<fb_triangle_mesh_state_ready>>.

include::{generated}/validity/protos/xrTriangleMeshEndUpdateFB.adoc[]
--

[open,refpage='xrTriangleMeshBeginVertexBufferUpdateFB',desc='Begin an update of the vertex data',type='protos',xrefs='xrTriangleMeshBeginUpdateFB xrTriangleMeshEndVertexBufferUpdateFB']
--
The flink:xrTriangleMeshBeginVertexBufferUpdateFB function is defined as:

include::{generated}/api/protos/xrTriangleMeshBeginVertexBufferUpdateFB.adoc[]

.Parameter Descriptions
****
* pname:mesh is the slink:XrTriangleMeshFB to update.
* pname:outVertexCount is a pointer to a value to populate with the current
  vertex count.
  The updated data must have the exact same number of vertices.
****

Begins an update of the vertex positions of a mutable triangle mesh.
The vertex count returned through pname:outVertexCount is defined by the
last call to flink:xrTriangleMeshEndUpdateFB.
Once the modification is done, call
flink:xrTriangleMeshEndVertexBufferUpdateFB to commit the changes and move
to state <<fb_triangle_mesh_state_ready>>.

The triangle mesh pname:mesh must: be mutable.
The runtime must: return ename:XR_ERROR_VALIDATION_FAILURE if the mesh is
immutable.

The triangle mesh pname:mesh must: be in state
<<fb_triangle_mesh_state_ready>>.

A successful call moves pname:mesh to state
<<fb_triangle_mesh_state_updating_vertices>>.

include::{generated}/validity/protos/xrTriangleMeshBeginVertexBufferUpdateFB.adoc[]
--

[open,refpage='xrTriangleMeshEndVertexBufferUpdateFB',desc='End an update of the vertex data',type='protos',xrefs='xrTriangleMeshBeginVertexBufferUpdateFB']
--
The flink:xrTriangleMeshEndVertexBufferUpdateFB function is defined as:

include::{generated}/api/protos/xrTriangleMeshEndVertexBufferUpdateFB.adoc[]

.Parameter Descriptions
****
* pname:mesh is the slink:XrTriangleMeshFB to update.
****

Signals to the runtime that the application has finished updating the vertex
buffer data following a call to
flink:xrTriangleMeshBeginVertexBufferUpdateFB.

The triangle mesh pname:mesh must: be mutable.
The runtime must: return ename:XR_ERROR_VALIDATION_FAILURE if the mesh is
immutable.

The triangle mesh pname:mesh must: be in state
<<fb_triangle_mesh_state_updating_vertices>>.

A successful call moves pname:mesh to state
<<fb_triangle_mesh_state_ready>>.

include::{generated}/validity/protos/xrTriangleMeshEndVertexBufferUpdateFB.adoc[]
--

*Issues*

*Version History*

* Revision 1, 2021-09-01 (Anton Vaneev)
** Initial extension description
* Revision 2, 2022-01-07 (Rylie Pavlik, Collabora, Ltd.)
** Add a state diagram to clarify valid usage, and allow
   ename:XR_ERROR_CALL_ORDER_INVALID.
