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

namespace impeller.fb;

//-----------------------------------------------------------------------------
/// Materials.
///

struct Color {
  r: float;
  g: float;
  b: float;
  a: float;
}

enum ComponentType:byte {
  k8Bit,
  k16Bit,
}

table EmbeddedImage {
  bytes: [ubyte];
  component_count: ubyte = 0;
  component_type: ComponentType;
  width: uint;
  height: uint;
}

/// The `bytes` field takes precedent over the `uri` field.
/// If both the `uri` and `bytes` fields are empty, a fully opaque white
/// placeholder will be used.
table Texture {
  /// A Flutter asset URI for a compressed image file to import and decode.
  uri: string;
  /// Decompressed image bytes for uploading to the GPU. If this field is not
  /// empty, it takes precedent over the `uri` field for sourcing the texture.
  embedded_image: EmbeddedImage;
}

enum MaterialType:byte {
  kUnlit,
  kPhysicallyBased,
}

/// The final color of each material component is the texture color multiplied
/// by the factor of the component.
/// Texture fields are indices into the `Scene`->`textures` array. All textures
/// are optional -- a texture index value of -1 indicates no texture.
table Material {
  // When the `MaterialType` is `kUnlit`, only the `base_color` fields are used.
  type: MaterialType;

  base_color_factor: Color;
  base_color_texture: int = -1;

  metallic_factor: float = 0;
  roughness_factor: float = 0.5;
  metallic_roughness_texture: int = -1;  // Red=Metallic, Green=Roughness.

  normal_texture: int = -1;  // Tangent space normal map.

  occlusion_texture: int = -1;
}

//-----------------------------------------------------------------------------
/// Geometry.
///

struct Vec2 {
  x: float;
  y: float;
}

struct Vec3 {
  x: float;
  y: float;
  z: float;
}

struct Vec4 {
  x: float;
  y: float;
  z: float;
  w: float;
}

// This attribute layout is expected to be identical to that within
// `impeller/scene/shaders/geometry.vert`.
struct Vertex {
  position: Vec3;
  normal: Vec3;
  tangent: Vec4; // The 4th component determines the handedness of the tangent.
  texture_coords: Vec2;
  color: Color;
}

table UnskinnedVertexBuffer {
  vertices: [Vertex];
}

struct SkinnedVertex {
  vertex: Vertex;
  /// Four joint indices corresponding to this mesh's skin transforms. These
  /// are floats instead of ints because this vertex data is uploaded directly
  /// to the GPU, and float attributes work for all Impeller backends.
  joints: Vec4;
  /// Four weight values that specify the influence of the corresponding
  /// joints.
  weights: Vec4;
}

table SkinnedVertexBuffer {
  vertices: [SkinnedVertex];
}

union VertexBuffer { UnskinnedVertexBuffer, SkinnedVertexBuffer }

enum IndexType:byte {
  k16Bit,
  k32Bit,
}

table Indices {
  data: [ubyte];
  count: uint32;
  type: IndexType;
}

table MeshPrimitive {
  vertices: VertexBuffer;
  indices: Indices;
  material: Material;
}

//-----------------------------------------------------------------------------
/// Animations.
///

table TranslationKeyframes {
  values: [Vec3];
}

table RotationKeyframes {
  values: [Vec4];
}

table ScaleKeyframes {
  values: [Vec3];
}

union Keyframes { TranslationKeyframes, RotationKeyframes, ScaleKeyframes }

table Channel {
  node: int;  // Index into `Scene`->`nodes`.
  timeline: [float];
  keyframes: Keyframes;
}

table Animation {
  name: string;
  channels: [Channel];
}

table Skin {
  joints: [int];  // Indices into `Scene`->`nodes`.
  inverse_bind_matrices: [Matrix];
  /// The root joint of the skeleton.
  skeleton: int;  // Index into `Scene`->`nodes`.
}

//-----------------------------------------------------------------------------
/// Scene graph.
///

struct Matrix {
  m: [float:16];
}

table Node {
  name: string;
  children: [int];  // Indices into `Scene`->`nodes`.
  transform: Matrix;
  mesh_primitives: [MeshPrimitive];
  skin: Skin;
}

table Scene {
  children: [int];  // Indices into `Scene`->`nodes`.
  transform: Matrix;
  nodes: [Node];
  textures: [Texture];  // Textures may be reused across different materials.
  animations: [Animation];
}

root_type Scene;
file_identifier "IPSC";
