@@ -4,10 +4,8 @@
package video

import (
"fmt"
"log"

"strings"
"unsafe"

"github.com/go-gl/gl/all-core/gl"
@@ -35,9 +33,10 @@ type WindowInterface interface {

// Video holds the state of the video package
type Video struct {
Window WindowInterface
Geom libretro.GameGeometry
Font *glfont.Font
GLVersion uint
Window WindowInterface
Geom libretro.GameGeometry
Font *glfont.Font

program uint32 // default program used for the game window
roundedProgram uint32 // program to draw rectangles with rounded corners
@@ -55,8 +54,9 @@ type Video struct {
}

// Init instanciates the video package
func Init(fullscreen bool) *Video {
func Init(fullscreen bool, GLVersion uint) *Video {
vid := &Video{}
vid.GLVersion = GLVersion
vid.Configure(fullscreen)
return vid
}
@@ -69,15 +69,66 @@ func (video *Video) Reconfigure(fullscreen bool) {
video.Configure(fullscreen)
}

func (video *Video) configureContext() uint {
var GLSLVersion uint
switch video.GLVersion {
case 20:
glfw.WindowHint(glfw.ContextVersionMajor, 2)
glfw.WindowHint(glfw.ContextVersionMinor, 0)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLAnyProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.False)
GLSLVersion = 110
case 21:
glfw.WindowHint(glfw.ContextVersionMajor, 2)
glfw.WindowHint(glfw.ContextVersionMinor, 1)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLAnyProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.False)
GLSLVersion = 120
case 30:
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 0)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLAnyProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.False)
GLSLVersion = 130
case 31:
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 1)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLAnyProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.False)
GLSLVersion = 140
case 32:
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 2)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
GLSLVersion = 150
case 41:
glfw.WindowHint(glfw.ContextVersionMajor, 4)
glfw.WindowHint(glfw.ContextVersionMinor, 1)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
GLSLVersion = 410
case 42:
glfw.WindowHint(glfw.ContextVersionMajor, 4)
glfw.WindowHint(glfw.ContextVersionMinor, 2)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
GLSLVersion = 420
default: // 32
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 2)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
GLSLVersion = 150
}
return GLSLVersion
}

// Configure instanciates the video package
func (video *Video) Configure(fullscreen bool) {
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 2)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

var width, height int
var m *glfw.Monitor
GLSLVersion := video.configureContext()

if fullscreen {
m = glfw.GetMonitors()[settings.Settings.VideoMonitorIndex]
@@ -112,7 +163,7 @@ func (video *Video) Configure(fullscreen bool) {
video.CoreRatioViewport(fbw, fbh)

// LoadFont (fontfile, font scale, window width, window height)
video.Font, err = glfont.LoadFont("assets/font.ttf", int32(64), fbw, fbh)
video.Font, err = glfont.LoadFont("assets/font.ttf", int32(64), fbw, fbh, GLSLVersion)
if err != nil {
panic(err)
}
@@ -123,27 +174,27 @@ func (video *Video) Configure(fullscreen bool) {
}

// Configure the vertex and fragment shaders
video.program, err = newProgram(vertexShader, darkenFragmentShader)
video.program, err = newProgram(GLSLVersion, vertexShader, darkenFragmentShader)
if err != nil {
panic(err)
}

video.roundedProgram, err = newProgram(vertexShader, roundedFragmentShader)
video.roundedProgram, err = newProgram(GLSLVersion, vertexShader, roundedFragmentShader)
if err != nil {
panic(err)
}

video.borderProgram, err = newProgram(vertexShader, borderFragmentShader)
video.borderProgram, err = newProgram(GLSLVersion, vertexShader, borderFragmentShader)
if err != nil {
panic(err)
}

video.circleProgram, err = newProgram(vertexShader, circleFragmentShader)
video.circleProgram, err = newProgram(GLSLVersion, vertexShader, circleFragmentShader)
if err != nil {
panic(err)
}

video.demulProgram, err = newProgram(vertexShader, demulFragmentShader)
video.demulProgram, err = newProgram(GLSLVersion, vertexShader, demulFragmentShader)
if err != nil {
panic(err)
}
@@ -303,78 +354,6 @@ func (video *Video) Refresh(data unsafe.Pointer, width int32, height int32, pitc
}
}

func newProgram(vertexShaderSource, fragmentShaderSource string) (uint32, error) {
vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
if err != nil {
return 0, err
}

fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
if err != nil {
return 0, err
}

program := gl.CreateProgram()

gl.AttachShader(program, vertexShader)
gl.AttachShader(program, fragmentShader)
gl.LinkProgram(program)

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

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

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

gl.DeleteShader(vertexShader)
gl.DeleteShader(fragmentShader)

return program, nil
}

func compileShader(source string, shaderType uint32) (uint32, error) {
shader := gl.CreateShader(shaderType)

csources, free := gl.Strs(source)
gl.ShaderSource(shader, 1, csources, nil)
free()
gl.CompileShader(shader)

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

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

return 0, fmt.Errorf("failed to compile %v: %v", source, log)
}

return shader, nil
}

var vertexShader = `
#version 330
in vec2 vert;
in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
fragTexCoord = vertTexCoord;
gl_Position = vec4(vert, 0, 1);
}
` + "\x00"

var vertices = []float32{
// X, Y, U, V
-1.0, -1.0, 0.0, 1.0, // left-bottom