Compare commits

..

No commits in common. "0142d5ea6e00dd0386bcb95244737aa6ea39f662" and "0497ff9ac78c040c456ce781e50eb384f0ee68e1" have entirely different histories.

17 changed files with 13699 additions and 377 deletions

4
.gitignore vendored
View File

@ -1,3 +1,3 @@
opengl-deferred opengl-deferred
assets assets/textures
!assets/shader assets/geometries

View File

@ -0,0 +1,2 @@
# Blender 3.4.1 MTL File: 'None'
# www.blender.org

View File

@ -0,0 +1,47 @@
# Blender 3.4.1
# www.blender.org
mtllib cube.mtl
o Cube
v -1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.000000 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 0.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vt 1.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vt 1.000000 1.000000
s 0
f 2/2/1 3/6/1 1/1/1
f 4/8/2 7/14/2 3/4/2
f 8/16/3 5/9/3 7/14/3
f 6/12/4 1/1/4 5/10/4
f 7/15/5 1/1/5 3/5/5
f 4/8/6 6/13/6 8/16/6
f 2/2/1 4/7/1 3/6/1
f 4/8/2 8/16/2 7/14/2
f 8/16/3 6/11/3 5/9/3
f 6/12/4 2/2/4 1/1/4
f 7/15/5 5/10/5 1/1/5
f 4/8/6 2/3/6 6/13/6

View File

@ -0,0 +1,2 @@
# Blender 3.4.1 MTL File: 'None'
# www.blender.org

View File

@ -0,0 +1,16 @@
# Blender 3.4.1
# www.blender.org
mtllib plane.mtl
o Plane
v -10.000000 0.000000 10.000000
v 10.000000 0.000000 10.000000
v -10.000000 0.000000 -10.000000
v 10.000000 0.000000 -10.000000
vn -0.0000 1.0000 -0.0000
vt 0.999900 0.000100
vt 0.999900 0.999900
vt 0.000100 0.000100
vt 0.000100 0.999900
s 0
f 2/2/1 3/3/1 1/1/1
f 2/2/1 4/4/1 3/3/1

View File

@ -0,0 +1,2 @@
# Blender 3.4.1 MTL File: 'None'
# www.blender.org

File diff suppressed because it is too large Load Diff

9965
assets/geometries/teapot.obj Normal file

File diff suppressed because it is too large Load Diff

1
go.mod
View File

