#include "shader.h"

#include <string.h>

#include "error.h"
#include "gl.h"

struct sw_shader sw_shader_create(char const *source, i32 type) {
	struct sw_shader shader;
	i32 gltype;
	i32 length;
	i32 ret;

	sw_log("create shader");

	switch(type) {
	case SW_SHADER_VERTEX:
		gltype = GL_VERTEX_SHADER;
		break;
	case SW_SHADER_FRAGMENT:
		gltype = GL_FRAGMENT_SHADER;
		break;
	default:
		gltype = 0;
		sw_error("unknown shader type");
	}

	shader._shader = glCreateShader(gltype);
	length = strlen(source);
	glShaderSource(shader._shader, 1, &source, &length);
	glCompileShader(shader._shader);

	glGetShaderiv(shader._shader, GL_COMPILE_STATUS, &ret);
	if(!ret) {
		char str[256];
		i32 len;

		glGetShaderInfoLog(shader._shader, 256, &len, str);
		sw_error("Shader Compile Error: %s", str);
	}

	return shader;
}

struct sw_shaderprogram
sw_shaderprogram_create(char const *vertex, char const *fragment) {
	struct sw_shaderprogram program;
	struct sw_shader v, f;
	i32 ret;

	sw_log("create shader program");
	v = sw_shader_create(vertex, SW_SHADER_VERTEX);
	f = sw_shader_create(fragment, SW_SHADER_FRAGMENT);
	program._program = glCreateProgram();
	glAttachShader(program._program, v._shader);
	glAttachShader(program._program, f._shader);
	sw_log("set attribute locations");
	glBindAttribLocation(program._program, SW_SHADERLOC_POS, "pos");
	sw_log("link shader");
	glLinkProgram(program._program);
	glGetProgramiv(program._program, GL_LINK_STATUS, &ret);
	if(!ret) {
		char str[256];
		i32 len;

		glGetProgramInfoLog(program._program, 256, &len, str);
		sw_error("Shader Link Error: %s", str);
	}
	return program;
}

void sw_shaderprogram_use(struct sw_shaderprogram program) {
	glUseProgram(program._program);
}
