// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

library fuchsia.ui.gfx;

using fuchsia.mem;

// Commands that are used to modify the state of a |Session|.
// TODO(SCN-237): reorder Command definitions to match the order in this union.
union Command {
  CreateResourceCmd create_resource;
  ReleaseResourceCmd release_resource;
  ExportResourceCmd export_resource;
  ImportResourceCmd import_resource;

  // Tagging commands.
  SetTagCmd set_tag;

  // Grouping commands.
  DetachCmd detach;

  // Spatial commands.
  SetTranslationCmd set_translation;
  SetScaleCmd set_scale;
  SetRotationCmd set_rotation;
  SetAnchorCmd set_anchor;
  SetSizeCmd set_size;
  SetOpacityCmd set_opacity;

  SendSizeChangeHintCmdHACK send_size_change_hint_hack;

  // Node-specific commands.
  AddChildCmd add_child;  // TODO: Should we require a DetachCmd before
                              // re-parenting?
  AddPartCmd add_part;
  DetachChildrenCmd detach_children;
  SetShapeCmd set_shape;
  SetMaterialCmd set_material;
  SetClipCmd set_clip;
  SetHitTestBehaviorCmd set_hit_test_behavior;
  SetViewPropertiesCmd set_view_properties;
  TakeSnapshotCmdHACK take_snapshot_cmd;

  // Camera and lighting commands.
  SetCameraCmd set_camera;
  SetCameraTransformCmd set_camera_transform;
  SetCameraProjectionCmd set_camera_projection;
  SetStereoCameraProjectionCmd set_stereo_camera_projection;
  SetCameraPoseBufferCmd set_camera_pose_buffer;
  SetLightColorCmd set_light_color;
  SetLightDirectionCmd set_light_direction;
  AddLightCmd add_light;
  DetachLightCmd detach_light;
  DetachLightsCmd detach_lights;

  SetTextureCmd set_texture;
  SetColorCmd set_color;

  // Mesh commands.
  BindMeshBuffersCmd bind_mesh_buffers;

  // Layer and renderer commands.
  AddLayerCmd add_layer;
  RemoveLayerCmd remove_layer;
  RemoveAllLayersCmd remove_all_layers;
  SetLayerStackCmd set_layer_stack;
  SetRendererCmd set_renderer;
  SetRendererParamCmd set_renderer_param;

  // Events.
  SetEventMaskCmd set_event_mask;

  // Diagnostic commands.
  SetLabelCmd set_label;

  // Debugging commands.
  SetDisableClippingCmd set_disable_clipping;

  // TODO(SCN-1026): Remove this.
  SetImportFocusCmd set_import_focus;
};

// Instructs the compositor to create the specified |Resource|, and to register
// it in a table so that it can be referenced by subsequent commands.
struct CreateResourceCmd {
  // An ID that is currently not used within the session.
  uint32 id;
  ResourceArgs resource;
};

// Releases the client's reference to the resource; it is then illegal to use
// the ID in subsequent Commands.  Other references to the resource may exist,
// so releasing the resource does not result in its immediate destruction; it is
// only destroyed once the last reference is released.  For example, the
// resource may be required to render an in-progress frame, or it may be
// referred to by another resource).  However, the ID will be immediately
// unregistered, and may be reused to create a new resource.
struct ReleaseResourceCmd {
  // ID of the resource to be dereferenced.
  uint32 id;
};

// Create an external reference to the specified resource, which can then be
// imported into another Session by passing a handle to |token|'s peer to
// ImportResourceCmd; see that comment for more details.
//
// The importing client is typically in a different process than the exporter.
// No specific mechanism is provided for transferring a token from an exporter
// to an importer; collaborators may choose any out-of-band API they wish to do
// so.
struct ExportResourceCmd {
  uint32 id;
  handle<eventpair> token;
};