@ -10,5 +10,4 @@ require (
github.com/go-gl/mathgl v1.1.0 // indirect github.com/go-gl/mathgl v1.1.0 // indirect
github.com/udhos/gwob v1.0.0 // indirect github.com/udhos/gwob v1.0.0 // indirect
golang.org/x/image v0.21.0 // indirect golang.org/x/image v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

3
go.sum
View File

@ -16,6 +16,3 @@ golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMx
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

152
main.go
View File

@ -2,13 +2,14 @@ package main
import ( import (
"fmt" "fmt"
"os"
"runtime" "runtime"
"git.tek.govt.hu/dowerx/opengl-deferred/types/gbuffer" "git.tek.govt.hu/dowerx/opengl-deferred/types/gbuffer"
"git.tek.govt.hu/dowerx/opengl-deferred/types/geometry" "git.tek.govt.hu/dowerx/opengl-deferred/types/geometry"
"git.tek.govt.hu/dowerx/opengl-deferred/types/light" "git.tek.govt.hu/dowerx/opengl-deferred/types/light"
"git.tek.govt.hu/dowerx/opengl-deferred/types/material" "git.tek.govt.hu/dowerx/opengl-deferred/types/shader"
am "git.tek.govt.hu/dowerx/opengl-deferred/utils/assetmanager" "git.tek.govt.hu/dowerx/opengl-deferred/types/texture"
"git.tek.govt.hu/dowerx/opengl-deferred/utils/fpscontrols" "git.tek.govt.hu/dowerx/opengl-deferred/utils/fpscontrols"
"github.com/go-gl/gl/v4.6-core/gl" "github.com/go-gl/gl/v4.6-core/gl"
"github.com/go-gl/glfw/v3.3/glfw" "github.com/go-gl/glfw/v3.3/glfw"
@ -16,13 +17,14 @@ import (
) )
const ( const (
WIDTH = 1280 WIDTH = 1600
HEIGHT = 720 HEIGHT = 900
TITLE = "opengl-deferred" TITLE = "opengl-deferred"
FOV = 75.0 FOV = 45.0
) )
func main() { func main() {
// init glfw // init glfw
runtime.LockOSThread() runtime.LockOSThread()
if err := glfw.Init(); err != nil { if err := glfw.Init(); err != nil {
@ -47,18 +49,65 @@ func main() {
panic(err) panic(err)
} }
gl.Enable(gl.DEPTH_TEST)
gl.Enable(gl.CULL_FACE) gl.Enable(gl.CULL_FACE)
gl.DepthFunc(gl.LESS) gl.DepthFunc(gl.LESS)
gl.ClearColor(0, 0, 0, 1) gl.ClearColor(0, 0, 0, 0)
fmt.Println("OpenGL version:", gl.GoStr(gl.GetString(gl.VERSION))) fmt.Println("OpenGL version:", gl.GoStr(gl.GetString(gl.VERSION)))
// load assets // load assets
assetManager, err := am.Init("assets") // shader
vertexSource, err := os.ReadFile("assets/shader/deferred/deferred.vs")
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer assetManager.Destroy() fragmentSource, err := os.ReadFile("assets/shader/deferred/deferred.fs")
if err != nil {
panic(err)
}
deferredShader, err := shader.New(string(vertexSource), string(fragmentSource))
if err != nil {
panic(err)
}
defer deferredShader.Delete()
vertexSource, err = os.ReadFile("assets/shader/pbr/pbr.vs")
if err != nil {
panic(err)
}
// fragmentSource, err = os.ReadFile("assets/shader/screen/screen-debug.fs")
// fragmentSource, err = os.ReadFile("assets/shader/screen/screen.fs")
fragmentSource, err = os.ReadFile("assets/shader/pbr/pbr.fs")
if err != nil {
panic(err)
}
screenShader, err := shader.New(string(vertexSource), string(fragmentSource))
if err != nil {
panic(err)
}
defer screenShader.Delete()
// geometry
var geometries []geometry.Geometry
cube, err := geometry.LoadOBJ("assets/geometries/cube.obj")
if err != nil {
panic(err)
}
defer cube.Delete()
geometries = append(geometries, cube)
plane, err := geometry.LoadOBJ("assets/geometries/plane.obj")
if err != nil {
panic(err)
}
defer plane.Delete()
geometries = append(geometries, plane)
screen, err := geometry.Screen() screen, err := geometry.Screen()
if err != nil { if err != nil {
@ -66,6 +115,49 @@ func main() {
} }
defer screen.Delete() defer screen.Delete()
// textures
albedo, err := texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_albedo.tif")
if err != nil {
panic(err)
}
defer albedo.Delete()
normal, err := texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_normal.tif")
if err != nil {
panic(err)
}
defer normal.Delete()
specular, err := texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_roughness.tif")
if err != nil {
panic(err)
}
defer specular.Delete()
roughness, err := texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_roughness.tif")
if err != nil {
panic(err)
}
defer roughness.Delete()
metalic, err := texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_roughness.tif")
if err != nil {
panic(err)
}
defer metalic.Delete()
white, err := texture.Load("assets/textures/white.png")
if err != nil {
panic(err)
}
defer white.Delete()
black, err := texture.Load("assets/textures/black.png")
if err != nil {
panic(err)
}
defer black.Delete()
// lights // lights
lights := []light.Light{ lights := []light.Light{
{Color: [3]float32{1, 1, 1}, Position: mgl32.Vec3{0, 10, 0}, Intensity: 40, Type: light.POINT}, {Color: [3]float32{1, 1, 1}, Position: mgl32.Vec3{0, 10, 0}, Intensity: 40, Type: light.POINT},
@ -84,12 +176,7 @@ func main() {
// transformations // transformations
projection := mgl32.Perspective(mgl32.DegToRad(FOV), float32(WIDTH)/HEIGHT, 0.1, 1000) projection := mgl32.Perspective(mgl32.DegToRad(FOV), float32(WIDTH)/HEIGHT, 0.1, 1000)
model := mgl32.Ident4() model := mgl32.Ident4()
controls := fpscontrols.Get(10, 10, mgl32.Vec3{0, 0, -10}, mgl32.Vec2{0, 0}, window) controls := fpscontrols.Get(15, 10, mgl32.Vec3{0, 0, -10}, mgl32.Vec2{0, 0}, window)
demoMaterial := am.GetAsset[material.Material](assetManager, "assets/material/demo")
screenMaterial := am.GetAsset[material.Material](assetManager, "assets/material/screen")
teapot := am.GetAsset[geometry.Geometry](assetManager, "assets/geometry/teapot")
for !window.ShouldClose() { for !window.ShouldClose() {
glfw.PollEvents() glfw.PollEvents()
@ -102,14 +189,26 @@ func main() {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
// apply the material albedo.Bind(gl.TEXTURE0)
demoMaterial.Apply() normal.Bind(gl.TEXTURE1)
// transfer uniforms specular.Bind(gl.TEXTURE2)
demoMaterial.Shader.Mat4("projection", projection) roughness.Bind(gl.TEXTURE3)
demoMaterial.Shader.Mat4("view", controls.View()) metalic.Bind(gl.TEXTURE4)
demoMaterial.Shader.Mat4("model", model)
teapot.Draw() // transfer uniforms
deferredShader.Use()
deferredShader.Mat4("projection", projection)
deferredShader.Mat4("view", controls.View())
deferredShader.Mat4("model", model)
deferredShader.Int("s_albedo", 0)
deferredShader.Int("s_normal", 1)
deferredShader.Int("s_specular", 2)
deferredShader.Int("s_roughness", 3)
deferredShader.Int("s_metalic", 4)
for _, g := range geometries {
g.Draw()
}
// second pass // second pass
gl.Disable(gl.DEPTH_TEST) gl.Disable(gl.DEPTH_TEST)
@ -118,13 +217,18 @@ func main() {
gbuff.BindTextures() gbuff.BindTextures()
screenMaterial.Apply() screenShader.Use()
screenShader.Int("s_albedo", 0)
screenShader.Int("s_depth", 1)
screenShader.Int("s_normal", 2)
screenShader.Int("s_material", 3)
screenShader.Int("s_position", 4)
pos := controls.Position() pos := controls.Position()
screenMaterial.Shader.Vec3("view_pos", &pos[0]) screenShader.Vec3("view_pos", &pos[0])
for _, light := range lights { for _, light := range lights {
screenMaterial.Shader.Light(&light) screenShader.Light(&light)
} }
screen.Draw() screen.Draw()

View File

@ -1,5 +0,0 @@
package asset
type Asset interface {
Delete()
}

View File

@ -1,110 +0,0 @@
package material
import (
"errors"
"os"
"git.tek.govt.hu/dowerx/opengl-deferred/types/asset"
"git.tek.govt.hu/dowerx/opengl-deferred/types/shader"
"git.tek.govt.hu/dowerx/opengl-deferred/types/texture"
"github.com/go-gl/gl/v4.6-core/gl"
"gopkg.in/yaml.v3"
)
type MaterialDefiniton struct {
Shader string `yaml:"shader"`
Textures []struct {
Slot uint32 `yaml:"slot"`
Texture string `yaml:"texture"`
} `yaml:"textures"`
Values []struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Value interface{} `yaml:"value"`
} `yaml:"values"`
}
type Material struct {
Shader *shader.Shader
ShaderName string
Textures []struct {
Slot uint32
Texture *texture.Texture
TextureName string
}
Values []Value
}
func (m Material) Delete() {}
func (m *Material) Apply() {
m.Shader.Use()
for _, t := range m.Textures {
t.Texture.Bind(gl.TEXTURE0 + t.Slot)
}
for _, v := range m.Values {
v.Apply(m.Shader)
}
}
func Load(path string, assets map[string]asset.Asset) (Material, error) {
var definition MaterialDefiniton
var material Material
data, err := os.ReadFile(path)
if err != nil {
return material, err
}
if err = yaml.Unmarshal(data, &definition); err != nil {
return material, err
}
material.ShaderName = definition.Shader
for _, t := range definition.Textures {
material.Textures = append(material.Textures, struct {
Slot uint32
Texture *texture.Texture
TextureName string
}{Slot: t.Slot, TextureName: t.Texture})
}
for _, vdef := range definition.Values {
var value Value
switch vdef.Type {
case "int":
intval, ok := vdef.Value.(int32)
if !ok {
return material, err
}
value = IntValue{Name: vdef.Name, Value: intval}
default:
return material, errors.New("Unknown value: " + vdef.Type)
}
material.Values = append(material.Values, value)
}
return material, err
}
func (m *Material) AttachAssets(assets map[string]asset.Asset) error {
tmpShader, ok := assets[m.ShaderName].(shader.Shader)
if !ok {
return errors.New("Failed to attach shader to material: " + m.ShaderName)
}
m.Shader = &tmpShader
for i, t := range m.Textures {
tmpTexture, ok := assets[t.TextureName].(texture.Texture)
if !ok {
return errors.New("Failed to attach texture to material: " + t.TextureName)
}
m.Textures[i].Texture = &tmpTexture
}
return nil
}

View File

@ -1,16 +0,0 @@
package material
import "git.tek.govt.hu/dowerx/opengl-deferred/types/shader"
type Value interface {
Apply(s *shader.Shader)
}
type IntValue struct {
Name string
Value int32
}
func (v IntValue) Apply(s *shader.Shader) {
s.Int(v.Name, v.Value)
}

View File

@ -3,7 +3,6 @@ package shader
import ( import (
"errors" "errors"
"fmt" "fmt"
"os"
"strings" "strings"
"git.tek.govt.hu/dowerx/opengl-deferred/types/light" "git.tek.govt.hu/dowerx/opengl-deferred/types/light"
@ -22,7 +21,7 @@ func (s *Shader) Use() {
s.lightCount = 0 s.lightCount = 0
} }
func (s Shader) Delete() { func (s *Shader) Delete() {
gl.DeleteProgram(s.program) gl.DeleteProgram(s.program)
} }
@ -92,7 +91,7 @@ func compileShader(source string, shaderType uint32) (uint32, error) {
return shader, nil return shader, nil
} }
func New(vertexSource string, fragmentSource string) (shader Shader, _ error) { func New(vertexSource string, fragmantSource string) (shader Shader, _ error) {
shader.uniforms = make(map[string]int32) shader.uniforms = make(map[string]int32)
vertexShader, err := compileShader(vertexSource, gl.VERTEX_SHADER) vertexShader, err := compileShader(vertexSource, gl.VERTEX_SHADER)
@ -100,17 +99,17 @@ func New(vertexSource string, fragmentSource string) (shader Shader, _ error) {
return shader, err return shader, err
} }
fragmentShader, err := compileShader(fragmentSource, gl.FRAGMENT_SHADER) fragmantShader, err := compileShader(fragmantSource, gl.FRAGMENT_SHADER)
if err != nil { if err != nil {
return shader, err return shader, err
} }
shader.program = gl.CreateProgram() shader.program = gl.CreateProgram()
gl.AttachShader(shader.program, vertexShader) gl.AttachShader(shader.program, vertexShader)
gl.AttachShader(shader.program, fragmentShader) gl.AttachShader(shader.program, fragmantShader)
gl.LinkProgram(shader.program) gl.LinkProgram(shader.program)
defer gl.DeleteShader(vertexShader) defer gl.DeleteShader(vertexShader)
defer gl.DeleteShader(fragmentShader) defer gl.DeleteShader(fragmantShader)
var status int32 var status int32
gl.GetProgramiv(shader.program, gl.LINK_STATUS, &status) gl.GetProgramiv(shader.program, gl.LINK_STATUS, &status)
@ -126,21 +125,3 @@ func New(vertexSource string, fragmentSource string) (shader Shader, _ error) {
return shader, nil return shader, nil
} }
func FromFiles(vertexPath, fragmentPath string) (shader Shader, _ error) {
vertexSource, err := os.ReadFile(vertexPath)
if err != nil {
return shader, err
}
fragmentSource, err := os.ReadFile(fragmentPath)
if err != nil {
return shader, err
}
shader, err = New(string(vertexSource), string(fragmentSource))
if err != nil {
return shader, err
}
return shader, nil
}

View File

@ -1,146 +0,0 @@
package assetmanager
import (
"fmt"
"os"
"path/filepath"
"regexp"
"slices"
"strings"
"git.tek.govt.hu/dowerx/opengl-deferred/types/asset"
"git.tek.govt.hu/dowerx/opengl-deferred/types/geometry"
"git.tek.govt.hu/dowerx/opengl-deferred/types/material"
"git.tek.govt.hu/dowerx/opengl-deferred/types/shader"
"git.tek.govt.hu/dowerx/opengl-deferred/types/texture"
)
type AssetManager struct {
assets map[string]asset.Asset
}
var instance *AssetManager
var (
TEXTURE_EXTENSIONS = []string{"png", "tif"}
GEOMETRY_EXTENSIONS = []string{"obj"}
SHADER_EXTENSIONS = []string{"sdr"}
MATERIAL_EXTENSIONS = []string{"mtl"}
SCENE_EXTENSIONS = []string{"scn"}
VERTEX_REGEX = regexp.MustCompile("vertex_file (?P<path>.*)$")
FRAGMENT_REGEX = regexp.MustCompile("fragment_file (?P<path>.*)$")
)
func (a *AssetManager) loadItem(path string, itemToLoad os.DirEntry) error {
if itemToLoad.Type().IsDir() {
items, err := os.ReadDir(filepath.Join(path, itemToLoad.Name()))
if err != nil {
return err
}
for _, item := range items {
if err = a.loadItem(filepath.Join(path, itemToLoad.Name()), item); err != nil {
return err
}
}
} else if itemToLoad.Type().IsRegular() {
parts := strings.Split(itemToLoad.Name(), ".")
extension := parts[len(parts)-1]
var asset asset.Asset
var err error
if slices.Contains(TEXTURE_EXTENSIONS, extension) {
asset, err = texture.Load(filepath.Join(path, itemToLoad.Name()))
} else if slices.Contains(GEOMETRY_EXTENSIONS, extension) {
asset, err = geometry.LoadOBJ(filepath.Join(path, itemToLoad.Name()))
} else if slices.Contains(SHADER_EXTENSIONS, extension) {
definition, err := os.ReadFile(filepath.Join(path, itemToLoad.Name()))
if err != nil {
return err
}
var vertexPath, fragmentPath string
for _, line := range strings.Split(string(definition), "\n") {
var matches []string
if matches = VERTEX_REGEX.FindStringSubmatch(line); matches != nil {
vertexPath = matches[VERTEX_REGEX.SubexpIndex("path")]
} else if matches = FRAGMENT_REGEX.FindStringSubmatch(line); matches != nil {
fragmentPath = matches[FRAGMENT_REGEX.SubexpIndex("path")]
}
}
asset, err = shader.FromFiles(filepath.Join(path, vertexPath), filepath.Join(path, fragmentPath))
if err != nil {
return err
}
} else if slices.Contains(MATERIAL_EXTENSIONS, extension) {
asset, err = material.Load(filepath.Join(path, itemToLoad.Name()), a.assets)
} else {
return nil
}
if err != nil {
return err
}
a.assets[filepath.Join(path, itemToLoad.Name()[:len(itemToLoad.Name())-len(extension)-1])] = asset
}
return nil
}
func Init(path string) (*AssetManager, error) {
if instance != nil {
instance.Destroy()
}
instance = &AssetManager{make(map[string]asset.Asset)}
items, err := os.ReadDir(path)
if err != nil {
return nil, err
}
for _, item := range items {
err = instance.loadItem(path, item)
if err != nil {
return nil, err
}
}
for k, asset := range instance.assets {
material, ok := asset.(material.Material)
if ok {
material.AttachAssets(instance.assets)
instance.assets[k] = material
}
}
fmt.Println("Loaded assets:")
for k := range instance.assets {
fmt.Printf(" %s\n", k)
}
return instance, err
}
func Get() *AssetManager {
return instance
}
func GetAsset[T asset.Asset](a *AssetManager, name string) *T {
value, ok := a.assets[name].(T)
if !ok {
return nil
}
return &value
}
func (a *AssetManager) Destroy() {
for _, item := range a.assets {
item.Delete()
}
}

View File

@ -14,12 +14,12 @@ type FPSControls struct {
position mgl32.Vec3 position mgl32.Vec3
rotation mgl32.Vec2 rotation mgl32.Vec2
currentMove mgl32.Vec3
currentLook mgl32.Vec2
lastMousePos mgl32.Vec2 lastMousePos mgl32.Vec2
view mgl32.Mat4 view mgl32.Mat4
window *glfw.Window
lastTime float64 lastTime float64
} }
@ -28,54 +28,19 @@ var instance *FPSControls
func (c *FPSControls) Update() { func (c *FPSControls) Update() {
time := glfw.GetTime() time := glfw.GetTime()
var deltaTime float32 = float32(time - c.lastTime) deltaTime := time - c.lastTime
c.lastTime = time c.lastTime = time
_, right, _ := c.directions() forward, right, up := c.directions()
globalUp := mgl32.Vec3{0, 1, 0} globalUp := mgl32.Vec3{0, 1, 0}
move := right.Mul(c.currentMove.X()).Add(globalUp.Mul(c.currentMove.Y())).Add(forward.Mul(c.currentMove.Z()))
c.position = c.position.Add(move.Mul(float32(deltaTime) * c.moveSpeed))
move := mgl32.Vec3{0, 0, 0} c.rotation = c.rotation.Add(c.currentLook.Mul(float32(deltaTime) * c.lookSpeed))
c.currentLook = mgl32.Vec2{}
c.view = mgl32.LookAtV(c.position, c.position.Add(forward), up)
if c.window.GetKey(glfw.KeyA) == glfw.Press {
move[0] += 1
}
if c.window.GetKey(glfw.KeyD) == glfw.Press {
move[0] -= 1
}
if c.window.GetKey(glfw.KeySpace) == glfw.Press {
move[1] += 1
}
if c.window.GetKey(glfw.KeyLeftShift) == glfw.Press {
move[1] -= 1
}
if c.window.GetKey(glfw.KeyW) == glfw.Press {
move[2] += 1
}
if c.window.GetKey(glfw.KeyS) == glfw.Press {
move[2] -= 1
}
move = right.Mul(move.X()).Add(globalUp.Mul(move.Y())).Add(right.Cross(globalUp).Mul(move.Z()))
c.position = c.position.Add(move.Mul(deltaTime * c.moveSpeed))
x, y := c.window.GetCursorPos()
look := mgl32.Vec2{
float32(y) - c.lastMousePos.X(),
c.lastMousePos.Y() - float32(x),
}.Mul(deltaTime * c.lookSpeed)
c.rotation = c.rotation.Add(look)
c.rotation = mgl32.Vec2{
min(max(-89.9, c.rotation.X()), 89.9),
float32(int32(c.rotation.Y())%360) + c.rotation.Y() - float32(int32(c.rotation.Y())),
}
c.lastMousePos[0] = float32(y)
c.lastMousePos[1] = float32(x)
forward, _, _ := c.directions()
c.view = mgl32.LookAtV(c.position, c.position.Add(forward), globalUp)
} }
func Get(lookSpeed, moveSpeed float32, position mgl32.Vec3, rotation mgl32.Vec2, window *glfw.Window) *FPSControls { func Get(lookSpeed, moveSpeed float32, position mgl32.Vec3, rotation mgl32.Vec2, window *glfw.Window) *FPSControls {
@ -88,9 +53,43 @@ func Get(lookSpeed, moveSpeed float32, position mgl32.Vec3, rotation mgl32.Vec2,
lookSpeed: lookSpeed, lookSpeed: lookSpeed,
position: position, position: position,
rotation: rotation, rotation: rotation,
window: window,
} }
window.SetKeyCallback(func(window *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
var val float32
switch action {
case glfw.Repeat:
return
case glfw.Press:
val = 1
case glfw.Release:
val = 0
}
switch key {
case glfw.KeyW:
instance.currentMove[2] = val
case glfw.KeyS:
instance.currentMove[2] = -val
case glfw.KeyA:
instance.currentMove[0] = val
case glfw.KeyD:
instance.currentMove[0] = -val
case glfw.KeySpace:
instance.currentMove[1] = val
case glfw.KeyLeftShift:
instance.currentMove[1] = -val
}
})
window.SetCursorPosCallback(func(window *glfw.Window, y float64, x float64) {
pos := mgl32.Vec2{float32(x), float32(y)}
instance.currentLook = instance.lastMousePos.Sub(pos)
instance.currentLook[0] *= -1
instance.lastMousePos = pos
})
window.SetInputMode(glfw.CursorMode, glfw.CursorDisabled) window.SetInputMode(glfw.CursorMode, glfw.CursorDisabled)
return instance return instance