// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

library vector_math.test.geometry_test;

import 'dart:typed_data';

import 'package:test/test.dart';

import 'package:vector_math/vector_math.dart';
import 'package:vector_math/vector_math_lists.dart';
import 'package:vector_math/vector_math_geometry.dart';

import 'test_utils.dart';

void testGenerateNormals() {
  final Vector3List positions = Vector3List.fromList([
    Vector3(-1.0, 1.0, 1.0),
    Vector3(1.0, 1.0, 1.0),
    Vector3(1.0, 1.0, -1.0),
    Vector3(1.0, -1.0, 1.0),
  ]);

  final Uint16List indices = Uint16List.fromList([0, 1, 2, 3, 2, 1]);

  final normals = Vector3List(positions.length);

  generateNormals(normals, positions, indices);

  relativeTest(normals[0], Vector3(0.0, 1.0, 0.0));
  relativeTest(normals[1], Vector3(0.70710, 0.70710, 0.0));
  relativeTest(normals[2], Vector3(0.70710, 0.70710, 0.0));
  relativeTest(normals[3], Vector3(1.0, 0.0, 0.0));
}

void testGenerateTangents() {
  final Vector3List positions = Vector3List.fromList([
    Vector3(-1.0, 1.0, 1.0),
    Vector3(1.0, 1.0, 1.0),
    Vector3(1.0, 1.0, -1.0),
    Vector3(1.0, -1.0, 1.0),
  ]);

  final Vector3List normals = Vector3List.fromList([
    Vector3(0.0, 1.0, 0.0),
    Vector3(0.70710, 0.70710, 0.0),
    Vector3(0.70710, 0.70710, 0.0),
    Vector3(1.0, 0.0, 0.0),
  ]);

  final Vector2List texCoords = Vector2List.fromList([
    Vector2(-1.0, 1.0),
    Vector2(1.0, 1.0),
    Vector2(1.0, -1.0),
    Vector2(-1.0, 1.0),
  ]);

  final Uint16List indices = Uint16List.fromList([0, 1, 2, 3, 2, 1]);

  final tangents = Vector4List(positions.length);

  generateTangents(tangents, positions, normals, texCoords, indices);

  relativeTest(tangents[0], Vector4(1.0, 0.0, 0.0, -1.0));
  relativeTest(tangents[1], Vector4(0.70710, 0.70710, 0.0, 1.0));
  relativeTest(tangents[2], Vector4(0.70710, 0.70710, 0.0, 1.0));
  relativeTest(tangents[3], Vector4(0.0, 1.0, 0.0, 1.0));
}

MeshGeometry filterUnitCube(GeometryFilter filter) {
  final generator = CubeGenerator();
  return generator.createCube(1.0, 1.0, 1.0, filters: [filter]);
}

void testTransformFilter() {
  final scaleMat = Matrix4.identity();
  scaleMat.scale(2.0, 2.0, 2.0);
  final filter = TransformFilter(scaleMat);
  final cube = filterUnitCube(filter);

  // Check to ensure all the vertices were properly scaled
  final positions = cube.getViewForAttrib('POSITION') as Vector3List;
  for (var i = 0; i < positions.length; ++i) {
    final position = positions[i];
    expect(position.storage[0].abs(), equals(2.0));
    expect(position.storage[1].abs(), equals(2.0));
    expect(position.storage[2].abs(), equals(2.0));
  }
}

void testFlatShadeFilter() {
  final filter = FlatShadeFilter();
  final cube = filterUnitCube(filter);

  // Flat shading removes indices and duplicates vertices
  expect(cube.indices, equals(null));
  expect(cube.length, equals(36));
}

void testBarycentricFilter() {
  final filter = BarycentricFilter();
  final cube = filterUnitCube(filter);

  // Generating barycentric coords removes indices and duplicates vertices
  expect(cube.indices, equals(null));
  expect(cube.length, equals(36));

  expect(cube.getViewForAttrib('BARYCENTRIC'), isNotNull);
}

void testColorFilter() {
  final filterColor = Vector4(1.0, 0.0, 0.0, 1.0);
  final filter = ColorFilter(filterColor);
  final cube = filterUnitCube(filter);

  // Ensure that the same color was applied to all vertices
  final colors = cube.getViewForAttrib('COLOR') as Vector4List;
  for (var i = 0; i < colors.length; ++i) {
    final color = colors[i];
    relativeTest(color, filterColor);
  }
}

void testCombineIndices() {
  // Combining two meshes should generate indices that are not out of range.
  final sphereGenerator = SphereGenerator();

  final sphere0 =
      sphereGenerator.createSphere(10.0, latSegments: 8, lonSegments: 8);
  final sphere1 =
      sphereGenerator.createSphere(10.0, latSegments: 8, lonSegments: 8);

  final combined = MeshGeometry.combine([sphere0, sphere1]);
  expect(combined.indices, everyElement(lessThan(combined.length)));
}

void main() {
  group('Geometry', () {
    group('Generators', () {
      test('normal generation', testGenerateNormals);
      test('tangent generation', testGenerateTangents);
      test('geometry combination', testCombineIndices);
    });
    group('Filters', () {
      test('transform filter', testTransformFilter);
      test('flat shade filter', testFlatShadeFilter);
      test('barycentric filter', testBarycentricFilter);
      test('color filter', testColorFilter);
    });
  });
}