// Import a resource that was exported via ExportResourceCmd().  |token| is
// a handle to the eventpair peer that was used to export the resource, and
// |spec| describes the type of the imported resource, and the commands which
// can legally be applied to it.  Afterward, |id| can be used to refer to the
// resource in an Command, similarly (but not identically: see below) to a
// resource that was created in the session.  For example, you can add children
// to an imported EntityNode via AddChildCmd.
//
// However, note that the importer does not gain full access to the imported
// resource, but rather to an attenuated subset of its capabilities.  For
// example, you cannot use a DetachCmd to detach an imported EntityNode from
// its parent.
//
// Unlike ExportResourceCmd, there is no configurable timeout.  There is an
// expectation that the exported resource will become available in a short
// amount of time.  TODO: this needs elaboration... e.g. we might notify via the
// SessionListener when we know that the link will never be made (e.g. if the
// peer of the import token is destroyed).
//
// TODO: describe how the imported resource behaves if the exported resource
// isn't yet available, or becomes unavailable (e.g. an imported Material might
// act as a plain white texture).
struct ImportResourceCmd {
  uint32 id;
  handle<eventpair> token;
  ImportSpec spec;
};

// Maximum length for a resource label.
const uint32 kLabelMaxLength = 32;

// Sets/clears a label to help developers identify the purpose of the resource
// when using diagnostic tools.
//
// The label serves no functional purpose in the scene graph.  It exists only
// to help developers understand its structure.  The scene manager may truncate
// or discard labels at will.
//
// Constraints:
// - The label's maximum length is |kLabelMaxLength| characters.
// - Setting the label to an empty string clears it.
struct SetLabelCmd {
  uint32 id;
  string label;
};

// Add a node as a child to another node.
//
// Constraints:
// - |id| refs a Node with the has_children characteristic.
// - |child_id| refs any Node.
//
// Discussion:
// The child node is first removed from its existing parent, as if DetachCmd
// was applied first.
struct AddChildCmd {
  uint32 node_id;
  uint32 child_id;
};

// Add a node as a part of another node.  The implications of being a part
// rather than a child differ based on the type of the part.  However, one
// implication is constant: removing all of a node's children (e.g. via
// DetachChildrenCmd) does not affect its parts.  This is similar to the
// "shadow DOM" in a web browser: the controls of a <video> element are
// implemented as using the shadow DOM, and do no show up amongst the children
// of that element.
//
// Constraints:
// - |id| refs a Node with the has_parts characteristic.
// - |part_id| refs any Node.
//
// Discussion:
// The part node is first removed from its existing parent, as if DetachCmd
// was applied first.
struct AddPartCmd {
  uint32 node_id;
  uint32 part_id;
};

interface SnapshotCallbackHACK {
  1: OnData(fuchsia.mem.Buffer data);
};

struct TakeSnapshotCmdHACK {
  uint32 node_id;
  SnapshotCallbackHACK callback;
};

// Detaches a parentable object from its parent (e.g. a node from a parent node,
// or a layer from a layer stack).  It is illegal to apply this command to a
// non-parentable object.  No-op if the target object currently has no parent.
//
// Constraints:
// - |id| refs a parentable object
//
// Discussion:
// For nodes, this command will detach a node from its parent, regardless of
// whether it is a part or a child of its parent.
struct DetachCmd {
  uint32 id;
};

// Detaches all of a node's children (but not its parts).
struct DetachChildrenCmd {
  uint32 node_id;
};

// Sets/clears a node's tag value.
//
// A session can apply a tag value to any node to which it has access, including
// imported nodes.  These tags are private to the session and cannot be read
// or modified by other sessions.  When multiple sessions import the same node,
// each session will only observe its own tag values.
//
// Hit test results for a session only include nodes which the session has
// tagged with a non-zero value.  Therefore a session can use tag values to
// associate nodes with their functional purpose when picked.
//
// Constraints:
// - |node_id| refs a |Node|.
// - |tag_value| is the tag value to assign, or 0 to remove the tag.
struct SetTagCmd {
  uint32 node_id;
  uint32 tag_value;
};

