package main

import (
	"fmt"
	"strings"

	"github.com/go-gl/gl/v4.1-core/gl"
)

func compileShader(src string, stype uint32) (prog uint32, err error) {
	prog = gl.CreateShader(stype)

	strs, free := gl.Strs(src, "\x00")
	gl.ShaderSource(prog, 1, strs, nil)
	free()
	gl.CompileShader(prog)

	var status int32
	gl.GetShaderiv(prog, gl.COMPILE_STATUS, &status)
	if status == gl.FALSE {
		var len int32
		gl.GetShaderiv(prog, gl.INFO_LOG_LENGTH, &len)

		log := strings.Repeat("\x00", int(len+1))
		gl.GetShaderInfoLog(prog, len, nil, gl.Str(log))

		gl.DeleteShader(prog)

		switch stype {
		case gl.VERTEX_SHADER:
			return 0, fmt.Errorf("failed to compile Vertex Shader: %s", log)
		case gl.FRAGMENT_SHADER:
			return 0, fmt.Errorf("failed to compile Fragment Shader: %s", log)
		default:
			return 0, fmt.Errorf("failed to compile Unknown(%d) Shader: %s", stype, log)
		}
	}

	return
}

func newProgram(vert, frag string) (prog uint32, err error) {

	vertid, err := compileShader(vert, gl.VERTEX_SHADER)
	if err != nil {
		return 0, err
	}

	fragid, err := compileShader(frag, gl.FRAGMENT_SHADER)
	if err != nil {
		gl.DeleteShader(vertid)
		return 0, err
	}

	prog = gl.CreateProgram()

	gl.AttachShader(prog, vertid)
	gl.AttachShader(prog, fragid)
	gl.LinkProgram(prog)

	var status int32
	gl.GetProgramiv(prog, gl.LINK_STATUS, &status)
	if status == gl.FALSE {
		var len int32
		gl.GetProgramiv(prog, gl.INFO_LOG_LENGTH, &len)

		log := strings.Repeat("\x00", int(len+1))
		gl.GetProgramInfoLog(prog, len, nil, gl.Str(log))

		gl.DeleteProgram(prog)
		gl.DeleteShader(vertid)
		gl.DeleteShader(fragid)

		return 0, fmt.Errorf("failed to link Program: %s", log)
	}

	gl.DeleteShader(vertid)
	gl.DeleteShader(fragid)

	return
}
