Files
radiantwave-legacy/internal/page/page.go
T

199 lines
6.4 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(app ApplicationInterface) error
HandleEvent(event *sdl.Event) error
Update(dt float32) error
Render() error
// Destroy cleans up the page's resources. The Application's page manager
// is responsible for calling this method
Destroy() error
}
// ApplicationInterface defines the set of methods that a page can use to
// interact with the main application.
type ApplicationInterface interface {
SwitchPage(p Page)
PushPage(p Page)
UnwindToPage(p Page)
GetDrawableSize() (int32, int32)
SchedulePop()
Quit()
}
// Base is a helper struct that pages can embed to get common functionality.
type Base struct {
App ApplicationInterface
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(app ApplicationInterface) error {
p.App = app
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,
}
screenWidth, screenHeight := p.App.GetDrawableSize()
p.Projection = mgl32.Ortho(0, float32(screenWidth), 0, float32(screenHeight), -1, 1)
p.ScreenHeight = screenHeight
p.ScreenWidth = screenWidth
p.ScreenCenterX = screenWidth / 2
p.ScreenCenterY = screenHeight / 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 }