// Sets a Resource's (typically a Node's) translation.
//
// Constraints:
// - |id| refs a Resource with the has_transform characteristic.
struct SetTranslationCmd {
  uint32 id;
  Vector3Value value;
};

// Sets a Resource's (typically a Node's) scale.
//
// Constraints:
// - |id| refs a Resource with the has_transform characteristic.
struct SetScaleCmd {
  uint32 id;
  Vector3Value value;
};

// Sets a Resource's (typically a Node's) rotation.
//
// Constraints:
// - |id| refs a Resource with the has_transform characteristic.
struct SetRotationCmd {
  uint32 id;
  QuaternionValue value;
};

// Sets a Resource's (typically a Node's) anchor point.
//
// Constraints:
// - |id| refs a Resource with the has_transform characteristic.
struct SetAnchorCmd {
  uint32 id;
  Vector3Value value;
};

// Sets an object's size.
//
// Constraints:
// - |id| refs a resizeable object.
// - some objects that support this command may have additional constraints
//   (e.g. in some cases |depth| must be zero).
struct SetSizeCmd {
  uint32 id;
  Vector2Value value;
};

// Sends a hint about a pending size change to the given node and all nodes
// below. This is generally sent before an animation.
//
// |width_change_factor| and |height_change_factor| is how much bigger or smaller
// the item is expected to be in the near future. This one number encapsulate
// both changes in scale, as well as changes to layout width and height.
struct SendSizeChangeHintCmdHACK {
  uint32 node_id;
  float32 width_change_factor;
  float32 height_change_factor;
};

// Sets a node's opacity.
//
// Constraints:
// - |node_id| refs a |Node| with the has_opacity characteristic.
// - |opacity| is in the range [0, 1].
struct SetOpacityCmd {
  uint32 node_id;
  float32 opacity;
};

// Sets/clears a node's shape.
//
// Constraints:
// - |node_id| refs a |Node| with the has_shape characteristic.
// - |shape_id| refs a |Shape|, or nothing.
// - if this command causes the target to have both a |Shape| and a |Material|,
//   then these must be compatible with each other (see README.md regarding
//   "Shape/Material Compatibility").
// TODO: add "Shape/Material Compatibility section"
//
// Discussion:
// In order to be painted, a node requires both a |Shape| and a |Material|.
// Without a material, a node can still participate in hit-testing and clipping.
// Without a shape, a node cannot do any of the above.
struct SetShapeCmd {
  uint32 node_id;
  uint32 shape_id;
};

// Sets/clears a node's material.
//
// Constraints:
// - |node_id| refs a |Node| with the has_material characteristic.
// - |material_id| refs a |Material|, or nothing.
// - if this command causes the target to have both a |Shape| and a |Material|,
//   then these must be compatible with each other (see README.md regarding
//   "Shape/Material Compatibility").
// TODO: add "Shape/Material Compatibility section"
//
// Discussion:
// In order to be painted, a node requires both a |Shape| and a |Material|.
// Without a material, a node can still participate in hit-testing and clipping.
// Without a shape, a node cannot do any of the above.
struct SetMaterialCmd {
  uint32 node_id;
  uint32 material_id;
};

// Sets/clears a node's clip.
//
// Constraints:
// - |node_id| refs a |Node| with the has_clip characteristic.
// - |clip_id| a |Node| with the is_clip characteristic, or nothing.  If the
//   referenced node is not rooted, then it will have no effect (since its
//   full world-transform cannot be determined).
// - |clip_to_self| If false, children are only clipped to the region specified
//   by |clip_id|.  If true, children are additionally clipped to the node's
//   shape (as determined by its ShapeNode parts).
//
// Discussion:
// If a node has a clip, it will be applied to both the parts and the children
// of the node.  Under some circumstances (TBD), a clip will not be applicable
// to a node; in such cases it will be as though no clip has been specified for
// the node.
// TODO: elaborate on the circumstances under which a clip is inapplicable.
// For example, consider a 3D space that looks through a portal into a 2D space
// that uses a clip for a circular reveal.  It would not be meaningful to clip
// objects on the outside (i.e. in the 3D space).
struct SetClipCmd {
  uint32 node_id;
  uint32 clip_id;
  bool clip_to_self;
};

