/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedScene"
#include "EmulatedScene.h"
#include "EmulatedSensor.h"

#include <stdlib.h>
#include <utils/Log.h>

#include <cmath>

// TODO: This should probably be done host-side in OpenGL for speed and better
// quality

namespace android {

// Define single-letter shortcuts for scene definition, for directly indexing
// mCurrentColors
#define G (EmulatedScene::GRASS * EmulatedScene::NUM_CHANNELS)
#define S (EmulatedScene::GRASS_SHADOW * EmulatedScene::NUM_CHANNELS)
#define H (EmulatedScene::HILL * EmulatedScene::NUM_CHANNELS)
#define W (EmulatedScene::WALL * EmulatedScene::NUM_CHANNELS)
#define R (EmulatedScene::ROOF * EmulatedScene::NUM_CHANNELS)
#define D (EmulatedScene::DOOR * EmulatedScene::NUM_CHANNELS)
#define C (EmulatedScene::CHIMNEY * EmulatedScene::NUM_CHANNELS)
#define I (EmulatedScene::WINDOW * EmulatedScene::NUM_CHANNELS)
#define U (EmulatedScene::SUN * EmulatedScene::NUM_CHANNELS)
#define K (EmulatedScene::SKY * EmulatedScene::NUM_CHANNELS)
#define M (EmulatedScene::MOON * EmulatedScene::NUM_CHANNELS)

const uint8_t EmulatedScene::kScene[EmulatedScene::kSceneWidth *
                                    EmulatedScene::kSceneHeight] = {
    //      5         10        15        20
    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,  // 5
    K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K, K,
    K, K, K, K, K, K, K, K, H, H, H, H, H, H, H, H, H, H, H, H,
    K, K, K, K, K, K, K, K, H, H, H, H, H, H, H, C, C, H, H, H,
    K, K, K, K, K, K, H, H, H, H, H, H, H, H, H, C, C, H, H, H,
    H, K, K, K, K, K, H, R, R, R, R, R, R, R, R, R, R, R, R, H,  // 10
    H, K, K, K, K, H, H, R, R, R, R, R, R, R, R, R, R, R, R, H,
    H, H, H, K, K, H, H, R, R, R, R, R, R, R, R, R, R, R, R, H,
    H, H, H, K, K, H, H, H, W, W, W, W, W, W, W, W, W, W, H, H,
    S, S, S, G, G, S, S, S, W, W, W, W, W, W, W, W, W, W, S, S,
    S, G, G, G, G, S, S, S, W, I, I, W, D, D, W, I, I, W, S, S,  // 15
    G, G, G, G, G, G, S, S, W, I, I, W, D, D, W, I, I, W, S, S,
    G, G, G, G, G, G, G, G, W, W, W, W, D, D, W, W, W, W, G, G,
    G, G, G, G, G, G, G, G, W, W, W, W, D, D, W, W, W, W, G, G,
    G, G, G, G, G, G, G, G, S, S, S, S, S, S, S, S, S, S, G, G,
    G, G, G, G, G, G, G, G, S, S, S, S, S, S, S, S, S, S, G, G,  // 20
    //      5         10        15        20
};

#undef G
#undef S
#undef H
#undef W
#undef R
#undef D
#undef C
#undef I
#undef U
#undef K
#undef M

EmulatedScene::EmulatedScene(int sensor_width_px, int sensor_height_px,
                             float sensor_sensitivity, int sensor_orientation,
                             bool is_front_facing)
    : screen_rotation_(0),
      current_scene_(scene_rot0_),
      sensor_orientation_(sensor_orientation),
      is_front_facing_(is_front_facing),
      hour_(12),
      exposure_duration_(0.033f) {
  // Assume that sensor filters are sRGB primaries to start
  filter_r_[0] = 3.2406f;
  filter_r_[1] = -1.5372f;
  filter_r_[2] = -0.4986f;
  filter_gr_[0] = -0.9689f;
  filter_gr_[1] = 1.8758f;
  filter_gr_[2] = 0.0415f;
  filter_gb_[0] = -0.9689f;
  filter_gb_[1] = 1.8758f;
  filter_gb_[2] = 0.0415f;
  filter_b_[0] = 0.0557f;
  filter_b_[1] = -0.2040f;
  filter_b_[2] = 1.0570f;

  InitiliazeSceneRotation(!is_front_facing_);
  Initialize(sensor_width_px, sensor_height_px, sensor_sensitivity);
}

EmulatedScene::~EmulatedScene() {
}

void EmulatedScene::Initialize(int sensor_width_px, int sensor_height_px,
                               float sensor_sensitivity) {
  sensor_width_ = sensor_width_px;
  sensor_height_ = sensor_height_px;
  sensor_sensitivity_ = sensor_sensitivity;

  // Map scene to sensor pixels
  if (sensor_width_ > sensor_height_) {
    map_div_ = (sensor_width_ / (kSceneWidth + 1)) + 1;
  }
  else {
    map_div_ = (sensor_height_ / (kSceneHeight + 1)) + 1;
  }
  offset_x_ = (kSceneWidth * map_div_ - sensor_width_) / 2;
  offset_y_ = (kSceneHeight * map_div_ - sensor_height_) / 2;

}

void EmulatedScene::SetColorFilterXYZ(float rX, float rY, float rZ, float grX,
                                      float grY, float grZ, float gbX, float gbY,
                                      float gbZ, float bX, float bY, float bZ) {
  filter_r_[0] = rX;
  filter_r_[1] = rY;
  filter_r_[2] = rZ;
  filter_gr_[0] = grX;
  filter_gr_[1] = grY;
  filter_gr_[2] = grZ;
  filter_gb_[0] = gbX;
  filter_gb_[1] = gbY;
  filter_gb_[2] = gbZ;
  filter_b_[0] = bX;
  filter_b_[1] = bY;
  filter_b_[2] = bZ;
}

void EmulatedScene::SetHour(int hour) {
  ALOGV("Hour set to: %d", hour);
  hour_ = hour % 24;
}

int EmulatedScene::GetHour() const {
  return hour_;
}

void EmulatedScene::SetScreenRotation(uint32_t screen_rotation) {
  screen_rotation_ = screen_rotation;
}

void EmulatedScene::SetExposureDuration(float seconds) {
  exposure_duration_ = seconds;
}

void EmulatedScene::SetTestPattern(bool enabled) {
  test_pattern_mode_ = enabled;
}

void EmulatedScene::SetTestPatternData(uint32_t data[4]) {
  memcpy(test_pattern_data_, data, 4);
}

void EmulatedScene::CalculateScene(nsecs_t time, int32_t handshake_divider) {
  // Calculate time fractions for interpolation
  const nsecs_t kOneHourInNsec = 1e9 * 60 * 60;
#ifdef FAST_SCENE_CYCLE
  hour_ = static_cast<int>(time * 6000 / kOneHourInNsec) % 24;
#endif
  int time_idx = hour_ / kTimeStep;
  int next_time_idx = (time_idx + 1) % (24 / kTimeStep);
  nsecs_t time_since_idx =
      (hour_ - time_idx * kTimeStep) * kOneHourInNsec + time;
  float time_frac = time_since_idx / (float)(kOneHourInNsec * kTimeStep);

  // Determine overall sunlight levels
  float sun_lux = kSunlight[time_idx] * (1 - time_frac) +
                  kSunlight[next_time_idx] * time_frac;
  ALOGV("Sun lux: %f", sun_lux);

  float sun_shade_lux = sun_lux * (kDaylightShadeIllum / kDirectSunIllum);

  // Determine sun/shade illumination chromaticity
  float current_sun_xy[2];
  float current_shade_xy[2];

  const float *prev_sun_xy, *next_sun_xy;
  const float *prev_shade_xy, *next_shade_xy;
  if (kSunlight[time_idx] == kSunsetIllum ||
      kSunlight[time_idx] == kTwilightIllum) {
    prev_sun_xy = kSunsetXY;
    prev_shade_xy = kSunsetXY;
  } else {
    prev_sun_xy = kDirectSunlightXY;
    prev_shade_xy = kDaylightXY;
  }
  if (kSunlight[next_time_idx] == kSunsetIllum ||
      kSunlight[next_time_idx] == kTwilightIllum) {
    next_sun_xy = kSunsetXY;
    next_shade_xy = kSunsetXY;
  } else {
    next_sun_xy = kDirectSunlightXY;
    next_shade_xy = kDaylightXY;
  }
  current_sun_xy[0] =
      prev_sun_xy[0] * (1 - time_frac) + next_sun_xy[0] * time_frac;
  current_sun_xy[1] =
      prev_sun_xy[1] * (1 - time_frac) + next_sun_xy[1] * time_frac;

  current_shade_xy[0] =
      prev_shade_xy[0] * (1 - time_frac) + next_shade_xy[0] * time_frac;
  current_shade_xy[1] =
      prev_shade_xy[1] * (1 - time_frac) + next_shade_xy[1] * time_frac;

  ALOGV("Sun XY: %f, %f, Shade XY: %f, %f", current_sun_xy[0],
        current_sun_xy[1], current_shade_xy[0], current_shade_xy[1]);

  // Converting for xyY to XYZ:
  // X = Y / y * x
  // Y = Y
  // Z = Y / y * (1 - x - y);
  float sun_xyz[3] = {sun_lux / current_sun_xy[1] * current_sun_xy[0], sun_lux,
                      sun_lux / current_sun_xy[1] *
                          (1 - current_sun_xy[0] - current_sun_xy[1])};
  float sun_shade_xyz[3] = {
      sun_shade_lux / current_shade_xy[1] * current_shade_xy[0], sun_shade_lux,
      sun_shade_lux / current_shade_xy[1] *
          (1 - current_shade_xy[0] - current_shade_xy[1])};
  ALOGV("Sun XYZ: %f, %f, %f", sun_xyz[0], sun_xyz[1], sun_xyz[2]);
  ALOGV("Sun shade XYZ: %f, %f, %f", sun_shade_xyz[0], sun_shade_xyz[1],
        sun_shade_xyz[2]);

  // Determine moonlight levels
  float moon_lux = kMoonlight[time_idx] * (1 - time_frac) +
                   kMoonlight[next_time_idx] * time_frac;
  float moonshade_lux = moon_lux * (kDaylightShadeIllum / kDirectSunIllum);

  float moon_xyz[3] = {
      moon_lux / kMoonlightXY[1] * kMoonlightXY[0], moon_lux,
      moon_lux / kMoonlightXY[1] * (1 - kMoonlightXY[0] - kMoonlightXY[1])};
  float moon_shade_xyz[3] = {
      moonshade_lux / kMoonlightXY[1] * kMoonlightXY[0], moonshade_lux,
      moonshade_lux / kMoonlightXY[1] * (1 - kMoonlightXY[0] - kMoonlightXY[1])};

  // Determine starlight level
  const float kClearNightXYZ[3] = {
      kClearNightIllum / kMoonlightXY[1] * kMoonlightXY[0], kClearNightIllum,
      kClearNightIllum / kMoonlightXY[1] *
          (1 - kMoonlightXY[0] - kMoonlightXY[1])};

  // Calculate direct and shaded light
  float direct_illum_xyz[3] = {
      sun_xyz[0] + moon_xyz[0] + kClearNightXYZ[0],
      sun_xyz[1] + moon_xyz[1] + kClearNightXYZ[1],
      sun_xyz[2] + moon_xyz[2] + kClearNightXYZ[2],
  };

  float shade_illum_xyz[3] = {kClearNightXYZ[0], kClearNightXYZ[1],
                              kClearNightXYZ[2]};

  shade_illum_xyz[0] += (hour_ < kSunOverhead) ? sun_xyz[0] : sun_shade_xyz[0];
  shade_illum_xyz[1] += (hour_ < kSunOverhead) ? sun_xyz[1] : sun_shade_xyz[1];
  shade_illum_xyz[2] += (hour_ < kSunOverhead) ? sun_xyz[2] : sun_shade_xyz[2];

  // Moon up period covers 23->0 transition, shift for simplicity
  int adj_hour = (hour_ + 12) % 24;
  int adj_moon_overhead = (kMoonOverhead + 12) % 24;
  shade_illum_xyz[0] +=
      (adj_hour < adj_moon_overhead) ? moon_xyz[0] : moon_shade_xyz[0];
  shade_illum_xyz[1] +=
      (adj_hour < adj_moon_overhead) ? moon_xyz[1] : moon_shade_xyz[1];
  shade_illum_xyz[2] +=
      (adj_hour < adj_moon_overhead) ? moon_xyz[2] : moon_shade_xyz[2];

  ALOGV("Direct XYZ: %f, %f, %f", direct_illum_xyz[0], direct_illum_xyz[1],
        direct_illum_xyz[2]);
  ALOGV("Shade XYZ: %f, %f, %f", shade_illum_xyz[0], shade_illum_xyz[1],
        shade_illum_xyz[2]);

  for (int i = 0; i < NUM_MATERIALS; i++) {
    // Converting for xyY to XYZ:
    // X = Y / y * x
    // Y = Y
    // Z = Y / y * (1 - x - y);
    float mat_xyz[3] = {
        kMaterials_xyY[i][2] / kMaterials_xyY[i][1] * kMaterials_xyY[i][0],
        kMaterials_xyY[i][2],
        kMaterials_xyY[i][2] / kMaterials_xyY[i][1] *
            (1 - kMaterials_xyY[i][0] - kMaterials_xyY[i][1])};

    if (kMaterialsFlags[i] == 0 || kMaterialsFlags[i] & kSky) {
      mat_xyz[0] *= direct_illum_xyz[0];
      mat_xyz[1] *= direct_illum_xyz[1];
      mat_xyz[2] *= direct_illum_xyz[2];
    } else if (kMaterialsFlags[i] & kShadowed) {
      mat_xyz[0] *= shade_illum_xyz[0];
      mat_xyz[1] *= shade_illum_xyz[1];
      mat_xyz[2] *= shade_illum_xyz[2];
    }  // else if (kMaterialsFlags[i] * kSelfLit), do nothing

    ALOGV("Mat %d XYZ: %f, %f, %f", i, mat_xyz[0], mat_xyz[1], mat_xyz[2]);
    float lux_to_electrons =
        sensor_sensitivity_ * exposure_duration_ / (kAperture * kAperture);
    current_colors_[i * NUM_CHANNELS + 0] =
        (filter_r_[0] * mat_xyz[0] + filter_r_[1] * mat_xyz[1] +
         filter_r_[2] * mat_xyz[2]) *
        lux_to_electrons;
    current_colors_[i * NUM_CHANNELS + 1] =
        (filter_gr_[0] * mat_xyz[0] + filter_gr_[1] * mat_xyz[1] +
         filter_gr_[2] * mat_xyz[2]) *
        lux_to_electrons;
    current_colors_[i * NUM_CHANNELS + 2] =
        (filter_gb_[0] * mat_xyz[0] + filter_gb_[1] * mat_xyz[1] +
         filter_gb_[2] * mat_xyz[2]) *
        lux_to_electrons;
    current_colors_[i * NUM_CHANNELS + 3] =
        (filter_b_[0] * mat_xyz[0] + filter_b_[1] * mat_xyz[1] +
         filter_b_[2] * mat_xyz[2]) *
        lux_to_electrons;

    ALOGV("Color %d RGGB: %d, %d, %d, %d", i,
          current_colors_[i * NUM_CHANNELS + 0],
          current_colors_[i * NUM_CHANNELS + 1],
          current_colors_[i * NUM_CHANNELS + 2],
          current_colors_[i * NUM_CHANNELS + 3]);
  }
  // Shake viewpoint; horizontal and vertical sinusoids at roughly
  // human handshake frequencies
  handshake_x_ =
      (kFreq1Magnitude * std::sin(kHorizShakeFreq1 * time_since_idx) +
       kFreq2Magnitude * std::sin(kHorizShakeFreq2 * time_since_idx)) *
      map_div_ * kShakeFraction;
  if (handshake_divider > 0) {
    handshake_x_ /= handshake_divider;
  }

  handshake_y_ = (kFreq1Magnitude * std::sin(kVertShakeFreq1 * time_since_idx) +
                  kFreq2Magnitude * std::sin(kVertShakeFreq2 * time_since_idx)) *
                 map_div_ * kShakeFraction;
  if (handshake_divider > 0) {
    handshake_y_ /= handshake_divider;
  }

  int32_t sensor_orientation =
      is_front_facing_ ? -sensor_orientation_ : sensor_orientation_;
  int32_t scene_rotation = ((screen_rotation_ + 360) + sensor_orientation) % 360;
  switch (scene_rotation) {
    case 90:
      current_scene_ = scene_rot90_;
      break;
    case 180:
      current_scene_ = scene_rot180_;
      break;
    case 270:
      current_scene_ = scene_rot270_;
      break;
    default:
      current_scene_ = scene_rot0_;
  }

  // Set starting pixel
  SetReadoutPixel(0, 0);
}

void EmulatedScene::InitiliazeSceneRotation(bool clock_wise) {
  memcpy(scene_rot0_, kScene, sizeof(scene_rot0_));

  size_t c = 0;
  for (ssize_t i = kSceneHeight-1; i >= 0; i--) {
    for (ssize_t j = kSceneWidth-1; j >= 0; j--) {
      scene_rot180_[c++] = kScene[i*kSceneWidth + j];
    }
  }

  c = 0;
  for (ssize_t i = kSceneWidth-1; i >= 0; i--) {
    for (size_t j = 0; j < kSceneHeight; j++) {
      if (clock_wise) {
        scene_rot90_[c++] = kScene[j*kSceneWidth + i];
      } else {
        scene_rot270_[c++] = kScene[j*kSceneWidth + i];
      }
    }
  }

  c = 0;
  for (size_t i = 0; i < kSceneWidth; i++) {
    for (ssize_t j = kSceneHeight-1; j >= 0; j--) {
      if (clock_wise) {
        scene_rot270_[c++] = kScene[j*kSceneWidth + i];
      } else {
        scene_rot90_[c++] = kScene[j*kSceneWidth + i];
      }
    }
  }
}

void EmulatedScene::SetReadoutPixel(int x, int y) {
  current_x_ = x;
  current_y_ = y;
  sub_x_ = (x + offset_x_ + handshake_x_) % map_div_;
  sub_y_ = (y + offset_y_ + handshake_y_) % map_div_;
  scene_x_ = (x + offset_x_ + handshake_x_) / map_div_;
  scene_y_ = (y + offset_y_ + handshake_y_) / map_div_;
  scene_idx_ = scene_y_ * kSceneWidth + scene_x_;
  current_scene_material_ = &(current_colors_[current_scene_[scene_idx_]]);
}

const uint32_t* EmulatedScene::GetPixelElectrons() {
  if (test_pattern_mode_) return test_pattern_data_;

  const uint32_t* pixel = current_scene_material_;
  current_x_++;
  sub_x_++;
  if (current_x_ >= sensor_width_) {
    current_x_ = 0;
    current_y_++;
    if (current_y_ >= sensor_height_) current_y_ = 0;
    SetReadoutPixel(current_x_, current_y_);
  } else if (sub_x_ > map_div_) {
    scene_idx_++;
    scene_x_++;
    current_scene_material_ = &(current_colors_[current_scene_[scene_idx_]]);
    sub_x_ = 0;
  }
  return pixel;
}

const uint32_t* EmulatedScene::GetPixelElectronsColumn() {
  const uint32_t* pixel = current_scene_material_;
  current_y_++;
  sub_y_++;
  if (current_y_ >= sensor_height_) {
    current_y_ = 0;
    current_x_++;
    if (current_x_ >= sensor_width_) current_x_ = 0;
    SetReadoutPixel(current_x_, current_y_);
  } else if (sub_y_ > map_div_) {
    scene_idx_ += kSceneWidth;
    scene_y_++;
    current_scene_material_ = &(current_colors_[current_scene_[scene_idx_]]);
    sub_y_ = 0;
  }
  return pixel;
}

// Handshake model constants.
// Frequencies measured in a nanosecond timebase
const float EmulatedScene::kHorizShakeFreq1 = 2 * M_PI * 2 / 1e9;   // 2 Hz
const float EmulatedScene::kHorizShakeFreq2 = 2 * M_PI * 13 / 1e9;  // 13 Hz
const float EmulatedScene::kVertShakeFreq1 = 2 * M_PI * 3 / 1e9;    // 3 Hz
const float EmulatedScene::kVertShakeFreq2 = 2 * M_PI * 11 / 1e9;   // 1 Hz
const float EmulatedScene::kFreq1Magnitude = 5;
const float EmulatedScene::kFreq2Magnitude = 1;
const float EmulatedScene::kShakeFraction =
    0.03;  // As a fraction of a scene tile

// Aperture of imaging lens
const float EmulatedScene::kAperture = 2.8;

// Sun illumination levels through the day
const float EmulatedScene::kSunlight[24 / kTimeStep] = {
    0,  // 00:00
    0,
    0,
    kTwilightIllum,  // 06:00
    kDirectSunIllum,
    kDirectSunIllum,
    kDirectSunIllum,  // 12:00
    kDirectSunIllum,
    kDirectSunIllum,
    kSunsetIllum,  // 18:00
    kTwilightIllum,
    0};

// Moon illumination levels through the day
const float EmulatedScene::kMoonlight[24 / kTimeStep] = {
    kFullMoonIllum,  // 00:00
    kFullMoonIllum,
    0,
    0,  // 06:00
    0,
    0,
    0,  // 12:00
    0,
    0,
    0,  // 18:00
    0,
    kFullMoonIllum};

const int EmulatedScene::kSunOverhead = 12;
const int EmulatedScene::kMoonOverhead = 0;

// Used for sun illumination levels
const float EmulatedScene::kDirectSunIllum = 100000;
const float EmulatedScene::kSunsetIllum = 400;
const float EmulatedScene::kTwilightIllum = 4;
// Used for moon illumination levels
const float EmulatedScene::kFullMoonIllum = 1;
// Other illumination levels
const float EmulatedScene::kDaylightShadeIllum = 20000;
const float EmulatedScene::kClearNightIllum = 2e-3;
const float EmulatedScene::kStarIllum = 2e-6;
const float EmulatedScene::kLivingRoomIllum = 50;

const float EmulatedScene::kIncandescentXY[2] = {0.44757f, 0.40745f};
const float EmulatedScene::kDirectSunlightXY[2] = {0.34842f, 0.35161f};
const float EmulatedScene::kDaylightXY[2] = {0.31271f, 0.32902f};
const float EmulatedScene::kNoonSkyXY[2] = {0.346f, 0.359f};
const float EmulatedScene::kMoonlightXY[2] = {0.34842f, 0.35161f};
const float EmulatedScene::kSunsetXY[2] = {0.527f, 0.413f};

const uint8_t EmulatedScene::kSelfLit = 0x01;
const uint8_t EmulatedScene::kShadowed = 0x02;
const uint8_t EmulatedScene::kSky = 0x04;

// For non-self-lit materials, the Y component is normalized with 1=full
// reflectance; for self-lit materials, it's the constant illuminance in lux.
const float EmulatedScene::kMaterials_xyY[EmulatedScene::NUM_MATERIALS][3] = {
    {0.3688f, 0.4501f, .1329f},                                  // GRASS
    {0.3688f, 0.4501f, .1329f},                                  // GRASS_SHADOW
    {0.3986f, 0.5002f, .4440f},                                  // HILL
    {0.3262f, 0.5040f, .2297f},                                  // WALL
    {0.4336f, 0.3787f, .1029f},                                  // ROOF
    {0.3316f, 0.2544f, .0639f},                                  // DOOR
    {0.3425f, 0.3577f, .0887f},                                  // CHIMNEY
    {kIncandescentXY[0], kIncandescentXY[1], kLivingRoomIllum},  // WINDOW
    {kDirectSunlightXY[0], kDirectSunlightXY[1], kDirectSunIllum},  // SUN
    {kNoonSkyXY[0], kNoonSkyXY[1], kDaylightShadeIllum / kDirectSunIllum},  // SKY
    {kMoonlightXY[0], kMoonlightXY[1], kFullMoonIllum}  // MOON
};

const uint8_t EmulatedScene::kMaterialsFlags[EmulatedScene::NUM_MATERIALS] = {
    0,         kShadowed, kShadowed, kShadowed, kShadowed, kShadowed,
    kShadowed, kSelfLit,  kSelfLit,  kSky,      kSelfLit,
};

}  // namespace android
