// Copyright (C) 2020 Daniel Mall
#include "CDemoSpokes.h"
#include "sokol_app.h"
#include "sokol_gfx.h"
#include "sokol_glue.h"
#include "demo-spokes.glsl.h"
#include "imgui.h"
#include "sokol_imgui.h"
#include <cstring>
#include "CDemoGlobals.h"

// embedded audio sounds
const unsigned char* ZrWavWurlitzer66216();
int ZrSizeWavWurlitzer66216();
const unsigned char* ZrWavHappy009();
int ZrSizeWavHappy009();

CDemoSpokes::CDemoSpokes()
{
	Init();
}

CDemoSpokes::~CDemoSpokes()
{
}

void CDemoSpokes::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;
}

// application state
static struct {
	sg_pipeline pip;
	sg_bindings bind1;
	sg_bindings bind2;
} SpokesState;

typedef struct
{
	float XYZW[4];
	float RGBA[4];
} SpokesVertex;

void CDemoSpokes::Init()
{
	SpokesVertex vertices[] =
	{
	  { { 0.0f, 0.0f, 0.0f, 1.0f}, { 1.0f, 1.0f, 1.0f, 1.0f } }, // 0

	  // Top
	  { { -0.2f, 0.8f, 0.0f, 1.0f}, { 0.0f, 1.0f, 0.0f, 1.0f } }, // 1
	  { { 0.2f, 0.8f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f, 1.0f } }, // 2
	  { { 0.0f, 0.8f, 0.0f, 1.0f}, { 0.0f, 1.0f, 1.0f, 1.0f } }, //3
	  { { 0.0f, 1.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f, 1.0f } },  // 4

	  // Bottom
	  { { -0.2f, -0.8f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f, 1.0f } }, // 5
	  { { 0.2f, -0.8f, 0.0f, 1.0f}, { 0.0f, 1.0f, 0.0f, 1.0f } }, // 6
	  { { 0.0f, -0.8f, 0.0f, 1.0f}, { 0.0f, 1.0f, 1.0f, 1.0f } }, //7
	  { { 0.0f, -1.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f, 1.0f } },  // 8

	  // Left
	  { { -0.8f, -0.2f, 0.0f, 1.0f}, { 0.0f, 1.0f, 0.0f, 1.0f } }, // 9
	  { { -0.8f, 0.2f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f, 1.0f } }, // 10
	  { { -0.8f, 0.0f, 0.0f, 1.0f}, { 0.0f, 1.0f, 1.0f, 1.0f } }, //11
	  { { -1.0f, 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f, 1.0f } },  // 12

	  // Right
	  { { 0.8f, -0.2f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f, 1.0f } }, // 13
	  { { 0.8f, 0.2f, 0.0f, 1.0f}, { 0.0f, 1.0f, 0.0f, 1.0f } }, // 14
	  { { 0.8f, 0.0f, 0.0f, 1.0f}, { 0.0f, 1.0f, 1.0f, 1.0f } }, //15
	  { { 1.0f, 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f, 1.0f } }  // 16
	};

	// spokes
	uint16_t indices1[] = {
		// Top
		0, 1, 3,
		0, 3, 2,
		3, 1, 4,
		3, 4, 2,

		// Bottom
		0, 5, 7,
		0, 7, 6,
		7, 5, 8,
		7, 8, 6,

		// Left
		0, 9, 11,
		0, 11, 10,
		11, 9, 12,
		11, 12, 10,

		// Right
		0, 13, 15,
		0, 15, 14,
		15, 13, 16,
		15, 16, 14
	};

	// diamond
	uint16_t indices2[] = {
		// Outer square border
		3, 4, 16,
		3, 15, 16,
		15, 16, 8,
		15, 7, 8,
		7, 8, 12,
		7, 11, 12,
		11, 12, 4,
		11, 3, 4,
		// Inner square
		0, 11, 3,
		0, 3, 15,
		0, 15, 7,
		0, 7, 11
	};

	sg_buffer_desc bufferDescV;
	memset(&bufferDescV, 0, sizeof(bufferDescV));
	bufferDescV.data = SG_RANGE(vertices);
	bufferDescV.label = "spokes-vertices";
	sg_buffer vbo = sg_make_buffer(bufferDescV);

	{
		sg_buffer_desc bufferDescI;
		memset(&bufferDescI, 0, sizeof(bufferDescI));
		bufferDescI.type = SG_BUFFERTYPE_INDEXBUFFER;
		bufferDescI.data = SG_RANGE(indices1);
		bufferDescI.label = "spokes-indices1";
		SpokesState.bind1.vertex_buffers[0] = vbo;
		SpokesState.bind1.index_buffer = sg_make_buffer(bufferDescI);
	}

	{
		sg_buffer_desc bufferDescI;
		memset(&bufferDescI, 0, sizeof(bufferDescI));
		bufferDescI.type = SG_BUFFERTYPE_INDEXBUFFER;
		bufferDescI.data = SG_RANGE(indices2);
		bufferDescI.label = "spokes-indices2";
		SpokesState.bind2.vertex_buffers[0] = vbo;
		SpokesState.bind2.index_buffer = sg_make_buffer(bufferDescI);
	}

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

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

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

/// draw
void CDemoSpokes::Frame()
{
	ShowCommandGui();

	sg_apply_pipeline(SpokesState.pip);

	if (m_bUseAlternative)
	{
		sg_apply_bindings(&SpokesState.bind2);
		sg_draw(0, 36, 1);
	}
	else
	{
		sg_apply_bindings(&SpokesState.bind1);
		sg_draw(0, 48, 1);
	}
}

void CDemoSpokes::ToggleGeometry()
{
	// toggle the geometry
	m_bUseAlternative = !m_bUseAlternative;

	// play sound effect
	CAudio* pAudio = global()->m_pAudio->CreateAudioFromMemory("ZrWavWurlitzer66216", ZrWavWurlitzer66216(), ZrSizeWavWurlitzer66216(), true, AUDIOMIXER_MAXVOLUME);
	global()->m_pAudio->PlaySound(pAudio, AUDIOMIXER_MAXVOLUME);
}

void CDemoSpokes::ShowCommandGui()
{
	ImGui::SetNextWindowPos(ImVec2(5, 50), ImGuiCond_FirstUseEver);

	// push style compact
	ImGuiStyle& style = ImGui::GetStyle();
	ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.70f)));
	ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.70f)));

	ImGui::Begin("Commands", nullptr);
	ImGui::SetWindowSize(ImVec2(220, 120));
	static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
	if (ImGui::BeginTable("##table1", 2, flags))
	{
		ImGui::TableSetupColumn("Key");
		ImGui::TableSetupColumn("Action");
		ImGui::TableHeadersRow();

		ImGui::TableNextRow();
		ImGui::TableNextColumn();
		ImGui::Text("T");
		ImGui::TableNextColumn();
		if (ImGui::SmallButton("Toggle Geometry"))
		{
			ToggleGeometry();
		}
		ImGui::EndTable();
	}
	ImGui::End();

	// pop style compact
	ImGui::PopStyleVar(2);
}

void CDemoSpokes::EventInput(const sapp_event* event)
{
	if (event->type == SAPP_EVENTTYPE_KEY_DOWN)
	{
		// keyboard key 'T'
		if (event->key_code == SAPP_KEYCODE_T)
		{
			ToggleGeometry();
		}
	}
}

void CDemoSpokes::Activate()
{
	// play background audio music
	global()->m_pAudio->TurnOnAudioMixer();
	CAudio* pAudio = global()->m_pAudio->CreateAudioFromMemory("ZrWavHappy009", ZrWavHappy009(), ZrSizeWavHappy009(), true, AUDIOMIXER_MAXVOLUME);
	global()->m_pAudio->PlayMusic(pAudio, AUDIOMIXER_MAXVOLUME);
}

void CDemoSpokes::Deactivate()
{
	// pause the audio
	global()->m_pAudio->TurnOffAudioMixer();
	global()->m_pAudio->ClearAudioQueue();
}