// Sets a node's hit test behavior.
//
// Discussion:
// By default, hit testing is performed on the node's content, its parts,
// and its children.
struct SetHitTestBehaviorCmd {
  uint32 node_id;
  HitTestBehavior hit_test_behavior;
};

// Sets the properties for a ViewHolder's attached View.
//
// Constraints:
// - |view_holder_id| refs a |ViewHolder|.
struct SetViewPropertiesCmd {
  uint32 view_holder_id;
  ViewProperties properties;
};

// Sets a renderer's camera.
//
// Constraints:
// - |renderer_id| refs a |Renderer|.
// - |camera_id| refs a |Camera|, or stops rendering by passing zero.
// - |matrix| is a value or variable of type kMatrix4x4.
struct SetCameraCmd {
  uint32 renderer_id;
  uint32 camera_id;
};

// Sets a camera's view matrix.
// This operation can be applied to both Cameras and StereoCameras.
//
// Constraints:
// - |camera_id| refs a |Camera|.
// - |eye_position| is the position of the eye.
// - |eye_look_at| is the point is the scene the that eye is pointed at.
// - |eye_up| defines the camera's "up" vector.
struct SetCameraTransformCmd {
  uint32 camera_id;
  Vector3Value eye_position;
  Vector3Value eye_look_at;
  Vector3Value eye_up;
};

// Sets a camera's projection matrix.
// This operation cannot be applied to a StereoCamera.
//
// Constraints:
// - |camera_id| refs a |Camera| that is not a |StereoCamera|.
// - |fovy| is the Y-axis field of view, in radians.
//
// NOTE: A default orthographic projection is specified by setting |fovy| to
// zero.  In this case, the camera transform is ignored.
struct SetCameraProjectionCmd {
  uint32 camera_id;
  FloatValue fovy;  // Y-axis field of view, in radians.
};

// Sets a StereoCamera's projection matrices.
// This operation can only be applied to a StereoCamera.
//
// Constraints:
// - |camera_id| refs a |StereoCamera|.
// - |left_projection| is the projection matrix for the left eye.
// - |right_projection| is the projection matrix for the right eye.
//
// These projection matrices may also contain a transform in camera space for
// their eye if needed.
struct SetStereoCameraProjectionCmd {
  uint32 camera_id;
  Matrix4Value left_projection;
  Matrix4Value right_projection;
};

