//
//  TexturedCube.cpp
//  TexturedCube
//
//  Created by John Ryland on 2/10/17.
//  Copyright © 2017 John Ryland. All rights reserved.
//

#include "../Framework/Framework.h"


DECLARE_PROGRAM_UNIFORMS(ShadedProgram)
  DECLARE_UNIFORM(mat4, modelViewProjectionMatrix)
  DECLARE_UNIFORM(mat4, modelViewMatrix)
  DECLARE_UNIFORM(mat3, normalMatrix)
DECLARE_PROGRAM_UNIFORMS_END


DECLARE_VERTEX(ShadedVertex)
  DECLARE_ATTRIB(vec3, pos, GL_FALSE)
  DECLARE_ATTRIB(vec3, normal, GL_FALSE)
  DECLARE_ATTRIB(vec3, tangent, GL_FALSE)
  DECLARE_ATTRIB(vec3, binormal, GL_FALSE)
DECLARE_VERTEX_END


const char* s_shadedVertexShader =
R"(
  varying lowp vec4 colorVarying;
  void main()
  {
    gl_Position = modelViewProjectionMatrix * vec4(pos, 1.0);
    colorVarying = vec4(pos + vec3(0.5), 1.0);
  }
)";


const char* s_shadedFragmentShader =
R"(
  varying lowp vec4 colorVarying;
  void main()
  {
    gl_FragColor = colorVarying;
  }
)";


class ShadedCube : public DemoContext
{
public:
  ~ShadedCube() override;
  void prepare() override;
  void update(float a_seconds) override;
  void draw() override;
  void onResize(const vec2f& a_shape) override;

private:
  ProgramContext2<ShadedProgram, ShadedVertex> m_demoModelContext;
  float m_projectionMatrix[16];
};


ShadedCube::~ShadedCube()
{
  m_demoModelContext.shutdown();
}


void ShadedCube::prepare()
{
  OptionsType options;
  m_demoModelContext.setup(s_shadedVertexShader, s_shadedFragmentShader, Medium, options, 1);

  std::vector<vec3f> vertexes;
  CreateTexturedCube(vertexes);
  m_demoModelContext.m_vertexArray.m_vertexData.clear();
  m_demoModelContext.m_vertexArray.m_vertexData.reserve(vertexes.size() / 2);
  bool odd = false;
  vec3f last;
  for (const vec3f& v : vertexes)
  {
    if (odd)
      m_demoModelContext.m_vertexArray.m_vertexData.push_back(ShadedVertex{ last.x, last.y, last.z, v.x, v.y, v.z });
    else
      last = v;
    odd = !odd;
  }

  m_demoModelContext.update();
  m_demoModelContext.setFlag(clearColor | clearDepth | enableCullFace | enableDepthTest);
  m_demoModelContext.setBackgroundColor(0.0f, 0.0f, 0.0f);
}


void ShadedCube::onResize(const vec2f& a_shape)
{
  Math::makePerspectiveMatrix4x4(m_projectionMatrix, Math::degreesToRadians(45.0f), a_shape.x / a_shape.y, 0.1f, 100.0f);
}


void ShadedCube::update(float a_seconds)
{
  float trans[3] = { 0.0f, 0.0f, -20.0f };
  float rotate[3] = { fmod(a_seconds*23.f, 360.0f), fmod(a_seconds*37.f, 360.0f), fmod(a_seconds*46.0f, 360.0f)};
  float baseModelViewMatrix[16];
  Math::translationRotationScaleToMatrix4x4(baseModelViewMatrix, trans, rotate, 5.0f);

  Math::multiplyMatrix4x4(m_demoModelContext.m_uniforms.m_modelViewProjectionMatrix.m[0], m_projectionMatrix, baseModelViewMatrix);
}


void ShadedCube::draw()
{
  m_demoModelContext.draw();
}


REGISTER_DEMO_CONTEXT("Shaded Cube", ShadedCube)

