Database is more usable now. All pages have been updated to use the database, and share an application configuration. Page Stack has been removed, no more pages hanging around in memory. Replaced with a 'Router' which uses an Enum to determine which page should be displayed, destroys the old page and initializes the new page all in one go. No more push, pop, rollback, etc. No more holding instances of pages. Logger has been updated with proper timestamps and sorting now works as expected."
187 lines
5.9 KiB
Go
187 lines
5.9 KiB
Go
// Package page provides the interface for pages
|
|
package page
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/go-gl/gl/v3.3-core/gl"
|
|
"github.com/go-gl/mathgl/mgl32"
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
"rhemawavetech.com/rhemawave/internal/shaderManager"
|
|
)
|
|
|
|
// Page defines the contract for all application screens.
|
|
type Page interface {
|
|
Init(ctx *PageCtx) error
|
|
HandleEvent(event *sdl.Event) error
|
|
Update(dt float32) error
|
|
Render() error
|
|
Destroy() error
|
|
}
|
|
|
|
// Base is a helper struct that pages can embed to get common functionality.
|
|
type Base struct {
|
|
Context *PageCtx
|
|
QuadVAO uint32
|
|
QuadVBO uint32
|
|
Projection mgl32.Mat4
|
|
ScreenWidth int32
|
|
ScreenHeight int32
|
|
ScreenCenterX int32
|
|
ScreenCenterY int32
|
|
}
|
|
|
|
// Init stores the application context and sets up common resources.
|
|
func (p *Base) Init(ctx *PageCtx) error {
|
|
p.Context = ctx
|
|
vertices := []float32{
|
|
// pos(x,y) tex(u,v)
|
|
0.0, 1.0, 0.0, 1.0,
|
|
1.0, 0.0, 1.0, 0.0,
|
|
0.0, 0.0, 0.0, 0.0,
|
|
|
|
0.0, 1.0, 0.0, 1.0,
|
|
1.0, 1.0, 1.0, 1.0,
|
|
1.0, 0.0, 1.0, 0.0,
|
|
}
|
|
|
|
W := p.Context.W
|
|
H := p.Context.H
|
|
|
|
p.Projection = mgl32.Ortho(0, float32(W), 0, float32(H), -1, 1)
|
|
p.ScreenHeight = H
|
|
p.ScreenWidth = W
|
|
p.ScreenCenterY = H / 2
|
|
p.ScreenCenterX = W / 2
|
|
|
|
gl.GenVertexArrays(1, &p.QuadVAO)
|
|
gl.GenBuffers(1, &p.QuadVBO)
|
|
gl.BindVertexArray(p.QuadVAO)
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, p.QuadVBO)
|
|
gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, gl.Ptr(vertices), gl.STATIC_DRAW)
|
|
|
|
stride := int32(4 * 4) // Each vertex has 4 floats (pos.x, pos.y, tex.u, tex.v)
|
|
|
|
// Attribute 0: Vertex Position (vec2)
|
|
gl.EnableVertexAttribArray(0)
|
|
gl.VertexAttribPointerWithOffset(0, 2, gl.FLOAT, false, stride, 0)
|
|
|
|
// Attribute 1: Texture Coordinate (vec2)
|
|
gl.EnableVertexAttribArray(1)
|
|
gl.VertexAttribPointerWithOffset(1, 2, gl.FLOAT, false, stride, 2*4) // Offset by 2 floats
|
|
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
|
|
gl.BindVertexArray(0)
|
|
gl.Disable(gl.BLEND)
|
|
gl.UseProgram(0)
|
|
return nil
|
|
}
|
|
|
|
// Destroy cleans up the common OpenGL resources.
|
|
func (p *Base) Destroy() error {
|
|
gl.DeleteBuffers(1, &p.QuadVBO)
|
|
gl.DeleteVertexArrays(1, &p.QuadVAO)
|
|
return nil
|
|
}
|
|
|
|
// BeginTextureRendering sets up shared GL state for a batch of RenderTexture calls.
|
|
// Call this once before a series of RenderTexture calls, then EndTextureRendering after.
|
|
func (p *Base) BeginTextureRendering(shader *shaderManager.Shader) {
|
|
gl.UseProgram(shader.ProgramID)
|
|
gl.Uniform1i(shader.LocTexture, 0)
|
|
gl.ActiveTexture(gl.TEXTURE0)
|
|
gl.Enable(gl.BLEND)
|
|
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
|
gl.BindVertexArray(p.QuadVAO)
|
|
}
|
|
|
|
// EndTextureRendering restores GL state after a batch of RenderTexture calls.
|
|
func (p *Base) EndTextureRendering() {
|
|
gl.BindVertexArray(0)
|
|
gl.Disable(gl.BLEND)
|
|
gl.UseProgram(0)
|
|
}
|
|
|
|
// RenderTexture draws a given texture to the screen at a specified position and size.
|
|
// For best performance, wrap multiple calls with BeginTextureRendering/EndTextureRendering.
|
|
// This method also works standalone for one-off renders.
|
|
func (p *Base) RenderTexture(shader *shaderManager.Shader, textureID uint32, position, size mgl32.Vec2, color sdl.Color) error {
|
|
gl.UseProgram(shader.ProgramID)
|
|
gl.Uniform1i(shader.LocTexture, 0)
|
|
|
|
if shader.LocTextColor == -1 {
|
|
return fmt.Errorf("could not find 'u_textColor' uniform in shader program %d", shader.ProgramID)
|
|
}
|
|
gl.Uniform4f(shader.LocTextColor, float32(color.R)/255.0, float32(color.G)/255.0, float32(color.B)/255.0, float32(color.A)/255.0)
|
|
|
|
model := mgl32.Ident4()
|
|
model = model.Mul4(mgl32.Translate3D(position.X(), position.Y(), 0))
|
|
model = model.Mul4(mgl32.Scale3D(size.X(), size.Y(), 1))
|
|
mvp := p.Projection.Mul4(model)
|
|
gl.UniformMatrix4fv(shader.LocMVPMatrix, 1, false, &mvp[0])
|
|
|
|
gl.ActiveTexture(gl.TEXTURE0)
|
|
gl.BindTexture(gl.TEXTURE_2D, textureID)
|
|
gl.Enable(gl.BLEND)
|
|
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
|
|
|
gl.BindVertexArray(p.QuadVAO)
|
|
gl.DrawArrays(gl.TRIANGLES, 0, 6)
|
|
|
|
gl.BindVertexArray(0)
|
|
gl.Disable(gl.BLEND)
|
|
gl.UseProgram(0)
|
|
return nil
|
|
}
|
|
|
|
// RenderTextureBatched is a lightweight version of RenderTexture for use inside
|
|
// a BeginTextureRendering/EndTextureRendering block. It skips redundant state setup.
|
|
func (p *Base) RenderTextureBatched(shader *shaderManager.Shader, textureID uint32, position, size mgl32.Vec2, color sdl.Color) {
|
|
gl.Uniform4f(shader.LocTextColor, float32(color.R)/255.0, float32(color.G)/255.0, float32(color.B)/255.0, float32(color.A)/255.0)
|
|
|
|
model := mgl32.Ident4()
|
|
model = model.Mul4(mgl32.Translate3D(position.X(), position.Y(), 0))
|
|
model = model.Mul4(mgl32.Scale3D(size.X(), size.Y(), 1))
|
|
mvp := p.Projection.Mul4(model)
|
|
gl.UniformMatrix4fv(shader.LocMVPMatrix, 1, false, &mvp[0])
|
|
|
|
gl.BindTexture(gl.TEXTURE_2D, textureID)
|
|
gl.DrawArrays(gl.TRIANGLES, 0, 6)
|
|
}
|
|
|
|
// RenderSolidColorQuad draws a rectangle of a solid color to the screen.
|
|
func (p *Base) RenderSolidColorQuad(shader *shaderManager.Shader, position, size mgl32.Vec2, color sdl.Color) error {
|
|
gl.UseProgram(shader.ProgramID)
|
|
|
|
model := mgl32.Ident4()
|
|
model = model.Mul4(mgl32.Translate3D(position.X(), position.Y(), 0))
|
|
model = model.Mul4(mgl32.Scale3D(size.X(), size.Y(), 1))
|
|
mvp := p.Projection.Mul4(model)
|
|
|
|
if shader.LocMVPMatrix == -1 {
|
|
return fmt.Errorf("RenderSolidColorQuad: could not find 'u_mvpMatrix' uniform")
|
|
}
|
|
gl.UniformMatrix4fv(shader.LocMVPMatrix, 1, false, &mvp[0])
|
|
|
|
if shader.LocColor == -1 {
|
|
return fmt.Errorf("RenderSolidColorQuad: could not find 'u_color' uniform")
|
|
}
|
|
gl.Uniform4f(shader.LocColor, float32(color.R)/255.0, float32(color.G)/255.0, float32(color.B)/255.0, float32(color.A)/255.0)
|
|
|
|
gl.Enable(gl.BLEND)
|
|
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
|
|
|
gl.BindVertexArray(p.QuadVAO)
|
|
gl.DrawArrays(gl.TRIANGLES, 0, 6)
|
|
|
|
gl.BindVertexArray(0)
|
|
gl.Disable(gl.BLEND)
|
|
gl.UseProgram(0)
|
|
return nil
|
|
}
|
|
|
|
// Provide default implementations for the Page interface.
|
|
func (p *Base) HandleEvent(event sdl.Event) error { return nil }
|
|
func (p *Base) Update(dt float32) error { return nil }
|
|
func (p *Base) Render() error { return nil }
|