// Sets the "pose buffer" for the camera identified by |camera_id|.
// This operation can be applied to both Cameras and StereoCameras.
//
// This will override any position and rotation set for the camera and will
// make it take its position and rotation from the pose buffer each frame
// based on the presentation time for that frame.
//
// A pose buffer represents a ring buffer of poses for a fixed number of time
// points in the future. Each entry in the buffer identified by |buffer_id| is
// a quaternion and a position layed out as follows:
//
// struct Pose {
//   // Quaternion
//   float32 a;
//   float32 b;
//   float32 c;
//   float32 d;
//
//   // Position
//   float32 x;
//   float32 y;
//   float32 z;
//
//   // Reserved/Padding
//   byte[4] reserved;
// }
//
// The buffer can be thought of as a packed array of |num_entries| Pose structs
// and is required to be at least num_entries * sizeof(Pose) bytes.
//
// The quaternions and positions are specified in the space of the camera's
// parent node.
//
// |base_time| is a base time point expressed in nanoseconds in the
// |CLOCK_MONOTONIC| timebase and |time_interval| is the time in nanoseconds
// between entries in the buffer. |base_time| must be in the past.
//
// For a given point in time |t| expressed in nanoseconds in the
// |CLOCK_MONOTONIC| timebase the index of the corresponding pose in
// the pose buffer can be computed as follows:
//
// index(t) = ((t - base_time) / time_interval) % num_entries
//
// poses[index(t)] is valid for t over the time interval (t - time_interval, t]
// and should be expected to updated continuously without synchronization
// for the duration of that interval. If a single pose value is needed for
// multiple non-atomic operations a value should be latched and stored outside
// the pose buffer.
//
// Because the poses are not protected by any synchronization primitives it is
// possible that when a pose is latched it will be only partially updated, and
// the pose being read will contain some components from the pose before it is
// updated and some components from the updated pose. The safety of using these
// "torn" poses relies on two things:
//
// 1) Sequential poses written to poses[index(t)] are very similar to each
// other numerically, so that if some components are taken from the first and
// some are taken from another the result is numerically similar to both
//
// 2) The space of positions and quaternions is locally flat at the scale of
// changes between sequential updates, which guarantees that two poses which
// are numerically similar also represent semantically similar poses (i.e.
// there are no discontinuities which will cause a small numerical change in
// the position or quaterninon to cause a large change in the encoded pose)
// For positions this is guaranteed because Scenic uses a Euclidean 3-space
// which is globally flat and for quaternions this is guaranteed because
// quaternions encode rotation as points on a unit 4-sphere, and spheres are
// locally flat. For more details on the encoding of rotations in quaterions
// see https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
//
// This commanderation is intended for late latching camera pose to support
// low-latency motion-tracked rendering.
struct SetCameraPoseBufferCmd {
  uint32 camera_id;
  uint32 buffer_id;
  uint32 num_entries;
  int64 base_time;
  uint64 time_interval;
};

// Sets the color of the Light identified by |light_id|.
struct SetLightColorCmd {
  uint32 light_id;
  ColorRgbValue color;
};

// Sets the direction of the DirectionalLight identified by |light_id|.
struct SetLightDirectionCmd {
  uint32 light_id;
  Vector3Value direction;
};

// Adds the light specified by |light_id| specified by |light_id| to the scene
// identified by |scene_id|.
struct AddLightCmd {
  uint32 scene_id;
  uint32 light_id;
};

// Detach the light specified by |light_id| from the scene that it is attached
// to, if any.
struct DetachLightCmd {
  uint32 light_id;
};

// Detach all lights from the scene specified by |scene_id|.
struct DetachLightsCmd {
  uint32 scene_id;
};

// Sets/clears a material's texture.
//
// Constraints:
// - |material_id| refs a |Material|.
// - |texture_id| refs a |Image|, |ImagePipe|, or nothing.
//
// If no texture is provided (i.e. |texture_id| is zero), a solid color is used.
// If a texture is provided, then the value sampled from the texture is
// multiplied by the color.
struct SetTextureCmd {
  uint32 material_id;
  uint32 texture_id;  // Refers to an Image resource.  May be zero (no texture).
};

// Sets a material's color.
//
// Constraints:
// - |material_id| refs a |Material|.
//
// If a texture is set on the material, then the value sampled from the texture
// is multiplied by the color.
struct SetColorCmd {
  uint32 material_id;
  ColorRgbaValue color;
};

// Set a mesh's indices and vertices.
//
// |mesh_id| refs the Mesh to be updated.
// |index_buffer_id| refs a Buffer that contains the mesh indices.
// |index_format| defines how the index buffer data is to be interpreted.
// |index_offset| number of bytes from the start of the index Buffer.
// |index_count| number of indices.
// |vertex_buffer_id| refs a Buffer that contains the mesh vertices.
// |vertex_format| defines how the vertex buffer data is to be interpreted.
// |vertex_offset| number of bytes from the start of the vertex Buffer.
// |vertex_count| number of vertices.
// |bounding_box| must contain all vertices within the specified range.
//
// The MeshVertexFormat defines which per-vertex attributes are provided by the
// mesh, and the size of each attribute (and therefore the size of each vertex).
// The attributes are ordered within the vertex in the same order that they
// appear within the MeshVertexFormat struct.  For example, if the values are
// kVector3, kNone and kVector2, then:
//   - each vertex has a position and UV-coordinates, but no surface normal.
//   - the 3D position occupies bytes 0-11 (3 dimensions * 4 bytes per float32).
//   - the UV coords occupy bytes 12-19, since no surface normal is provided.
enum MeshIndexFormat {
  // TODO(SCN-275): only kUint32 is currently supported.
  kUint16 = 1;
  kUint32 = 2;
};

