#pragma once

#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <iostream>

#include "mesh.h"

namespace kek {

template<typename ...Args>
using GenericFunction = void(*)(Args... args);

template<typename ...Args>
struct GenericCallable {
	GenericFunction<Args..., void *> function;
	void *data;

	GenericCallable(): function(nullptr), data(nullptr) {}

	GenericCallable(GenericFunction<Args..., void *> function, void *data): function(function), data(data) {}

	void operator()(Args... args) {
		if(function == nullptr) return;
		function(args..., data);
	}
};

typedef GenericCallable<> Callable;

float clampCyclic(float value, float min, float max);

float clamp(float value, float min, float max);

float clampCyclic(int value, int min, int max);

float clamp(int value, int min, int max);

enum class CubeFace {
	FRONT, BACK, UP, DOWN, LEFT, RIGHT
};

glm::vec3 faceNormal(CubeFace face);

void genCubeVertices(float w, float h, float d, bool texCoords, float **outVerts, size_t *outSize, size_t *vertexCount);

std::vector<Vertex> genCubeVertices(float w, float h, float d, bool texCoords);

Mesh *genCubeMesh(float w, float h, float d, std::shared_ptr<Texture> ambient, std::shared_ptr<Texture> diffuse, std::shared_ptr<Texture> specular);

std::string toString(glm::vec3 vector);

}
