better asset manager

This commit is contained in:
BENEDEK László 2024-12-17 01:16:17 +01:00
parent 5da859f0e7
commit 1b1abda7d0
4 changed files with 141 additions and 112 deletions

88
main.go
View File

@ -7,8 +7,6 @@ import (
"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/shader"
"git.tek.govt.hu/dowerx/opengl-deferred/types/texture"
"git.tek.govt.hu/dowerx/opengl-deferred/utils/assetmanager" "git.tek.govt.hu/dowerx/opengl-deferred/utils/assetmanager"
"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"
@ -55,43 +53,11 @@ func main() {
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 := assetmanager.Get() assetManager, err := assetmanager.Init("assets")
defer assetManager.Delete()
// shader
tmpShader, err := shader.FromFiles("assets/shader/deferred/deferred.vs", "assets/shader/deferred/deferred.fs")
if err != nil { if err != nil {
panic(err) panic(err)
} }
assetManager.Add("deferred", tmpShader) defer assetManager.Destroy()
tmpShader, err = shader.FromFiles("assets/shader/pbr/pbr.vs", "assets/shader/pbr/pbr.fs")
if err != nil {
panic(err)
}
assetManager.Add("pbr", tmpShader)
tmpShader, err = shader.FromFiles("assets/shader/screen/screen.vs", "assets/shader/screen/screen.fs")
if err != nil {
panic(err)
}
assetManager.Add("screen", tmpShader)
deferredShader := assetManager.Shadres["deferred"]
screenShader := assetManager.Shadres["pbr"]
// geometry
tmpGeometry, err := geometry.LoadOBJ("assets/geometries/20.obj")
if err != nil {
panic(err)
}
assetManager.Add("teapot", tmpGeometry)
// tmpGeometry, err = geometry.LoadOBJ("assets/geometries/plane.obj")
// if err != nil {
// panic(err)
// }
// assetManager.Add("plane", tmpGeometry)
screen, err := geometry.Screen() screen, err := geometry.Screen()
if err != nil { if err != nil {
@ -99,37 +65,6 @@ func main() {
} }
defer screen.Delete() defer screen.Delete()
// textures
tmpTexture, err := texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_albedo.tif")
if err != nil {
panic(err)
}
assetManager.Add("albedo", tmpTexture)
tmpTexture, err = texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_normal.tif")
if err != nil {
panic(err)
}
assetManager.Add("normal", tmpTexture)
tmpTexture, err = texture.Load("assets/textures/TCom_Pavement_PaintedConcrete3_512_roughness.tif")
if err != nil {
panic(err)
}
assetManager.Add("roughness", tmpTexture)
tmpTexture, err = texture.Load("assets/textures/white.png")
if err != nil {
panic(err)
}
assetManager.Add("white", tmpTexture)
tmpTexture, err = texture.Load("assets/textures/black.png")
if err != nil {
panic(err)
}
assetManager.Add("black", tmpTexture)
// 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},
@ -150,6 +85,10 @@ func main() {
model := mgl32.Ident4() model := mgl32.Ident4()
controls := fpscontrols.Get(10, 10, mgl32.Vec3{0, 0, -10}, mgl32.Vec2{0, 0}, window) controls := fpscontrols.Get(10, 10, mgl32.Vec3{0, 0, -10}, mgl32.Vec2{0, 0}, window)
deferredShader := assetManager.GetShader("assets/shader/deferred")
screenShader := assetManager.GetShader("assets/shader/screen")
teapot := assetManager.GetGeometry("assets/geometry/teapot")
for !window.ShouldClose() { for !window.ShouldClose() {
glfw.PollEvents() glfw.PollEvents()
controls.Update() controls.Update()
@ -161,11 +100,11 @@ func main() {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
assetManager.Textures["albedo"].Bind(gl.TEXTURE0) assetManager.GetTexture("assets/texture/albedo").Bind(gl.TEXTURE0)
assetManager.Textures["normal"].Bind(gl.TEXTURE1) assetManager.GetTexture("assets/texture/normal").Bind(gl.TEXTURE1)
assetManager.Textures["roughness"].Bind(gl.TEXTURE2) assetManager.GetTexture("assets/texture/roughness").Bind(gl.TEXTURE2)
assetManager.Textures["roughness"].Bind(gl.TEXTURE3) assetManager.GetTexture("assets/texture/roughness").Bind(gl.TEXTURE3)
assetManager.Textures["roughness"].Bind(gl.TEXTURE4) assetManager.GetTexture("assets/texture/roughness").Bind(gl.TEXTURE4)
// transfer uniforms // transfer uniforms
deferredShader.Use() deferredShader.Use()
@ -178,9 +117,8 @@ func main() {
deferredShader.Int("s_specular", 2) deferredShader.Int("s_specular", 2)
deferredShader.Int("s_roughness", 3) deferredShader.Int("s_roughness", 3)
deferredShader.Int("s_metalic", 4) deferredShader.Int("s_metalic", 4)
for _, g := range assetManager.Geometries {
g.Draw() teapot.Draw()
}
// second pass // second pass
gl.Disable(gl.DEPTH_TEST) gl.Disable(gl.DEPTH_TEST)

5
types/asset/asset.go Normal file
View File

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

View File

@ -22,7 +22,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)
} }

View File

@ -1,67 +1,153 @@
package assetmanager package assetmanager
import ( import (
"errors" "fmt"
"reflect" "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/geometry"
"git.tek.govt.hu/dowerx/opengl-deferred/types/shader" "git.tek.govt.hu/dowerx/opengl-deferred/types/shader"
"git.tek.govt.hu/dowerx/opengl-deferred/types/texture" "git.tek.govt.hu/dowerx/opengl-deferred/types/texture"
) )
type AssetManager struct { type AssetManager struct {
Geometries map[string]geometry.Geometry assets map[string]asset.Asset
Textures map[string]texture.Texture
Shadres map[string]shader.Shader
} }
var instance *AssetManager var instance *AssetManager
var ( var (
geometryType = reflect.TypeOf(geometry.Geometry{}) TEXTURE_EXTENSIONS = []string{"png", "tif"}
textureType = reflect.TypeOf(texture.Texture{}) GEOMETRY_EXTENSIONS = []string{"obj"}
shaderType = reflect.TypeOf(shader.Shader{}) SHADER_EXTENSIONS = []string{"sdr"}
VERTEX_REGEX = regexp.MustCompile("vertex_file (?P<path>.*)$")
FRAGMENT_REGEX = regexp.MustCompile("fragment_file (?P<path>.*)$")
) )
func Get() *AssetManager { func (a *AssetManager) loadItem(path string, itemToLoad os.DirEntry) error {
if instance != nil { if itemToLoad.Type().IsDir() {
return &AssetManager{} items, err := os.ReadDir(filepath.Join(path, itemToLoad.Name()))
if err != nil {
return err
} }
instance = &AssetManager{ for _, item := range items {
Geometries: make(map[string]geometry.Geometry), if err = a.loadItem(filepath.Join(path, itemToLoad.Name()), item); err != nil {
Textures: make(map[string]texture.Texture), return err
Shadres: make(map[string]shader.Shader), }
}
} 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
} }
return instance 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")]
}
} }
func (m *AssetManager) Add(key string, item interface{}) error { asset, err = shader.FromFiles(filepath.Join(path, vertexPath), filepath.Join(path, fragmentPath))
switch reflect.TypeOf(item) { if err != nil {
case geometryType: return err
m.Geometries[key] = item.(geometry.Geometry) }
case textureType: } else {
m.Textures[key] = item.(texture.Texture) return nil
case shaderType: }
m.Shadres[key] = item.(shader.Shader)
default: if err != nil {
return errors.New("unknown asset type") return err
}
a.assets[filepath.Join(path, itemToLoad.Name()[:len(itemToLoad.Name())-len(extension)-1])] = asset
} }
return nil return nil
} }
func (m *AssetManager) Delete() { func Init(path string) (*AssetManager, error) {
for _, g := range m.Geometries { if instance != nil {
g.Delete() instance.Destroy()
} }
for _, t := range m.Textures { instance = &AssetManager{make(map[string]asset.Asset)}
t.Delete()
items, err := os.ReadDir(path)
if err != nil {
return nil, err
} }
for _, s := range m.Shadres { for _, item := range items {
s.Delete() err = instance.loadItem(path, item)
if err != nil {
return nil, err
}
}
fmt.Println("Loaded assets:")
for k := range instance.assets {
fmt.Printf(" %s\n", k)
}
return instance, err
}
func Get() *AssetManager {
return instance
}
func (a *AssetManager) GetAsset(name string) asset.Asset {
return a.assets[name]
}
func (a *AssetManager) GetTexture(name string) *texture.Texture {
value, ok := a.GetAsset(name).(texture.Texture)
if !ok {
return nil
}
return &value
}
func (a *AssetManager) GetGeometry(name string) *geometry.Geometry {
value, ok := a.GetAsset(name).(geometry.Geometry)
if !ok {
return nil
}
return &value
}
func (a *AssetManager) GetShader(name string) *shader.Shader {
value, ok := a.GetAsset(name).(shader.Shader)
if !ok {
return nil
}
return &value
}
func (a *AssetManager) Destroy() {
for _, item := range a.assets {
item.Delete()
} }
} }