mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Fresh start
This commit is contained in:
@ -1,45 +0,0 @@
|
|||||||
package input
|
|
||||||
|
|
||||||
import "github.com/veandco/go-sdl2/sdl"
|
|
||||||
|
|
||||||
var (
|
|
||||||
anyKeyDown bool
|
|
||||||
anyMouseBtnDown bool
|
|
||||||
)
|
|
||||||
|
|
||||||
//EventLoopStarted should be called just before processing SDL events
|
|
||||||
func EventLoopStarted() {
|
|
||||||
|
|
||||||
anyKeyDown = false
|
|
||||||
anyMouseBtnDown = false
|
|
||||||
|
|
||||||
//Clear XThisFrame which is needed because a repeat event needs multiple frames to happen
|
|
||||||
for _, v := range mouseBtns {
|
|
||||||
|
|
||||||
v.isDoubleClick = false
|
|
||||||
v.pressedThisFrame = false
|
|
||||||
v.releasedThisFrame = false
|
|
||||||
|
|
||||||
if v.state == sdl.PRESSED {
|
|
||||||
anyMouseBtnDown = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range keyboardKeys {
|
|
||||||
|
|
||||||
v.pressedThisFrame = false
|
|
||||||
v.releasedThisFrame = false
|
|
||||||
|
|
||||||
if v.state == sdl.PRESSED {
|
|
||||||
anyKeyDown = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AnyKeyDown() bool {
|
|
||||||
return anyKeyDown
|
|
||||||
}
|
|
||||||
|
|
||||||
func AnyMouseBtnDown() bool {
|
|
||||||
return anyMouseBtnDown
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
package input
|
|
||||||
|
|
||||||
import "github.com/veandco/go-sdl2/sdl"
|
|
||||||
|
|
||||||
type keyState struct {
|
|
||||||
key sdl.Keycode
|
|
||||||
state byte
|
|
||||||
pressedThisFrame bool
|
|
||||||
releasedThisFrame bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
keyboardKeys = make(map[sdl.Keycode]*keyState)
|
|
||||||
)
|
|
||||||
|
|
||||||
func HandleKeyboardEvent(e *sdl.KeyboardEvent) {
|
|
||||||
|
|
||||||
ks := keyboardKeys[e.Keysym.Sym]
|
|
||||||
if ks == nil {
|
|
||||||
ks = &keyState{key: e.Keysym.Sym}
|
|
||||||
keyboardKeys[e.Keysym.Sym] = ks
|
|
||||||
}
|
|
||||||
|
|
||||||
ks.state = e.State
|
|
||||||
ks.pressedThisFrame = e.Repeat == 0 && e.State == sdl.PRESSED
|
|
||||||
ks.releasedThisFrame = e.Repeat == 0 && e.State == sdl.RELEASED
|
|
||||||
}
|
|
||||||
|
|
||||||
func KeyClicked(kc sdl.Keycode) bool {
|
|
||||||
|
|
||||||
key := keyboardKeys[kc]
|
|
||||||
if key == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.pressedThisFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func KeyReleased(kc sdl.Keycode) bool {
|
|
||||||
|
|
||||||
key := keyboardKeys[kc]
|
|
||||||
if key == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.releasedThisFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func KeyDown(kc sdl.Keycode) bool {
|
|
||||||
|
|
||||||
key := keyboardKeys[kc]
|
|
||||||
if key == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.state == sdl.PRESSED
|
|
||||||
}
|
|
||||||
|
|
||||||
func KeyUp(kc sdl.Keycode) bool {
|
|
||||||
|
|
||||||
key := keyboardKeys[kc]
|
|
||||||
if key == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return key.state == sdl.RELEASED
|
|
||||||
}
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
package input
|
|
||||||
|
|
||||||
import "github.com/veandco/go-sdl2/sdl"
|
|
||||||
|
|
||||||
type mouseBtnState struct {
|
|
||||||
button byte
|
|
||||||
state byte
|
|
||||||
isDoubleClick bool
|
|
||||||
pressedThisFrame bool
|
|
||||||
releasedThisFrame bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
mouseBtns = make(map[byte]*mouseBtnState)
|
|
||||||
)
|
|
||||||
|
|
||||||
func HandleMouseBtnEvent(e *sdl.MouseButtonEvent) {
|
|
||||||
|
|
||||||
mb := mouseBtns[e.Button]
|
|
||||||
if mb == nil {
|
|
||||||
mb = &mouseBtnState{button: e.Button}
|
|
||||||
mouseBtns[e.Button] = mb
|
|
||||||
}
|
|
||||||
|
|
||||||
mb.state = e.State
|
|
||||||
mb.isDoubleClick = e.Clicks > 1 && e.State == sdl.PRESSED
|
|
||||||
mb.pressedThisFrame = e.State == sdl.PRESSED
|
|
||||||
mb.releasedThisFrame = e.State == sdl.RELEASED
|
|
||||||
}
|
|
||||||
|
|
||||||
func MouseClicked(mouseBtn byte) bool {
|
|
||||||
|
|
||||||
mb := mouseBtns[mouseBtn]
|
|
||||||
if mb == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return mb.pressedThisFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func MouseDoubleClicked(mouseBtn byte) bool {
|
|
||||||
|
|
||||||
mb := mouseBtns[mouseBtn]
|
|
||||||
if mb == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return mb.isDoubleClick
|
|
||||||
}
|
|
||||||
|
|
||||||
func MouseReleased(mouseBtn byte) bool {
|
|
||||||
|
|
||||||
mb := mouseBtns[mouseBtn]
|
|
||||||
if mb == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return mb.releasedThisFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func MouseDown(mouseBtn byte) bool {
|
|
||||||
|
|
||||||
mb := mouseBtns[mouseBtn]
|
|
||||||
if mb == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return mb.state == sdl.PRESSED
|
|
||||||
}
|
|
||||||
|
|
||||||
func MouseUp(mouseBtn byte) bool {
|
|
||||||
|
|
||||||
mb := mouseBtns[mouseBtn]
|
|
||||||
if mb == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return mb.state == sdl.RELEASED
|
|
||||||
}
|
|
||||||
238
main.go
238
main.go
@ -1,243 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bloeys/go-sdl-engine/input"
|
|
||||||
"github.com/bloeys/go-sdl-engine/logging"
|
|
||||||
"github.com/bloeys/go-sdl-engine/shaders"
|
|
||||||
"github.com/bloeys/go-sdl-engine/timing"
|
|
||||||
"github.com/go-gl/gl/v4.6-core/gl"
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
winWidth int32 = 1280
|
|
||||||
winHeight int32 = 720
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
isRunning = true
|
|
||||||
window *sdl.Window
|
|
||||||
glContext sdl.GLContext
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
err := sdl.Init(sdl.INIT_EVERYTHING)
|
|
||||||
if err != nil {
|
|
||||||
logging.ErrLog.Panicln("Failed to init SDL. Err:", err.Error())
|
|
||||||
}
|
|
||||||
defer sdl.Quit()
|
|
||||||
|
|
||||||
//Size of each pixel field
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_RED_SIZE, 8)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_GREEN_SIZE, 8)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_BLUE_SIZE, 8)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_ALPHA_SIZE, 8)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
//Min frame buffer size
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_BUFFER_SIZE, 4*8)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
//Whether to enable a double buffer
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
//Run in compatiability (old and modern opengl) or modern (core) opengl only
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
//Set wanted opengl version
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 4)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
err = sdl.GLSetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 6)
|
|
||||||
panicIfErr(err, "")
|
|
||||||
|
|
||||||
//Create window
|
|
||||||
window, err = sdl.CreateWindow(
|
|
||||||
"Go Game Engine",
|
|
||||||
sdl.WINDOWPOS_CENTERED,
|
|
||||||
sdl.WINDOWPOS_CENTERED,
|
|
||||||
winWidth,
|
|
||||||
winHeight,
|
|
||||||
sdl.WINDOW_OPENGL)
|
|
||||||
if err != nil {
|
|
||||||
logging.ErrLog.Panicln("Failed to create window. Err: " + err.Error())
|
|
||||||
}
|
|
||||||
defer window.Destroy()
|
|
||||||
|
|
||||||
//Create GL context
|
|
||||||
glContext, err = window.GLCreateContext()
|
|
||||||
if err != nil {
|
|
||||||
logging.ErrLog.Panicln("Creating OpenGL context failed. Err: " + err.Error())
|
|
||||||
}
|
|
||||||
defer sdl.GLDeleteContext(glContext)
|
|
||||||
|
|
||||||
if err := gl.Init(); err != nil {
|
|
||||||
logging.ErrLog.Panicln("Initing OpenGL Context failed. Err: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
initGL()
|
|
||||||
loadShaders()
|
|
||||||
gameLoop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func initGL() {
|
|
||||||
|
|
||||||
gl.ClearColor(0, 0, 0, 0)
|
|
||||||
|
|
||||||
gl.Enable(gl.DEPTH_TEST)
|
|
||||||
gl.ClearDepth(1)
|
|
||||||
gl.DepthFunc(gl.LEQUAL)
|
|
||||||
gl.Viewport(0, 0, winWidth, winHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
var simpleProg shaders.Program
|
|
||||||
|
|
||||||
func loadShaders() {
|
|
||||||
|
|
||||||
simpleVert, err := shaders.NewShaderFromFile("simpleVert", "./res/shaders/simple.vert.glsl", shaders.Vertex)
|
|
||||||
panicIfErr(err, "Parsing vert shader failed")
|
|
||||||
|
|
||||||
simpleFrag, err := shaders.NewShaderFromFile("simpleFrag", "./res/shaders/simple.frag.glsl", shaders.Fragment)
|
|
||||||
panicIfErr(err, "Parsing frag shader failed")
|
|
||||||
|
|
||||||
simpleProg = shaders.NewProgram("simple")
|
|
||||||
simpleProg.AttachShader(simpleVert)
|
|
||||||
simpleProg.AttachShader(simpleFrag)
|
|
||||||
simpleProg.Link()
|
|
||||||
}
|
|
||||||
|
|
||||||
var vao uint32
|
|
||||||
|
|
||||||
func gameLoop() {
|
|
||||||
|
|
||||||
//vertex positions in opengl coords
|
|
||||||
verts := []float32{
|
|
||||||
-0.5, 0.5, 0,
|
|
||||||
0.5, 0.5, 0,
|
|
||||||
0.5, -0.5, 0,
|
|
||||||
-0.5, -0.5, 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
//Trianlge indices used for drawing
|
|
||||||
indices := []uint32{
|
|
||||||
0, 1, 2,
|
|
||||||
0, 2, 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create a VAO to store the different VBOs of a given object/set of vertices
|
|
||||||
gl.GenVertexArrays(1, &vao)
|
|
||||||
|
|
||||||
//Bind the VAO first so later buffer binds/VBOs are put within this VAO
|
|
||||||
gl.BindVertexArray(vao)
|
|
||||||
|
|
||||||
//Gen buffer to hold EBOs and fill it with data. Note that an EBO must NOT be unbound before the VAO, otherwise
|
|
||||||
//its settings are lost as the VAO records its actions
|
|
||||||
var ebo uint32
|
|
||||||
gl.GenBuffers(1, &ebo)
|
|
||||||
|
|
||||||
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo)
|
|
||||||
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices)*4, gl.Ptr(indices), gl.STATIC_DRAW)
|
|
||||||
|
|
||||||
//Gen vertPos VBO and fill it with data
|
|
||||||
var vertPosVBO uint32
|
|
||||||
gl.GenBuffers(1, &vertPosVBO)
|
|
||||||
|
|
||||||
gl.BindBuffer(gl.ARRAY_BUFFER, vertPosVBO)
|
|
||||||
gl.BufferData(gl.ARRAY_BUFFER, len(verts)*4, gl.Ptr(verts), gl.STATIC_DRAW)
|
|
||||||
|
|
||||||
//Assign vertPos VBO to vertPos shader attribute by specifying that each vertPos variable
|
|
||||||
//takes 3 values from the VBO, where each value is a float.
|
|
||||||
|
|
||||||
//We also specify the total size (in bytes) of the values used for a single vertPos.
|
|
||||||
//The offset defines the bytes to skip between each set of vertPos values
|
|
||||||
vertPosLoc := uint32(gl.GetAttribLocation(simpleProg.ID, gl.Str("vertPos\x00")))
|
|
||||||
gl.VertexAttribPointer(vertPosLoc, 3, gl.FLOAT, false, 3*4, gl.PtrOffset(0))
|
|
||||||
|
|
||||||
//Vertex attributes are disabled by default, so we need to finally enable it
|
|
||||||
gl.EnableVertexAttribArray(vertPosLoc)
|
|
||||||
|
|
||||||
//We are done working with VBOs so can unbind the VAO to avoid corrupting it later.
|
|
||||||
//Note: Actions (binding/setting buffers, enabling/disabling attribs) done between
|
|
||||||
//bind and unbind of a VAO are recorded by it, and when its rebinded before a draw the
|
|
||||||
//settings are retrieved, therefore keep in mind work after a VAO unbind will be lost.
|
|
||||||
gl.BindVertexArray(0)
|
|
||||||
|
|
||||||
for isRunning {
|
|
||||||
|
|
||||||
timing.FrameStarted()
|
|
||||||
|
|
||||||
handleEvents()
|
|
||||||
update()
|
|
||||||
draw()
|
|
||||||
|
|
||||||
window.GLSwap()
|
|
||||||
|
|
||||||
timing.FrameEnded()
|
|
||||||
window.SetTitle(fmt.Sprintf("FPS: %.2f; dt: %.3f", timing.FPS(), timing.DT()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleEvents() {
|
|
||||||
|
|
||||||
input.EventLoopStarted()
|
|
||||||
|
|
||||||
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
|
||||||
|
|
||||||
switch e := event.(type) {
|
|
||||||
|
|
||||||
case *sdl.KeyboardEvent:
|
|
||||||
input.HandleKeyboardEvent(e)
|
|
||||||
|
|
||||||
case *sdl.MouseButtonEvent:
|
|
||||||
input.HandleMouseBtnEvent(e)
|
|
||||||
|
|
||||||
case *sdl.QuitEvent:
|
|
||||||
println("Quit at ", e.Timestamp)
|
|
||||||
isRunning = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func update() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func draw() {
|
|
||||||
//Clear screen and depth buffers
|
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
|
||||||
|
|
||||||
simpleProg.Use()
|
|
||||||
|
|
||||||
deg2rad := math.Pi / 180.0
|
|
||||||
t := float64(time.Now().UnixMilli()) / 10
|
|
||||||
|
|
||||||
x := float32(math.Sin(t*deg2rad*0.3)+1) * 0.5
|
|
||||||
y := float32(math.Sin(t*deg2rad*0.5)+1) * 0.5
|
|
||||||
z := float32(math.Sin(t*deg2rad*0.7)+1) * 0.5
|
|
||||||
simpleProg.SetUniformF32("c", x, y, z)
|
|
||||||
|
|
||||||
gl.BindVertexArray(vao)
|
|
||||||
gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, gl.PtrOffset(0))
|
|
||||||
gl.BindVertexArray(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func panicIfErr(err error, msg string) {
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logging.ErrLog.Panicln(msg+". Err:", err.Error())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
#version 460 core
|
|
||||||
|
|
||||||
uniform vec3 c;
|
|
||||||
|
|
||||||
out vec4 fragColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
fragColor = vec4(c, 1);
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#version 460 core
|
|
||||||
|
|
||||||
in vec3 vertPos;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = vec4(vertPos, 1.0);
|
|
||||||
}
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
package shaders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/bloeys/go-sdl-engine/logging"
|
|
||||||
"github.com/go-gl/gl/v4.6-core/gl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Program struct {
|
|
||||||
Name string
|
|
||||||
ID uint32
|
|
||||||
Shaders []Shader
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProgram(name string) Program {
|
|
||||||
|
|
||||||
p := Program{Name: name}
|
|
||||||
p.Shaders = make([]Shader, 0)
|
|
||||||
|
|
||||||
if p.ID = gl.CreateProgram(); p.ID == 0 {
|
|
||||||
logging.ErrLog.Fatalln("Creating OpenGL program failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
//AttachShader adds the shader to list of shaders and attaches it in opengl
|
|
||||||
func (p *Program) AttachShader(s Shader) {
|
|
||||||
|
|
||||||
p.Shaders = append(p.Shaders, s)
|
|
||||||
gl.AttachShader(p.ID, s.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
//DetachShader removes the shader from the list of shaders and detaches it in opengl
|
|
||||||
func (p *Program) DetachShader(s Shader) {
|
|
||||||
|
|
||||||
//To remove a shader we move the last shader to its place, then shrink the slice by one
|
|
||||||
for i := 0; i < len(p.Shaders); i++ {
|
|
||||||
|
|
||||||
if p.Shaders[i].ID != s.ID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.DetachShader(p.ID, s.ID)
|
|
||||||
|
|
||||||
p.Shaders[i] = p.Shaders[len(p.Shaders)-1]
|
|
||||||
p.Shaders = p.Shaders[:len(p.Shaders)-1]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Link deletes all shaders from opengl and clears the shaders array if linking is successful.
|
|
||||||
//Note: This is allowed because only the final program is needed after linking
|
|
||||||
func (p *Program) Link() error {
|
|
||||||
|
|
||||||
gl.LinkProgram(p.ID)
|
|
||||||
if err := getProgramLinkError(*p); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range p.Shaders {
|
|
||||||
gl.DeleteShader(v.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Shaders = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProgramLinkError(p Program) error {
|
|
||||||
|
|
||||||
var linkSuccessful int32
|
|
||||||
gl.GetProgramiv(p.ID, gl.LINK_STATUS, &linkSuccessful)
|
|
||||||
if linkSuccessful == gl.TRUE {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get the log length and create a string big enough for it and fill it with NULL
|
|
||||||
var logLength int32
|
|
||||||
gl.GetProgramiv(p.ID, gl.INFO_LOG_LENGTH, &logLength)
|
|
||||||
infoLog := gl.Str(strings.Repeat("\x00", int(logLength)))
|
|
||||||
|
|
||||||
//Read the error log and return a go error
|
|
||||||
gl.GetProgramInfoLog(p.ID, logLength, nil, infoLog)
|
|
||||||
return fmt.Errorf("Program linking failed. Linking log: %s", gl.GoStr(infoLog))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Program) Use() {
|
|
||||||
gl.UseProgram(p.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Program) GetUniformLocation(name string) int32 {
|
|
||||||
return gl.GetUniformLocation(p.ID, gl.Str(name+"\x00"))
|
|
||||||
}
|
|
||||||
|
|
||||||
//SetUniformF32 handles setting uniform values of 1-4 floats.
|
|
||||||
//Returns false if len(floats) is <1 or >4, or if the uniform was not found.
|
|
||||||
//Uniforms aren't found if it doesn't exist or was not used in the shader
|
|
||||||
func (p *Program) SetUniformF32(name string, floats ...float32) bool {
|
|
||||||
|
|
||||||
loc := p.GetUniformLocation(name)
|
|
||||||
if loc == -1 {
|
|
||||||
logging.WarnLog.Printf(
|
|
||||||
"Uniform with name '%s' was not found. "+
|
|
||||||
"This is either because it doesn't exist or isn't used in the shader",
|
|
||||||
name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch len(floats) {
|
|
||||||
case 1:
|
|
||||||
gl.Uniform1f(loc, floats[0])
|
|
||||||
case 2:
|
|
||||||
gl.Uniform2f(loc, floats[0], floats[1])
|
|
||||||
case 3:
|
|
||||||
gl.Uniform3f(loc, floats[0], floats[1], floats[2])
|
|
||||||
case 4:
|
|
||||||
gl.Uniform4f(loc, floats[0], floats[1], floats[2], floats[3])
|
|
||||||
default:
|
|
||||||
logging.ErrLog.Println("Invalid input size in SetUniformF32. Size must be 1-4 but got", len(floats))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
//SetUniformI32 handles setting uniform values of 1-4 ints.
|
|
||||||
//Returns false if len(ints) is <1 or >4, or if the uniform was not found.
|
|
||||||
//Uniforms aren't found if it doesn't exist or was not used in the shader
|
|
||||||
func (p *Program) SetUniformI32(name string, ints ...int32) bool {
|
|
||||||
|
|
||||||
loc := p.GetUniformLocation(name)
|
|
||||||
if loc == -1 {
|
|
||||||
logging.WarnLog.Printf(
|
|
||||||
"Uniform with name '%s' was not found. "+
|
|
||||||
"This is either because it doesn't exist or isn't used in the shader",
|
|
||||||
name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch len(ints) {
|
|
||||||
case 1:
|
|
||||||
gl.Uniform1i(loc, ints[0])
|
|
||||||
case 2:
|
|
||||||
gl.Uniform2i(loc, ints[0], ints[1])
|
|
||||||
case 3:
|
|
||||||
gl.Uniform3i(loc, ints[0], ints[1], ints[2])
|
|
||||||
case 4:
|
|
||||||
gl.Uniform4i(loc, ints[0], ints[1], ints[2], ints[3])
|
|
||||||
default:
|
|
||||||
logging.ErrLog.Println("Invalid input size in SetUniformI32. Size must be 1-4 but got", len(ints))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
//Delete deletes all shaders and then deletes the program
|
|
||||||
func (p *Program) Delete() {
|
|
||||||
for _, v := range p.Shaders {
|
|
||||||
v.Delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.DeleteProgram(p.ID)
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package shaders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/bloeys/go-sdl-engine/logging"
|
|
||||||
"github.com/go-gl/gl/v4.6-core/gl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Shader struct {
|
|
||||||
Name string
|
|
||||||
ID uint32
|
|
||||||
Type ShaderType
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewShaderFromFile reads a shader from file, creates a new opengl shader and compiles it
|
|
||||||
func NewShaderFromFile(name, shaderFilePath string, st ShaderType) (Shader, error) {
|
|
||||||
|
|
||||||
b, err := os.ReadFile(shaderFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return Shader{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewShaderFromString(name, string(b), st)
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewShaderFromString creates a new opengl shader and compiles it
|
|
||||||
func NewShaderFromString(name, sourceString string, st ShaderType) (Shader, error) {
|
|
||||||
|
|
||||||
glString, freeFunc := gl.Strs(sourceString + "\x00")
|
|
||||||
defer freeFunc()
|
|
||||||
|
|
||||||
newShader := Shader{Name: name, Type: st}
|
|
||||||
if newShader.ID = gl.CreateShader(st.GLType()); newShader.ID == 0 {
|
|
||||||
logging.ErrLog.Panicln("Creating shader failed. ShaderType:", st)
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.ShaderSource(newShader.ID, 1, glString, nil)
|
|
||||||
gl.CompileShader(newShader.ID)
|
|
||||||
|
|
||||||
return newShader, getShaderCompileError(newShader)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getShaderCompileError(s Shader) error {
|
|
||||||
|
|
||||||
var compileSuccessful int32
|
|
||||||
gl.GetShaderiv(s.ID, gl.COMPILE_STATUS, &compileSuccessful)
|
|
||||||
if compileSuccessful == gl.TRUE {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get the log length and create a string big enough for it and fill it with NULL
|
|
||||||
var logLength int32
|
|
||||||
gl.GetShaderiv(s.ID, gl.INFO_LOG_LENGTH, &logLength)
|
|
||||||
infoLog := gl.Str(strings.Repeat("\x00", int(logLength)))
|
|
||||||
|
|
||||||
//Read the error log and return a go error
|
|
||||||
gl.GetShaderInfoLog(s.ID, logLength, nil, infoLog)
|
|
||||||
return fmt.Errorf("Shader compilation failed. Compilation log: %s", gl.GoStr(infoLog))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Shader) Delete() {
|
|
||||||
gl.DeleteShader(s.ID)
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package shaders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/bloeys/go-sdl-engine/logging"
|
|
||||||
"github.com/go-gl/gl/v4.6-core/gl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ShaderType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
Unknown ShaderType = iota
|
|
||||||
Vertex
|
|
||||||
Fragment
|
|
||||||
)
|
|
||||||
|
|
||||||
//GLType returns the GL shader type of this ShaderType
|
|
||||||
//Panics if not known
|
|
||||||
func (t ShaderType) GLType() uint32 {
|
|
||||||
|
|
||||||
switch t {
|
|
||||||
case Vertex:
|
|
||||||
return gl.VERTEX_SHADER
|
|
||||||
case Fragment:
|
|
||||||
return gl.FRAGMENT_SHADER
|
|
||||||
}
|
|
||||||
|
|
||||||
logging.ErrLog.Panicf("Converting ShaderType->GL Shader Type failed. Unknown ShaderType of value: %v\n", t)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
//FromGLShaderType returns the ShaderType of the passed GL shader type.
|
|
||||||
//Panics if not known
|
|
||||||
func (t ShaderType) FromGLShaderType(glShaderType int) ShaderType {
|
|
||||||
|
|
||||||
switch glShaderType {
|
|
||||||
case gl.VERTEX_SHADER:
|
|
||||||
return Vertex
|
|
||||||
case gl.FRAGMENT_SHADER:
|
|
||||||
return Fragment
|
|
||||||
default:
|
|
||||||
logging.ErrLog.Panicf("Converting GL shader type->ShaderType failed. Unknown GL shader type of value: %v\n", glShaderType)
|
|
||||||
return Unknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
package timing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
fps float32 = 60
|
|
||||||
dt float32 = 1.0 / 60.0
|
|
||||||
dtLimit float32 = 1.0 / 120.0
|
|
||||||
frameStartTime time.Time = time.Now()
|
|
||||||
)
|
|
||||||
|
|
||||||
func FrameStarted() {
|
|
||||||
frameStartTime = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
func FrameEnded() {
|
|
||||||
|
|
||||||
//If FPS is more than 120 then limit to that
|
|
||||||
dt = float32(time.Since(frameStartTime).Seconds())
|
|
||||||
if dt < dtLimit {
|
|
||||||
sdl.Delay(8 - uint32(dt*1000))
|
|
||||||
dt = float32(time.Since(frameStartTime).Seconds())
|
|
||||||
}
|
|
||||||
|
|
||||||
//Display FPS is the average of the FPS of this frame and the last frame
|
|
||||||
fps = (fps + 1/dt) / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
//DT returns last frame delta time (number of seconds frame took)
|
|
||||||
func DT() float32 {
|
|
||||||
return dt
|
|
||||||
}
|
|
||||||
|
|
||||||
//FPS returns fps
|
|
||||||
func FPS() float32 {
|
|
||||||
return fps
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user