// Copyright (C) 2020 Daniel Mall
#include "CDemoTriangle.h"
#include "sokol_app.h"
#include "sokol_gfx.h"
#include "sokol_time.h"
#include "sokol_glue.h"
#include "demo-triangle.glsl.h"
#include <cstring>

// OpenGL Mathematics (GLM) - MATH functions GLM
// https://github.com/g-truc/glm
#include "glm/glm.hpp" // Include all GLM core / GLSL features (vec2, vec3, mat4, radians)
#include "glm/ext.hpp" // Include all GLM extensions (perspective, translate, rotate)

CDemoTriangle::CDemoTriangle()
{
	Init();
}

CDemoTriangle::~CDemoTriangle()
{
}

/* application state */
static struct {
	sg_pipeline pip;
	sg_bindings bind;
} state;

void CDemoTriangle::Init()
{
	static const struct
	{
		float x, y;
		float r, g, b;
	} vertices[3] =
	{
		{ -0.6f, -0.4f, 1.f, 0.f, 0.f },
		{ 0.6f, -0.4f, 0.f, 1.f, 0.f },
		{ 0.f,  0.6f, 0.f, 0.f, 1.f }
	};

	sg_buffer_desc aBufferDesc;
	memset(&aBufferDesc, 0, sizeof(aBufferDesc));
	aBufferDesc.data = SG_RANGE(vertices);
	aBufferDesc.label = "triangle-vertices";
	state.bind.vertex_buffers[0] = sg_make_buffer(aBufferDesc);

	/* create shader from code-generated sg_shader_desc */
	sg_shader shd = sg_make_shader(demotriangle_shader_desc(sg_query_backend()));

	sg_pipeline_desc aPipelineDesc;
	memset(&aPipelineDesc, 0, sizeof(aPipelineDesc));
	aPipelineDesc.shader = shd;
	/* if the vertex layout doesn't have gaps, don't need to provide strides and offsets */
	aPipelineDesc.layout.attrs[ATTR_vs_position].format = SG_VERTEXFORMAT_FLOAT2;
	aPipelineDesc.layout.attrs[ATTR_vs_color0].format = SG_VERTEXFORMAT_FLOAT3;
	aPipelineDesc.label = "triangle-pipeline";

	/* create a pipeline object (default render states are fine for triangle) */
	state.pip = sg_make_pipeline(aPipelineDesc);
}

void CDemoTriangle::PassAction(sg_pass_action& passAction)
{
	/* a pass action to framebuffer to black */
	passAction.colors[0].action = SG_ACTION_CLEAR;
	passAction.colors[0].value.r = 0.0f;
	passAction.colors[0].value.g = 0.0f;
	passAction.colors[0].value.b = 0.0f;
	passAction.colors[0].value.a = 1.0f;
}

void CDemoTriangle::Frame()
{
	const float w = sapp_widthf();
	const float h = sapp_heightf();
	const float ratio = (w / h);

	const uint64_t nTicks = stm_now();
	double fTimeSeconds = stm_sec(nTicks);

	glm::mat4 m = glm::mat4(1.0f);
	m = glm::rotate(m, (float)fTimeSeconds, glm::vec3(0.0f, 0.0f, 1.0f));
	glm::mat4 p = glm::ortho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
	glm::mat4 mvp = (p * m);

	vs_params_t vs_params;
	const float* pSource = (const float*) glm::value_ptr(mvp);
	for (int i = 0; i < 16; ++i)
	{
		vs_params.mvp[i] = pSource[i];
	}

	sg_apply_pipeline(state.pip);
	sg_apply_bindings(&state.bind);
	sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vs_params, SG_RANGE_REF(vs_params));
	sg_draw(0, 3, 1);
}
