From 6dee7b0f1dff197f661d90dfa5ed96be79714ffe Mon Sep 17 00:00:00 2001 From: bloeys Date: Sat, 22 Jan 2022 22:23:44 +0400 Subject: [PATCH] Starting work on Engine+Mesh+Material systems/packages --- buffers/buffers.go | 4 +- engine/engine.go | 108 +++++++++++++ engine/windowflags.go | 29 ++++ main.go | 311 ++++++++++---------------------------- materials/material.go | 109 +++++++++++++ meshes/mesh.go | 81 ++++++++++ shaders/shader_program.go | 73 --------- 7 files changed, 407 insertions(+), 308 deletions(-) create mode 100755 engine/engine.go create mode 100755 engine/windowflags.go create mode 100755 materials/material.go create mode 100755 meshes/mesh.go diff --git a/buffers/buffers.go b/buffers/buffers.go index 835a1ed..1c89edb 100755 --- a/buffers/buffers.go +++ b/buffers/buffers.go @@ -153,11 +153,11 @@ func (bo *BufferObject) SetBuffer(buf *Buffer) { } } -func (bo *BufferObject) Activate() { +func (bo *BufferObject) Bind() { gl.BindVertexArray(bo.VAOID) } -func (bo *BufferObject) Deactivate() { +func (bo *BufferObject) UnBind() { gl.BindVertexArray(0) } diff --git a/engine/engine.go b/engine/engine.go new file mode 100755 index 0000000..ddaeb6c --- /dev/null +++ b/engine/engine.go @@ -0,0 +1,108 @@ +package engine + +import ( + "github.com/bloeys/nmage/timing" + "github.com/go-gl/gl/v4.1-core/gl" + "github.com/veandco/go-sdl2/sdl" +) + +type Window struct { + SDLWin *sdl.Window + GlCtx sdl.GLContext +} + +func (w *Window) Destroy() error { + return w.SDLWin.Destroy() +} + +func Init() error { + + timing.Init() + err := initSDL() + + return err +} + +func initSDL() error { + + err := sdl.Init(sdl.INIT_EVERYTHING) + if err != nil { + return err + } + + sdl.ShowCursor(1) + + sdl.GLSetAttribute(sdl.MAJOR_VERSION, 4) + sdl.GLSetAttribute(sdl.MINOR_VERSION, 1) + + // R(0-255) G(0-255) B(0-255) + sdl.GLSetAttribute(sdl.GL_RED_SIZE, 8) + sdl.GLSetAttribute(sdl.GL_GREEN_SIZE, 8) + sdl.GLSetAttribute(sdl.GL_BLUE_SIZE, 8) + + sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1) + sdl.GLSetAttribute(sdl.GL_DEPTH_SIZE, 24) + sdl.GLSetAttribute(sdl.GL_STENCIL_SIZE, 8) + + sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE) + + return nil +} + +func CreateOpenGLWindow(title string, x, y, width, height int32, flags WindowFlags) (*Window, error) { + return createWindow(title, x, y, width, height, WindowFlags_OPENGL|flags) +} + +func CreateOpenGLWindowCentered(title string, width, height int32, flags WindowFlags) (*Window, error) { + return createWindow(title, -1, -1, width, height, WindowFlags_OPENGL|flags) +} + +func createWindow(title string, x, y, width, height int32, flags WindowFlags) (*Window, error) { + + if x == -1 && y == -1 { + x = sdl.WINDOWPOS_CENTERED + y = sdl.WINDOWPOS_CENTERED + } + + sdlWin, err := sdl.CreateWindow(title, x, y, width, height, uint32(flags)) + if err != nil { + return nil, err + } + win := &Window{SDLWin: sdlWin} + + win.GlCtx, err = sdlWin.GLCreateContext() + if err != nil { + return nil, err + } + + err = initOpenGL() + if err != nil { + return nil, err + } + + return win, err +} + +func initOpenGL() error { + + if err := gl.Init(); err != nil { + return err + } + + gl.Enable(gl.DEPTH_TEST) + + gl.Enable(gl.CULL_FACE) + gl.CullFace(gl.BACK) + gl.FrontFace(gl.CCW) + + gl.ClearColor(0, 0, 0, 1) + return nil +} + +func SetVSync(enabled bool) { + if enabled { + sdl.GLSetSwapInterval(1) + } else { + sdl.GLSetSwapInterval(0) + } +} diff --git a/engine/windowflags.go b/engine/windowflags.go new file mode 100755 index 0000000..1593867 --- /dev/null +++ b/engine/windowflags.go @@ -0,0 +1,29 @@ +package engine + +import "github.com/veandco/go-sdl2/sdl" + +type WindowFlags int + +const ( + WindowFlags_FULLSCREEN WindowFlags = sdl.WINDOW_FULLSCREEN + WindowFlags_OPENGL WindowFlags = sdl.WINDOW_OPENGL + WindowFlags_SHOWN WindowFlags = sdl.WINDOW_SHOWN + WindowFlags_HIDDEN WindowFlags = sdl.WINDOW_HIDDEN + WindowFlags_BORDERLESS WindowFlags = sdl.WINDOW_BORDERLESS + WindowFlags_RESIZABLE WindowFlags = sdl.WINDOW_RESIZABLE + WindowFlags_MINIMIZED WindowFlags = sdl.WINDOW_MINIMIZED + WindowFlags_MAXIMIZED WindowFlags = sdl.WINDOW_MAXIMIZED + WindowFlags_INPUT_GRABBED WindowFlags = sdl.WINDOW_INPUT_GRABBED + WindowFlags_INPUT_FOCUS WindowFlags = sdl.WINDOW_INPUT_FOCUS + WindowFlags_MOUSE_FOCUS WindowFlags = sdl.WINDOW_MOUSE_FOCUS + WindowFlags_FULLSCREEN_DESKTOP WindowFlags = sdl.WINDOW_FULLSCREEN_DESKTOP + WindowFlags_FOREIGN WindowFlags = sdl.WINDOW_FOREIGN + WindowFlags_ALLOW_HIGHDPI WindowFlags = sdl.WINDOW_ALLOW_HIGHDPI + WindowFlags_MOUSE_CAPTURE WindowFlags = sdl.WINDOW_MOUSE_CAPTURE + WindowFlags_ALWAYS_ON_TOP WindowFlags = sdl.WINDOW_ALWAYS_ON_TOP + WindowFlags_SKIP_TASKBAR WindowFlags = sdl.WINDOW_SKIP_TASKBAR + WindowFlags_UTILITY WindowFlags = sdl.WINDOW_UTILITY + WindowFlags_TOOLTIP WindowFlags = sdl.WINDOW_TOOLTIP + WindowFlags_POPUP_MENU WindowFlags = sdl.WINDOW_POPUP_MENU + // WindowFlags_VULKAN WindowFlags = sdl.WINDOW_VULKAN +) diff --git a/main.go b/main.go index 73236c4..ea0996f 100755 --- a/main.go +++ b/main.go @@ -6,28 +6,31 @@ import ( "github.com/bloeys/assimp-go/asig" "github.com/bloeys/gglm/gglm" - "github.com/bloeys/nmage/asserts" - "github.com/bloeys/nmage/buffers" + "github.com/bloeys/nmage/engine" "github.com/bloeys/nmage/input" "github.com/bloeys/nmage/logging" - "github.com/bloeys/nmage/shaders" + "github.com/bloeys/nmage/materials" + "github.com/bloeys/nmage/meshes" "github.com/bloeys/nmage/timing" "github.com/go-gl/gl/v4.1-core/gl" "github.com/inkyblackness/imgui-go/v4" "github.com/veandco/go-sdl2/sdl" ) -//TODO: -//Make a window/engine class -//Mesh class +//TODO: Tasks: +//Engine loop +//Proper rendering setup +//Flesh out the material system //Object //Abstract UI //Textures -//Proper Asset loading -//Rework buffers package -//Interleaved or packed buffers (xyzxyzxyz OR xxxyyyzzz) //Audio +//Low Priority: +// Proper Asset loading +// Rework buffers package +// Interleaved or packed buffers (xyzxyzxyz OR xxxyyyzzz) + type ImguiInfo struct { imCtx *imgui.Context @@ -42,11 +45,11 @@ var ( winHeight int32 = 720 isRunning bool = true - window *sdl.Window + window *engine.Window - simpleShader shaders.ShaderProgram - imShader shaders.ShaderProgram - bo *buffers.BufferObject + simpleMat *materials.Material + imguiMat *materials.Material + cubeMesh *meshes.Mesh modelMat = gglm.NewTrMatId() projMat = &gglm.Mat4{} @@ -61,44 +64,42 @@ func main() { runtime.LockOSThread() - err := initSDL() + //Init engine + err := engine.Init() if err != nil { - logging.ErrLog.Fatalln("Failed to init SDL. Err:", err) + logging.ErrLog.Fatalln("Failed to init nMage. Err:", err) } - window, err = sdl.CreateWindow("Go SDL Engine", sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, winWidth, winHeight, sdl.WINDOW_OPENGL|sdl.WINDOW_RESIZABLE) + //Create window + window, err = engine.CreateOpenGLWindowCentered("nMage", winWidth, winHeight, engine.WindowFlags_RESIZABLE) if err != nil { logging.ErrLog.Fatalln("Failed to create window. Err: ", err) } defer window.Destroy() - glCtx, err := window.GLCreateContext() - if err != nil { - logging.ErrLog.Fatalln("Failed to create OpenGL context. Err: ", err) - } - defer sdl.GLDeleteContext(glCtx) + engine.SetVSync(false) - err = initOpenGL() + //Create materials + simpleMat = materials.NewMaterial("Simple Mat", "./res/shaders/simple") + imguiMat = materials.NewMaterial("ImGUI Mat", "./res/shaders/imgui") + + //Load meshes + cubeMesh, err = meshes.NewMesh("Cube", "./res/models/color-cube.fbx", asig.PostProcess(0)) if err != nil { - logging.ErrLog.Fatalln(err) + logging.ErrLog.Fatalln("Failed to load cube mesh. Err: ", err) } - //Set vsync - sdl.GLSetSwapInterval(0) - - loadShaders() - loadBuffers() initImGUI() //Enable vertex attributes - simpleShader.SetAttribute("vertPosIn", bo, bo.VertPosBuf) - simpleShader.EnableAttribute("vertPosIn") + simpleMat.SetAttribute("vertPosIn", cubeMesh.BufObj, cubeMesh.BufObj.VertPosBuf) + simpleMat.EnableAttribute("vertPosIn") - simpleShader.SetAttribute("vertColorIn", bo, bo.ColorBuf) - simpleShader.EnableAttribute("vertColorIn") + simpleMat.SetAttribute("vertColorIn", cubeMesh.BufObj, cubeMesh.BufObj.ColorBuf) + simpleMat.EnableAttribute("vertColorIn") - simpleShader.SetAttribute("vertNormalIn", bo, bo.NormalBuf) - simpleShader.EnableAttribute("vertNormalIn") + simpleMat.SetAttribute("vertNormalIn", cubeMesh.BufObj, cubeMesh.BufObj.NormalBuf) + simpleMat.EnableAttribute("vertNormalIn") //Movement, scale and rotation translationMat := gglm.NewTranslationMat(gglm.NewVec3(0, 0, 0)) @@ -106,21 +107,20 @@ func main() { rotMat := gglm.NewRotMat(gglm.NewQuatEuler(gglm.NewVec3(0, 0, 0).AsRad())) modelMat.Mul(translationMat.Mul(rotMat.Mul(scaleMat))) - simpleShader.SetUnifMat4("modelMat", &modelMat.Mat4) + simpleMat.SetUnifMat4("modelMat", &modelMat.Mat4) //Moves objects into the cameras view updateViewMat() //Perspective/Depth projMat := gglm.Perspective(45*gglm.Deg2Rad, float32(winWidth)/float32(winHeight), 0.1, 500) - simpleShader.SetUnifMat4("projMat", projMat) + simpleMat.SetUnifMat4("projMat", projMat) //Lights - simpleShader.SetUnifVec3("lightPos1", &lightPos1) - simpleShader.SetUnifVec3("lightColor1", &lightColor1) + simpleMat.SetUnifVec3("lightPos1", &lightPos1) + simpleMat.SetUnifVec3("lightColor1", &lightColor1) //Game loop - timing.Init() for isRunning { timing.FrameStarted() @@ -132,154 +132,14 @@ func main() { timing.FrameEnded() - window.SetTitle(fmt.Sprintf("FPS: %.0f; Elapsed: %v", 1/timing.DT(), timing.ElapsedTime())) + window.SDLWin.SetTitle(fmt.Sprintf("FPS: %.0f; Elapsed: %v", 1/timing.DT(), timing.ElapsedTime())) } } func updateViewMat() { targetPos := camPos.Clone().Add(camForward) viewMat := gglm.LookAt(camPos, targetPos, gglm.NewVec3(0, 1, 0)) - simpleShader.SetUnifMat4("viewMat", &viewMat.Mat4) -} - -func initSDL() error { - - err := sdl.Init(sdl.INIT_EVERYTHING) - if err != nil { - return err - } - - sdl.ShowCursor(1) - - sdl.GLSetAttribute(sdl.MAJOR_VERSION, 4) - sdl.GLSetAttribute(sdl.MINOR_VERSION, 1) - - // R(0-255) G(0-255) B(0-255) - sdl.GLSetAttribute(sdl.GL_RED_SIZE, 8) - sdl.GLSetAttribute(sdl.GL_GREEN_SIZE, 8) - sdl.GLSetAttribute(sdl.GL_BLUE_SIZE, 8) - - sdl.GLSetAttribute(sdl.GL_DOUBLEBUFFER, 1) - sdl.GLSetAttribute(sdl.GL_DEPTH_SIZE, 24) - sdl.GLSetAttribute(sdl.GL_STENCIL_SIZE, 8) - - sdl.GLSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE) - - return nil -} - -func initOpenGL() error { - - if err := gl.Init(); err != nil { - return err - } - - gl.Enable(gl.DEPTH_TEST) - - gl.Enable(gl.CULL_FACE) - gl.CullFace(gl.BACK) - gl.FrontFace(gl.CCW) - - gl.ClearColor(0, 0, 0, 1) - return nil -} - -func loadShaders() { - - var err error - simpleShader, err = shaders.NewShaderProgram() - if err != nil { - logging.ErrLog.Fatalln("Failed to create new shader program. Err: ", err) - } - - vertShader, err := shaders.LoadAndCompilerShader("./res/shaders/simple.vert.glsl", shaders.VertexShaderType) - if err != nil { - logging.ErrLog.Fatalln("Failed to create new shader. Err: ", err) - } - - fragShader, err := shaders.LoadAndCompilerShader("./res/shaders/simple.frag.glsl", shaders.FragmentShaderType) - if err != nil { - logging.ErrLog.Fatalln("Failed to create new shader. Err: ", err) - } - - simpleShader.AttachShader(vertShader) - simpleShader.AttachShader(fragShader) - simpleShader.Link() - - //ImGUI shader - imShader, err = shaders.NewShaderProgram() - if err != nil { - logging.ErrLog.Fatalln("Failed to create new shader program. Err: ", err) - } - - imguiVertShader, err := shaders.LoadAndCompilerShader("./res/shaders/imgui.vert.glsl", shaders.VertexShaderType) - if err != nil { - logging.ErrLog.Fatalln("Failed to create new shader. Err: ", err) - } - - imguiFragShader, err := shaders.LoadAndCompilerShader("./res/shaders/imgui.frag.glsl", shaders.FragmentShaderType) - if err != nil { - logging.ErrLog.Fatalln("Failed to create new shader. Err: ", err) - } - - imShader.AttachShader(imguiVertShader) - imShader.AttachShader(imguiFragShader) - imShader.Link() -} - -func flattenVec3(vec3s []gglm.Vec3) []float32 { - - floats := make([]float32, len(vec3s)*3) - for i := 0; i < len(vec3s); i++ { - floats[i*3+0] = vec3s[i].X() - floats[i*3+1] = vec3s[i].Y() - floats[i*3+2] = vec3s[i].Z() - } - - return floats -} - -func flattenVec4(vec4s []gglm.Vec4) []float32 { - - floats := make([]float32, len(vec4s)*4) - for i := 0; i < len(vec4s); i++ { - floats[i*4+0] = vec4s[i].X() - floats[i*4+1] = vec4s[i].Y() - floats[i*4+2] = vec4s[i].Z() - floats[i*4+3] = vec4s[i].W() - } - - return floats -} - -func flattenFaces(faces []asig.Face) []uint32 { - - asserts.True(len(faces[0].Indices) == 3, fmt.Sprintf("Face doesn't have 3 indices. Index count: %v\n", len(faces[0].Indices))) - - uints := make([]uint32, len(faces)*3) - for i := 0; i < len(faces); i++ { - uints[i*3+0] = uint32(faces[i].Indices[0]) - uints[i*3+1] = uint32(faces[i].Indices[1]) - uints[i*3+2] = uint32(faces[i].Indices[2]) - } - - return uints -} - -func loadBuffers() { - - // scene, release, err := asig.ImportFile("./res/models/weird-cube.fbx", asig.PostProcessTriangulate) - scene, release, err := asig.ImportFile("./res/models/color-cube.fbx", asig.PostProcessTriangulate) - if err != nil { - logging.ErrLog.Panicln("Failed to load model. Err: " + err.Error()) - } - release() - - bo = buffers.NewBufferObject() - bo.GenBuffer(flattenVec3(scene.Meshes[0].Vertices), buffers.BufUsageStatic, buffers.BufTypeVertPos, buffers.DataTypeVec3) - bo.GenBuffer(flattenVec3(scene.Meshes[0].Normals), buffers.BufUsageStatic, buffers.BufTypeNormal, buffers.DataTypeVec3) - bo.GenBuffer(flattenVec4(scene.Meshes[0].ColorSets[0]), buffers.BufUsageStatic, buffers.BufTypeColor, buffers.DataTypeVec4) - bo.GenBufferUint32(flattenFaces(scene.Meshes[0].Faces), buffers.BufUsageStatic, buffers.BufTypeIndex, buffers.DataTypeUint32) + simpleMat.SetUnifMat4("viewMat", &viewMat.Mat4) } func initImGUI() { @@ -309,11 +169,11 @@ func initImGUI() { imIO.Fonts().SetTextureID(imgui.TextureID(imguiInfo.texID)) //Shader attributes - imShader.Activate() - imShader.EnableAttribute("Position") - imShader.EnableAttribute("UV") - imShader.EnableAttribute("Color") - imShader.Deactivate() + imguiMat.Bind() + imguiMat.EnableAttribute("Position") + imguiMat.EnableAttribute("UV") + imguiMat.EnableAttribute("Color") + imguiMat.UnBind() //Init imgui input mapping keys := map[int]int{ @@ -380,26 +240,12 @@ func handleInputs() { case *sdl.MouseMotionEvent: input.HandleMouseMotionEvent(e) - case *sdl.WindowEvent: - - //NOTE: SDL is not firing window resize, but is resizing the window by itself - // if e.Type != sdl.WINDOWEVENT_SIZE_CHANGED { - // continue - // } - - // winWidth = e.Data1 - // winHeight = e.Data2 - // window.SetSize(int32(winWidth), int32(winHeight)) - - // projMat = gglm.Perspective(45*gglm.Deg2Rad, float32(winWidth)/float32(winHeight), 0.1, 20) - // simpleShader.SetUnifMat4("projMat", projMat) - case *sdl.QuitEvent: isRunning = false } } - currWinWidth, currWinHeight := window.GetSize() + currWinWidth, currWinHeight := window.SDLWin.GetSize() if winWidth != currWinWidth || winHeight != currWinHeight { handleWindowResize(currWinWidth, currWinHeight) } @@ -422,14 +268,14 @@ func handleWindowResize(newWinWidth, newWinHeight int32) { winWidth = newWinWidth winHeight = newWinHeight - fbWidth, fbHeight := window.GLGetDrawableSize() + fbWidth, fbHeight := window.SDLWin.GLGetDrawableSize() if fbWidth <= 0 || fbHeight <= 0 { return } gl.Viewport(0, 0, fbWidth, fbHeight) projMat = gglm.Perspective(45*gglm.Deg2Rad, float32(winWidth)/float32(winHeight), 0.1, 20) - simpleShader.SetUnifMat4("projMat", projMat) + simpleMat.SetUnifMat4("projMat", projMat) } var time uint64 = 0 @@ -443,7 +289,7 @@ var lightColor1 gglm.Vec3 = *gglm.NewVec3(1, 1, 1) func runGameLogic() { - var camSpeed float32 = 15.0 + var camSpeed float32 = 15 if input.KeyDown(sdl.K_w) { camPos.Data[1] += camSpeed * timing.DT() updateViewMat() @@ -470,7 +316,7 @@ func runGameLogic() { } modelMat.Rotate(10*timing.DT()*gglm.Deg2Rad, gglm.NewVec3(1, 1, 1).Normalize()) - simpleShader.SetUnifMat4("modelMat", &modelMat.Mat4) + simpleMat.SetUnifMat4("modelMat", &modelMat.Mat4) //ImGUI imIO := imgui.CurrentIO() @@ -489,19 +335,19 @@ func runGameLogic() { imgui.NewFrame() if imgui.SliderFloat3("Ambient Color", &ambientColor.Data, 0, 1) { - simpleShader.SetUnifVec3("ambientLightColor", &ambientColor) + simpleMat.SetUnifVec3("ambientLightColor", &ambientColor) } if imgui.SliderFloat("Ambient Color Strength", &ambientColorStrength, 0, 1) { - simpleShader.SetUnifFloat32("ambientStrength", ambientColorStrength) + simpleMat.SetUnifFloat32("ambientStrength", ambientColorStrength) } if imgui.SliderFloat3("Light Pos 1", &lightPos1.Data, -10, 10) { - simpleShader.SetUnifVec3("lightPos1", &lightPos1) + simpleMat.SetUnifVec3("lightPos1", &lightPos1) } if imgui.SliderFloat3("Light Color 1", &lightColor1.Data, 0, 1) { - simpleShader.SetUnifVec3("lightColor1", &lightColor1) + simpleMat.SetUnifVec3("lightColor1", &lightColor1) } imgui.Render() @@ -509,38 +355,37 @@ func runGameLogic() { func draw() { - gl.Disable(gl.SCISSOR_TEST) - gl.Enable(gl.CULL_FACE) - gl.Enable(gl.DEPTH_TEST) - gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + simpleMat.Bind() - simpleShader.Activate() - - //DRAW - bo.Activate() + cubeMesh.BufObj.Bind() tempModelMat := modelMat.Clone() rowSize := 10 for y := 0; y < rowSize; y++ { for x := 0; x < rowSize; x++ { - simpleShader.SetUnifMat4("modelMat", &tempModelMat.Translate(gglm.NewVec3(-1, 0, 0)).Mat4) - gl.DrawElements(gl.TRIANGLES, int32(bo.IndexBuf.DataLen), gl.UNSIGNED_INT, gl.PtrOffset(0)) + simpleMat.SetUnifMat4("modelMat", &tempModelMat.Translate(gglm.NewVec3(-1, 0, 0)).Mat4) + gl.DrawElements(gl.TRIANGLES, int32(cubeMesh.BufObj.IndexBuf.DataLen), gl.UNSIGNED_INT, gl.PtrOffset(0)) } - simpleShader.SetUnifMat4("modelMat", &tempModelMat.Translate(gglm.NewVec3(float32(rowSize), -1, 0)).Mat4) + simpleMat.SetUnifMat4("modelMat", &tempModelMat.Translate(gglm.NewVec3(float32(rowSize), -1, 0)).Mat4) } - simpleShader.SetUnifMat4("modelMat", &modelMat.Mat4) - bo.Deactivate() + simpleMat.SetUnifMat4("modelMat", &modelMat.Mat4) + cubeMesh.BufObj.UnBind() drawUI() + window.SDLWin.GLSwap() - window.GLSwap() + //Reset imgui changes before next draw + gl.Disable(gl.SCISSOR_TEST) + gl.Enable(gl.CULL_FACE) + gl.Enable(gl.DEPTH_TEST) + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) } func drawUI() { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - fbWidth, fbHeight := window.GLGetDrawableSize() + fbWidth, fbHeight := window.SDLWin.GLGetDrawableSize() if fbWidth <= 0 || fbHeight <= 0 { return } @@ -564,13 +409,13 @@ func drawUI() { // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). // DisplayMin is typically (0,0) for single viewport apps. - imShader.Activate() + imguiMat.Bind() - gl.Uniform1i(gl.GetUniformLocation(imShader.ID, gl.Str("Texture\x00")), 0) + gl.Uniform1i(gl.GetUniformLocation(imguiMat.ShaderProg.ID, gl.Str("Texture\x00")), 0) //PERF: only update the ortho matrix on window resize orthoMat := gglm.Ortho(0, float32(winWidth), 0, float32(winHeight), 0, 20) - imShader.SetUnifMat4("ProjMtx", &orthoMat.Mat4) + imguiMat.SetUnifMat4("ProjMtx", &orthoMat.Mat4) gl.BindSampler(0, 0) // Rely on combined texture/sampler state. // Recreate the VAO every time @@ -580,12 +425,12 @@ func drawUI() { gl.BindBuffer(gl.ARRAY_BUFFER, imguiInfo.vboID) vertexSize, vertexOffsetPos, vertexOffsetUv, vertexOffsetCol := imgui.VertexBufferLayout() - imShader.EnableAttribute("Position") - imShader.EnableAttribute("UV") - imShader.EnableAttribute("Color") - gl.VertexAttribPointerWithOffset(uint32(imShader.GetAttribLoc("Position")), 2, gl.FLOAT, false, int32(vertexSize), uintptr(vertexOffsetPos)) - gl.VertexAttribPointerWithOffset(uint32(imShader.GetAttribLoc("UV")), 2, gl.FLOAT, false, int32(vertexSize), uintptr(vertexOffsetUv)) - gl.VertexAttribPointerWithOffset(uint32(imShader.GetAttribLoc("Color")), 4, gl.UNSIGNED_BYTE, true, int32(vertexSize), uintptr(vertexOffsetCol)) + imguiMat.EnableAttribute("Position") + imguiMat.EnableAttribute("UV") + imguiMat.EnableAttribute("Color") + gl.VertexAttribPointerWithOffset(uint32(imguiMat.GetAttribLoc("Position")), 2, gl.FLOAT, false, int32(vertexSize), uintptr(vertexOffsetPos)) + gl.VertexAttribPointerWithOffset(uint32(imguiMat.GetAttribLoc("UV")), 2, gl.FLOAT, false, int32(vertexSize), uintptr(vertexOffsetUv)) + gl.VertexAttribPointerWithOffset(uint32(imguiMat.GetAttribLoc("Color")), 4, gl.UNSIGNED_BYTE, true, int32(vertexSize), uintptr(vertexOffsetCol)) indexSize := imgui.IndexBufferLayout() drawType := gl.UNSIGNED_SHORT diff --git a/materials/material.go b/materials/material.go new file mode 100755 index 0000000..cb955a7 --- /dev/null +++ b/materials/material.go @@ -0,0 +1,109 @@ +package materials + +import ( + "github.com/bloeys/gglm/gglm" + "github.com/bloeys/nmage/buffers" + "github.com/bloeys/nmage/logging" + "github.com/bloeys/nmage/shaders" + "github.com/go-gl/gl/v4.1-core/gl" +) + +type Material struct { + Name string + ShaderProg shaders.ShaderProgram +} + +func (m *Material) Bind() { + gl.UseProgram(m.ShaderProg.ID) +} + +func (m *Material) UnBind() { + gl.UseProgram(0) +} + +func (m *Material) GetAttribLoc(attribName string) int32 { + return gl.GetAttribLocation(m.ShaderProg.ID, gl.Str(attribName+"\x00")) +} + +func (m *Material) SetAttribute(attribName string, bufObj *buffers.BufferObject, buf *buffers.Buffer) { + + bufObj.Bind() + buf.Activate() + + attribLoc := m.GetAttribLoc(attribName) + gl.VertexAttribPointer(uint32(attribLoc), buf.ElementCount, buf.ElementType, false, buf.GetSize(), gl.PtrOffset(0)) + + bufObj.Bind() + buf.Deactivate() +} + +func (m *Material) EnableAttribute(attribName string) { + gl.EnableVertexAttribArray(uint32(m.GetAttribLoc(attribName))) +} + +func (m *Material) DisableAttribute(attribName string) { + gl.DisableVertexAttribArray(uint32(m.GetAttribLoc(attribName))) +} + +func (m *Material) SetUnifFloat32(uniformName string, val float32) { + loc := gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00")) + gl.ProgramUniform1f(m.ShaderProg.ID, loc, val) +} + +func (m *Material) SetUnifVec2(uniformName string, vec2 *gglm.Vec2) { + loc := gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00")) + gl.ProgramUniform2fv(m.ShaderProg.ID, loc, 1, &vec2.Data[0]) +} + +func (m *Material) SetUnifVec3(uniformName string, vec3 *gglm.Vec3) { + loc := gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00")) + gl.ProgramUniform3fv(m.ShaderProg.ID, loc, 1, &vec3.Data[0]) +} + +func (m *Material) SetUnifVec4(uniformName string, vec4 *gglm.Vec4) { + loc := gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00")) + gl.ProgramUniform4fv(m.ShaderProg.ID, loc, 1, &vec4.Data[0]) +} + +func (m *Material) SetUnifMat2(uniformName string, mat2 *gglm.Mat2) { + loc := gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00")) + gl.ProgramUniformMatrix2fv(m.ShaderProg.ID, loc, 1, false, &mat2.Data[0][0]) +} + +func (m *Material) SetUnifMat3(uniformName string, mat3 *gglm.Mat3) { + loc := gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00")) + gl.ProgramUniformMatrix3fv(m.ShaderProg.ID, loc, 1, false, &mat3.Data[0][0]) +} + +func (m *Material) SetUnifMat4(uniformName string, mat4 *gglm.Mat4) { + loc := gl.GetUniformLocation(m.ShaderProg.ID, gl.Str(uniformName+"\x00")) + gl.ProgramUniformMatrix4fv(m.ShaderProg.ID, loc, 1, false, &mat4.Data[0][0]) +} + +func (m *Material) Delete() { + gl.DeleteProgram(m.ShaderProg.ID) +} + +func NewMaterial(matName, shaderPath string) *Material { + + shdrProg, err := shaders.NewShaderProgram() + if err != nil { + logging.ErrLog.Fatalln("Failed to create new shader program. Err: ", err) + } + + vertShader, err := shaders.LoadAndCompilerShader(shaderPath+".vert.glsl", shaders.VertexShaderType) + if err != nil { + logging.ErrLog.Fatalln("Failed to load and create vertex shader. Err: ", err) + } + + fragShader, err := shaders.LoadAndCompilerShader(shaderPath+".frag.glsl", shaders.FragmentShaderType) + if err != nil { + logging.ErrLog.Fatalln("Failed to load and create fragment shader. Err: ", err) + } + + shdrProg.AttachShader(vertShader) + shdrProg.AttachShader(fragShader) + shdrProg.Link() + + return &Material{Name: matName, ShaderProg: shdrProg} +} diff --git a/meshes/mesh.go b/meshes/mesh.go new file mode 100755 index 0000000..f8fdc01 --- /dev/null +++ b/meshes/mesh.go @@ -0,0 +1,81 @@ +package meshes + +import ( + "errors" + "fmt" + + "github.com/bloeys/assimp-go/asig" + "github.com/bloeys/gglm/gglm" + "github.com/bloeys/nmage/asserts" + "github.com/bloeys/nmage/buffers" +) + +type Mesh struct { + Name string + BufObj *buffers.BufferObject +} + +func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (*Mesh, error) { + + scene, release, err := asig.ImportFile(modelPath, asig.PostProcessTriangulate|postProcessFlags) + if err != nil { + return nil, errors.New("Failed to load model. Err: " + err.Error()) + } + defer release() + + if len(scene.Meshes) == 0 { + return nil, errors.New("No meshes found in file: " + modelPath) + } + + mesh := &Mesh{Name: name, BufObj: buffers.NewBufferObject()} + + sceneMesh := scene.Meshes[0] + mesh.BufObj.GenBuffer(flattenVec3(sceneMesh.Normals), buffers.BufUsageStatic, buffers.BufTypeNormal, buffers.DataTypeVec3) + mesh.BufObj.GenBuffer(flattenVec3(sceneMesh.Vertices), buffers.BufUsageStatic, buffers.BufTypeVertPos, buffers.DataTypeVec3) + mesh.BufObj.GenBufferUint32(flattenFaces(sceneMesh.Faces), buffers.BufUsageStatic, buffers.BufTypeIndex, buffers.DataTypeUint32) + + if len(sceneMesh.ColorSets) > 0 { + mesh.BufObj.GenBuffer(flattenVec4(sceneMesh.ColorSets[0]), buffers.BufUsageStatic, buffers.BufTypeColor, buffers.DataTypeVec4) + } + + return mesh, nil +} + +func flattenVec3(vec3s []gglm.Vec3) []float32 { + + floats := make([]float32, len(vec3s)*3) + for i := 0; i < len(vec3s); i++ { + floats[i*3+0] = vec3s[i].X() + floats[i*3+1] = vec3s[i].Y() + floats[i*3+2] = vec3s[i].Z() + } + + return floats +} + +func flattenVec4(vec4s []gglm.Vec4) []float32 { + + floats := make([]float32, len(vec4s)*4) + for i := 0; i < len(vec4s); i++ { + floats[i*4+0] = vec4s[i].X() + floats[i*4+1] = vec4s[i].Y() + floats[i*4+2] = vec4s[i].Z() + floats[i*4+3] = vec4s[i].W() + } + + return floats +} + +func flattenFaces(faces []asig.Face) []uint32 { + + asserts.True(len(faces[0].Indices) == 3, fmt.Sprintf("Face doesn't have 3 indices. Index count: %v\n", len(faces[0].Indices))) + + uints := make([]uint32, len(faces)*3) + for i := 0; i < len(faces); i++ { + uints[i*3+0] = uint32(faces[i].Indices[0]) + uints[i*3+1] = uint32(faces[i].Indices[1]) + uints[i*3+2] = uint32(faces[i].Indices[2]) + } + + return uints +} diff --git a/shaders/shader_program.go b/shaders/shader_program.go index 414bc4b..cea6fbb 100755 --- a/shaders/shader_program.go +++ b/shaders/shader_program.go @@ -1,8 +1,6 @@ package shaders import ( - "github.com/bloeys/gglm/gglm" - "github.com/bloeys/nmage/buffers" "github.com/bloeys/nmage/logging" "github.com/go-gl/gl/v4.1-core/gl" ) @@ -37,74 +35,3 @@ func (sp *ShaderProgram) Link() { gl.DeleteShader(sp.FragShaderID) } } - -func (sp *ShaderProgram) Activate() { - gl.UseProgram(sp.ID) -} - -func (sp *ShaderProgram) Deactivate() { - gl.UseProgram(0) -} - -func (sp *ShaderProgram) GetAttribLoc(attribName string) int32 { - return gl.GetAttribLocation(sp.ID, gl.Str(attribName+"\x00")) -} - -func (sp *ShaderProgram) SetAttribute(attribName string, bufObj *buffers.BufferObject, buf *buffers.Buffer) { - - bufObj.Activate() - buf.Activate() - - attribLoc := sp.GetAttribLoc(attribName) - gl.VertexAttribPointer(uint32(attribLoc), buf.ElementCount, buf.ElementType, false, buf.GetSize(), gl.PtrOffset(0)) - - bufObj.Activate() - buf.Deactivate() -} - -func (sp *ShaderProgram) EnableAttribute(attribName string) { - gl.EnableVertexAttribArray(uint32(sp.GetAttribLoc(attribName))) -} - -func (sp *ShaderProgram) DisableAttribute(attribName string) { - gl.DisableVertexAttribArray(uint32(sp.GetAttribLoc(attribName))) -} - -func (sp *ShaderProgram) SetUnifFloat32(uniformName string, val float32) { - loc := gl.GetUniformLocation(sp.ID, gl.Str(uniformName+"\x00")) - gl.ProgramUniform1f(sp.ID, loc, val) -} - -func (sp *ShaderProgram) SetUnifVec2(uniformName string, vec2 *gglm.Vec2) { - loc := gl.GetUniformLocation(sp.ID, gl.Str(uniformName+"\x00")) - gl.ProgramUniform2fv(sp.ID, loc, 1, &vec2.Data[0]) -} - -func (sp *ShaderProgram) SetUnifVec3(uniformName string, vec3 *gglm.Vec3) { - loc := gl.GetUniformLocation(sp.ID, gl.Str(uniformName+"\x00")) - gl.ProgramUniform3fv(sp.ID, loc, 1, &vec3.Data[0]) -} - -func (sp *ShaderProgram) SetUnifVec4(uniformName string, vec4 *gglm.Vec4) { - loc := gl.GetUniformLocation(sp.ID, gl.Str(uniformName+"\x00")) - gl.ProgramUniform4fv(sp.ID, loc, 1, &vec4.Data[0]) -} - -func (sp *ShaderProgram) SetUnifMat2(uniformName string, mat2 *gglm.Mat2) { - loc := gl.GetUniformLocation(sp.ID, gl.Str(uniformName+"\x00")) - gl.ProgramUniformMatrix2fv(sp.ID, loc, 1, false, &mat2.Data[0][0]) -} - -func (sp *ShaderProgram) SetUnifMat3(uniformName string, mat3 *gglm.Mat3) { - loc := gl.GetUniformLocation(sp.ID, gl.Str(uniformName+"\x00")) - gl.ProgramUniformMatrix3fv(sp.ID, loc, 1, false, &mat3.Data[0][0]) -} - -func (sp *ShaderProgram) SetUnifMat4(uniformName string, mat4 *gglm.Mat4) { - loc := gl.GetUniformLocation(sp.ID, gl.Str(uniformName+"\x00")) - gl.ProgramUniformMatrix4fv(sp.ID, loc, 1, false, &mat4.Data[0][0]) -} - -func (sp *ShaderProgram) Delete() { - gl.DeleteProgram(sp.ID) -}