199 lines
6.4 KiB
Go
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 }
|