diff --git a/main.go b/main.go index b733023..0c66c75 100644 --- a/main.go +++ b/main.go @@ -7,8 +7,6 @@ import ( "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/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/fpscontrols" "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))) // load assets - assetManager := assetmanager.Get() - defer assetManager.Delete() - - // shader - tmpShader, err := shader.FromFiles("assets/shader/deferred/deferred.vs", "assets/shader/deferred/deferred.fs") + assetManager, err := assetmanager.Init("assets") if err != nil { panic(err) } - assetManager.Add("deferred", tmpShader) - - 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) + defer assetManager.Destroy() screen, err := geometry.Screen() if err != nil { @@ -99,37 +65,6 @@ func main() { } 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 := []light.Light{ {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() 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() { glfw.PollEvents() controls.Update() @@ -161,11 +100,11 @@ func main() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) - assetManager.Textures["albedo"].Bind(gl.TEXTURE0) - assetManager.Textures["normal"].Bind(gl.TEXTURE1) - assetManager.Textures["roughness"].Bind(gl.TEXTURE2) - assetManager.Textures["roughness"].Bind(gl.TEXTURE3) - assetManager.Textures["roughness"].Bind(gl.TEXTURE4) + assetManager.GetTexture("assets/texture/albedo").Bind(gl.TEXTURE0) + assetManager.GetTexture("assets/texture/normal").Bind(gl.TEXTURE1) + assetManager.GetTexture("assets/texture/roughness").Bind(gl.TEXTURE2) + assetManager.GetTexture("assets/texture/roughness").Bind(gl.TEXTURE3) + assetManager.GetTexture("assets/texture/roughness").Bind(gl.TEXTURE4) // transfer uniforms deferredShader.Use() @@ -178,9 +117,8 @@ func main() { deferredShader.Int("s_specular", 2) deferredShader.Int("s_roughness", 3) deferredShader.Int("s_metalic", 4) - for _, g := range assetManager.Geometries { - g.Draw() - } + + teapot.Draw() // second pass gl.Disable(gl.DEPTH_TEST) diff --git a/types/asset/asset.go b/types/asset/asset.go new file mode 100644 index 0000000..038fea9 --- /dev/null +++ b/types/asset/asset.go @@ -0,0 +1,5 @@ +package asset + +type Asset interface { + Delete() +} diff --git a/types/shader/shader.go b/types/shader/shader.go index f9752c1..bfb3f74 100644 --- a/types/shader/shader.go +++ b/types/shader/shader.go @@ -22,7 +22,7 @@ func (s *Shader) Use() { s.lightCount = 0 } -func (s *Shader) Delete() { +func (s Shader) Delete() { gl.DeleteProgram(s.program) } diff --git a/utils/assetmanager/assetmanager.go b/utils/assetmanager/assetmanager.go index 8e9e3b8..4bc5ed1 100644 --- a/utils/assetmanager/assetmanager.go +++ b/utils/assetmanager/assetmanager.go @@ -1,67 +1,153 @@ package assetmanager import ( - "errors" - "reflect" + "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/shader" "git.tek.govt.hu/dowerx/opengl-deferred/types/texture" ) type AssetManager struct { - Geometries map[string]geometry.Geometry - Textures map[string]texture.Texture - Shadres map[string]shader.Shader + assets map[string]asset.Asset } var instance *AssetManager var ( - geometryType = reflect.TypeOf(geometry.Geometry{}) - textureType = reflect.TypeOf(texture.Texture{}) - shaderType = reflect.TypeOf(shader.Shader{}) + TEXTURE_EXTENSIONS = []string{"png", "tif"} + GEOMETRY_EXTENSIONS = []string{"obj"} + SHADER_EXTENSIONS = []string{"sdr"} + + VERTEX_REGEX = regexp.MustCompile("vertex_file (?P.*)$") + FRAGMENT_REGEX = regexp.MustCompile("fragment_file (?P.*)$") ) -func Get() *AssetManager { - if instance != nil { - return &AssetManager{} - } +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 + } - instance = &AssetManager{ - Geometries: make(map[string]geometry.Geometry), - Textures: make(map[string]texture.Texture), - Shadres: make(map[string]shader.Shader), - } + 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] - return instance -} + var asset asset.Asset + var err error -func (m *AssetManager) Add(key string, item interface{}) error { - switch reflect.TypeOf(item) { - case geometryType: - m.Geometries[key] = item.(geometry.Geometry) - case textureType: - m.Textures[key] = item.(texture.Texture) - case shaderType: - m.Shadres[key] = item.(shader.Shader) - default: - return errors.New("unknown asset type") + 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 { + return nil + } + + if err != nil { + return err + } + + a.assets[filepath.Join(path, itemToLoad.Name()[:len(itemToLoad.Name())-len(extension)-1])] = asset } return nil } -func (m *AssetManager) Delete() { - for _, g := range m.Geometries { - g.Delete() +func Init(path string) (*AssetManager, error) { + if instance != nil { + instance.Destroy() } - for _, t := range m.Textures { - t.Delete() + instance = &AssetManager{make(map[string]asset.Asset)} + + items, err := os.ReadDir(path) + if err != nil { + return nil, err } - for _, s := range m.Shadres { - s.Delete() + for _, item := range items { + 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() } }