Day 15: Basic renderer+improve material system+lockosthread on init

This commit is contained in:
bloeys
2022-02-26 22:07:59 +04:00
parent 660c41bc06
commit 709dc062cc
8 changed files with 124 additions and 69 deletions

View File

@ -1,7 +1,10 @@
package engine
import (
"runtime"
"github.com/bloeys/nmage/input"
"github.com/bloeys/nmage/renderer"
"github.com/bloeys/nmage/timing"
"github.com/go-gl/gl/v4.1-core/gl"
"github.com/inkyblackness/imgui-go/v4"
@ -12,6 +15,7 @@ type Window struct {
SDLWin *sdl.Window
GlCtx sdl.GLContext
EventCallbacks []func(sdl.Event)
Rend renderer.Render
}
func (w *Window) handleInputs() {
@ -92,6 +96,7 @@ func (w *Window) Destroy() error {
func Init() error {
runtime.LockOSThread()
timing.Init()
err := initSDL()
@ -124,15 +129,15 @@ func initSDL() error {
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 CreateOpenGLWindow(title string, x, y, width, height int32, flags WindowFlags, rend renderer.Render) (*Window, error) {
return createWindow(title, x, y, width, height, WindowFlags_OPENGL|flags, rend)
}
func CreateOpenGLWindowCentered(title string, width, height int32, flags WindowFlags) (*Window, error) {
return createWindow(title, -1, -1, width, height, WindowFlags_OPENGL|flags)
func CreateOpenGLWindowCentered(title string, width, height int32, flags WindowFlags, rend renderer.Render) (*Window, error) {
return createWindow(title, -1, -1, width, height, WindowFlags_OPENGL|flags, rend)
}
func createWindow(title string, x, y, width, height int32, flags WindowFlags) (*Window, error) {
func createWindow(title string, x, y, width, height int32, flags WindowFlags, rend renderer.Render) (*Window, error) {
if x == -1 && y == -1 {
x = sdl.WINDOWPOS_CENTERED
@ -143,7 +148,11 @@ func createWindow(title string, x, y, width, height int32, flags WindowFlags) (*
if err != nil {
return nil, err
}
win := &Window{SDLWin: sdlWin, EventCallbacks: make([]func(sdl.Event), 0)}
win := &Window{
SDLWin: sdlWin,
EventCallbacks: make([]func(sdl.Event), 0),
Rend: rend,
}
win.GlCtx, err = sdlWin.GLCreateContext()
if err != nil {

View File

@ -46,6 +46,7 @@ func Run(g Game) {
w.SDLWin.GLSwap()
g.FrameEnd()
w.Rend.FrameEnd()
timing.FrameEnded()
}

55
main.go
View File

@ -2,7 +2,6 @@ package main
import (
"fmt"
"runtime"
"github.com/bloeys/assimp-go/asig"
"github.com/bloeys/gglm/gglm"
@ -12,24 +11,28 @@ import (
"github.com/bloeys/nmage/logging"
"github.com/bloeys/nmage/materials"
"github.com/bloeys/nmage/meshes"
"github.com/bloeys/nmage/renderer/rend3dgl"
"github.com/bloeys/nmage/timing"
nmageimgui "github.com/bloeys/nmage/ui/imgui"
"github.com/go-gl/gl/v4.1-core/gl"
"github.com/inkyblackness/imgui-go/v4"
"github.com/veandco/go-sdl2/sdl"
)
//TODO: Tasks:
//Proper rendering setup
// Build simple game
// Integrate physx
// Entities and components
// Camera class
//Audio
//Flesh out the material system
//Low Priority:
// Renderer batching
// Scene graph
// Separate engine loop from rendering loop? or leave it to the user?
// Abstract keys enum away from sdl
// Abstract UI
// Proper Asset loading
// Audio
// Frustum culling
// Material system editor with fields automatically extracted from the shader
var (
isRunning bool = true
@ -70,14 +73,9 @@ func (g *OurGame) Init() {
if err != nil {
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
}
cubeMesh.AddTexture(tex)
//Set mesh textures on material
for _, v := range cubeMesh.TextureIDs {
simpleMat.AddTextureID(v)
}
//Enable vertex attributes
//Configure material
simpleMat.DiffuseTex = tex.TexID
simpleMat.SetAttribute(cubeMesh.Buf)
//Movement, scale and rotation
@ -149,42 +147,23 @@ func (g *OurGame) Update() {
imgui.DragFloat3("Cam Pos", &camPos.Data)
}
var dtAccum float32 = 0
var lastElapsedTime uint64 = 0
var framesSinceLastFPSUpdate uint = 0
func (g *OurGame) Render() {
simpleMat.Bind()
cubeMesh.Buf.Bind()
tempModelMat := modelMat.Clone()
rowSize := 100
for y := 0; y < rowSize; y++ {
for x := 0; x < rowSize; x++ {
simpleMat.SetUnifMat4("modelMat", &tempModelMat.Translate(gglm.NewVec3(-1, 0, 0)).Mat4)
gl.DrawElements(gl.TRIANGLES, cubeMesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0))
tempModelMat.Translate(gglm.NewVec3(-1, 0, 0))
window.Rend.Draw(cubeMesh, tempModelMat, simpleMat)
}
simpleMat.SetUnifMat4("modelMat", &tempModelMat.Translate(gglm.NewVec3(float32(rowSize), -1, 0)).Mat4)
}
simpleMat.SetUnifMat4("modelMat", &modelMat.Mat4)
dtAccum += timing.DT()
framesSinceLastFPSUpdate++
if timing.ElapsedTime() > lastElapsedTime {
avgDT := dtAccum / float32(framesSinceLastFPSUpdate)
g.GetWindow().SDLWin.SetTitle(fmt.Sprint("nMage (", 1/avgDT, " fps)"))
dtAccum = 0
framesSinceLastFPSUpdate = 0
tempModelMat.Translate(gglm.NewVec3(float32(rowSize), -1, 0))
}
lastElapsedTime = timing.ElapsedTime()
g.GetWindow().SDLWin.SetTitle(fmt.Sprint("nMage (", timing.GetAvgFPS(), " fps)"))
}
func (g *OurGame) FrameEnd() {
}
func (g *OurGame) ShouldRun() bool {
@ -205,8 +184,6 @@ func (g *OurGame) Deinit() {
func main() {
runtime.LockOSThread()
//Init engine
err := engine.Init()
if err != nil {
@ -214,7 +191,7 @@ func main() {
}
//Create window
window, err = engine.CreateOpenGLWindowCentered("nMage", 1280, 720, engine.WindowFlags_RESIZABLE)
window, err = engine.CreateOpenGLWindowCentered("nMage", 1280, 720, engine.WindowFlags_RESIZABLE, rend3dgl.NewRend3DGL())
if err != nil {
logging.ErrLog.Fatalln("Failed to create window. Err: ", err)
}

View File

@ -12,7 +12,8 @@ import (
type Material struct {
Name string
ShaderProg shaders.ShaderProgram
TexIDs []uint32
DiffuseTex uint32
UnifLocs map[string]int32
AttribLocs map[string]int32
@ -21,19 +22,17 @@ type Material struct {
func (m *Material) Bind() {
gl.UseProgram(m.ShaderProg.ID)
for i, v := range m.TexIDs {
gl.ActiveTexture(gl.TEXTURE0 + uint32(i))
gl.BindTexture(gl.TEXTURE_2D, v)
}
gl.ActiveTexture(gl.TEXTURE0)
gl.BindTexture(gl.TEXTURE_2D, m.DiffuseTex)
}
func (m *Material) UnBind() {
gl.UseProgram(0)
for i := range m.TexIDs {
gl.ActiveTexture(gl.TEXTURE0 + uint32(i))
gl.BindTexture(gl.TEXTURE_2D, 0)
}
//TODO: Should we unbind textures here? Are these two lines needed?
// gl.ActiveTexture(gl.TEXTURE0)
// gl.BindTexture(gl.TEXTURE_2D, 0)
}
func (m *Material) GetAttribLoc(attribName string) int32 {
@ -79,10 +78,6 @@ func (m *Material) SetAttribute(bufObj buffers.Buffer) {
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
}
func (m *Material) AddTextureID(texID uint32) {
m.TexIDs = append(m.TexIDs, texID)
}
func (m *Material) EnableAttribute(attribName string) {
gl.EnableVertexAttribArray(uint32(m.GetAttribLoc(attribName)))
}

View File

@ -7,20 +7,14 @@ import (
"github.com/bloeys/assimp-go/asig"
"github.com/bloeys/gglm/gglm"
"github.com/bloeys/nmage/asserts"
"github.com/bloeys/nmage/assets"
"github.com/bloeys/nmage/buffers"
)
type Mesh struct {
Name string
TextureIDs []uint32
Buf buffers.Buffer
}
func (m *Mesh) AddTexture(tex assets.Texture) {
m.TextureIDs = append(m.TextureIDs, tex.TexID)
}
func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (*Mesh, error) {
scene, release, err := asig.ImportFile(modelPath, asig.PostProcessTriangulate|postProcessFlags)

41
renderer/rend3dgl/rend3dgl.go Executable file
View File

@ -0,0 +1,41 @@
package rend3dgl
import (
"github.com/bloeys/gglm/gglm"
"github.com/bloeys/nmage/materials"
"github.com/bloeys/nmage/meshes"
"github.com/bloeys/nmage/renderer"
"github.com/go-gl/gl/v4.1-core/gl"
)
var _ renderer.Render = &Rend3DGL{}
type Rend3DGL struct {
BoundMesh *meshes.Mesh
BoundMat *materials.Material
}
func (r3d *Rend3DGL) Draw(mesh *meshes.Mesh, trMat *gglm.TrMat, mat *materials.Material) {
if mesh != r3d.BoundMesh {
mesh.Buf.Bind()
r3d.BoundMesh = mesh
}
if mat != r3d.BoundMat {
mat.Bind()
r3d.BoundMat = mat
}
mat.SetUnifMat4("modelMat", &trMat.Mat4)
gl.DrawElements(gl.TRIANGLES, mesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0))
}
func (r3d *Rend3DGL) FrameEnd() {
r3d.BoundMesh = nil
r3d.BoundMat = nil
}
func NewRend3DGL() *Rend3DGL {
return &Rend3DGL{}
}

12
renderer/renderer.go Executable file
View File

@ -0,0 +1,12 @@
package renderer
import (
"github.com/bloeys/gglm/gglm"
"github.com/bloeys/nmage/materials"
"github.com/bloeys/nmage/meshes"
)
type Render interface {
Draw(mesh *meshes.Mesh, trMat *gglm.TrMat, mat *materials.Material)
FrameEnd()
}

View File

@ -8,6 +8,12 @@ var (
dt float32 = 0.01
frameStart time.Time
startTime time.Time
//fps calculator vars
dtAccum float32 = 1
lastElapsedTime uint64 = 0
framesSinceLastFPSUpdate uint = 0
avgFps float32 = 1
)
func Init() {
@ -15,11 +21,26 @@ func Init() {
}
func FrameStarted() {
frameStart = time.Now()
//fps stuff
dtAccum += dt
framesSinceLastFPSUpdate++
et := ElapsedTime()
if et > lastElapsedTime {
avgDT := dtAccum / float32(framesSinceLastFPSUpdate)
avgFps = 1 / avgDT
dtAccum = 0
framesSinceLastFPSUpdate = 0
}
lastElapsedTime = et
}
func FrameEnded() {
//Calculate new dt
dt = float32(time.Since(frameStart).Seconds())
if dt == 0 {
dt = float32(time.Microsecond)
@ -31,6 +52,11 @@ func DT() float32 {
return dt
}
//GetAvgFPS returns the fps averaged over 1 second
func GetAvgFPS() float32 {
return avgFps
}
//ElapsedTime is time since game start
func ElapsedTime() uint64 {
return uint64(time.Since(startTime).Seconds())