mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Day 15: Basic renderer+improve material system+lockosthread on init
This commit is contained in:
@ -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 {
|
||||
|
||||
@ -46,6 +46,7 @@ func Run(g Game) {
|
||||
w.SDLWin.GLSwap()
|
||||
|
||||
g.FrameEnd()
|
||||
w.Rend.FrameEnd()
|
||||
timing.FrameEnded()
|
||||
}
|
||||
|
||||
|
||||
59
main.go
59
main.go
@ -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
|
||||
//Entities and components
|
||||
//Camera class
|
||||
//Audio
|
||||
//Flesh out the material system
|
||||
// Build simple game
|
||||
// Integrate physx
|
||||
// Entities and components
|
||||
// Camera class
|
||||
|
||||
//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)
|
||||
}
|
||||
|
||||
@ -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)))
|
||||
}
|
||||
|
||||
@ -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
41
renderer/rend3dgl/rend3dgl.go
Executable 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
12
renderer/renderer.go
Executable 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()
|
||||
}
|
||||
@ -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())
|
||||
|
||||
Reference in New Issue
Block a user