struct MeshVertexFormat {
  // kVector2 or kVector3.
  ValueType position_type;
  // kVector2 or kVector3 (must match position_type), or kNone.
  ValueType normal_type;
  // kVector2 or kNone.
  ValueType tex_coord_type;
};

struct BindMeshBuffersCmd {
  uint32 mesh_id;
  uint32 index_buffer_id;
  MeshIndexFormat index_format;
  uint64 index_offset;
  uint32 index_count;
  uint32 vertex_buffer_id;
  MeshVertexFormat vertex_format;
  uint64 vertex_offset;
  uint32 vertex_count;
  BoundingBox bounding_box;
};

// Add a layer to a layer stack.
// Constraints:
// - |layer_stack_id| refs a |LayerStack|.
// - |layer_id| refs a |Layer|.
// - The layer must not already belong to a different stack; it must first be
//   detached.
struct AddLayerCmd {
  uint32 layer_stack_id;
  uint32 layer_id;
};

// Remove a layer from a layer stack.
// Constraints:
// - |layer_stack_id| refs a |LayerStack|.
// - |layer_id| refs a |Layer|.
// - The layer must belong to this stack.
struct RemoveLayerCmd {
  uint32 layer_stack_id;
  uint32 layer_id;
};

// Remove all layers from a layer stack.
// Constraints
// - |layer_stack_id| refs a |LayerStack|.
struct RemoveAllLayersCmd {
  uint32 layer_stack_id;
};

// Set a compositor's layer stack, replacing the current stack (if any).
// Constraints:
// - |compositor_id| refs a |DisplayCompositor| or |ImagePipeCompositor|.
// - |layer_stack_id| refs a |LayerStack|.
struct SetLayerStackCmd {
  uint32 compositor_id;
  uint32 layer_stack_id;
};

// Set a layer's renderer, replacing the current renderer (if any).
// Constraints:
// - |layer_id| refs a |Layer|.
// - |renderer_id| refs a |Renderer|.
struct SetRendererCmd {
  uint32 layer_id;
  uint32 renderer_id;
};

// Sets a parameter that affects how a renderer renders a scene.
//
// |renderer_id| refs the Renderer that is being modified.
// |param| describes the parameter that should be set, and to what.
struct SetRendererParamCmd {
  uint32 renderer_id;
  RendererParam param;
};

// Sets which events a resource should deliver to the session listener.
// This command replaces any prior event mask for the resource.
//
// The initial event mask for a resource is zero, meaning no events are
// reported.
//
// Constraints:
// - |resource_id| is a valid resource id
// - |event_mask| is zero or a combination of |k*EventMask| bits OR'ed together.
struct SetEventMaskCmd {
  uint32 id;
  uint32 event_mask;
};

// Set whether clipping should be disabled for the specified renderer.  For a
// newly-created renderer, clipping will NOT be disabled (i.e. it will be
// enabled).
//
// NOTE: this disables visual clipping only; objects are still clipped for the
// purposes of hit-testing.
//
// |renderer_id| refs the target renderer.
// |disable_clipping| specifies whether the clipping should be disabled.
struct SetDisableClippingCmd {
  uint32 renderer_id;
  bool disable_clipping;
};

// TODO(SCN-1026): Remove this.
struct SetImportFocusCmd {
  uint32 id;
  bool focusable;
};