3 Commits

Author SHA1 Message Date
Marvin Blum
e88c163725 More code restructuring and system access functions. 2016-08-19 00:15:27 +02:00
Marvin Blum
bc624295be Simplified for loops in render systems. 2016-08-19 00:04:05 +02:00
Marvin Blum
69886eff00 Code restructuring. 2016-08-18 23:58:41 +02:00
19 changed files with 304 additions and 283 deletions

View File

@@ -1,5 +1,10 @@
# Changelog # Changelog
## 0.2_beta
* code restructuring
* added system access functions (like GetSpriteRenderer())
## 0.1_beta ## 0.1_beta
* beta release * beta release

View File

@@ -7,8 +7,8 @@ Game engine written in Go using OpenGL and GLFW. Mostly for 2D rendering, but al
go-game requires OpenGL and GLFW. The following three steps install everything you need: go-game requires OpenGL and GLFW. The following three steps install everything you need:
``` ```
go get github.com/go-gl/gl/v3.1-core/gl go get github.com/go-gl/gl/v3.2-core/gl
go get github.com/go-gl/glfw/v3.1/glfw go get github.com/go-gl/glfw/v3.2/glfw
go get github.com/DeKugelschieber/go-game go get github.com/DeKugelschieber/go-game
``` ```

View File

@@ -1,5 +1,9 @@
package goga package goga
var (
actorIdGen = ActorId(0)
)
// An actor ID is a unique integer, // An actor ID is a unique integer,
// which can be used to reference an actor. // which can be used to reference an actor.
type ActorId uint64 type ActorId uint64
@@ -10,10 +14,6 @@ type Actor struct {
id ActorId id ActorId
} }
var (
actorIdGen = ActorId(0)
)
// Creates a new basic actor with unique ID. // Creates a new basic actor with unique ID.
func NewActor() *Actor { func NewActor() *Actor {
actorIdGen++ actorIdGen++

View File

@@ -80,14 +80,14 @@ func (c *Culling2D) GetName() string {
// Updates visibility of all contained sprites. // Updates visibility of all contained sprites.
func (c *Culling2D) Update(delta float64) { func (c *Culling2D) Update(delta float64) {
for i := range c.cullables { for _, cullable := range c.cullables {
if c.cullables[i].Pos.X > c.viewport.Z || if cullable.Pos.X > c.viewport.Z ||
c.cullables[i].Pos.X+c.cullables[i].Size.X < c.viewport.X || cullable.Pos.X+cullable.Size.X < c.viewport.X ||
c.cullables[i].Pos.Y > c.viewport.W || cullable.Pos.Y > c.viewport.W ||
c.cullables[i].Pos.Y+c.cullables[i].Size.Y < c.viewport.Y { cullable.Pos.Y+cullable.Size.Y < c.viewport.Y {
c.cullables[i].Visible = false cullable.Visible = false
} else { } else {
c.cullables[i].Visible = true cullable.Visible = true
} }
} }
} }

View File

@@ -33,20 +33,10 @@ func (g *Game) Setup() {
sprite.Size.X = sprite.Size.X / 4 sprite.Size.X = sprite.Size.X / 4
sprite.Size.Y = sprite.Size.Y / 4 sprite.Size.Y = sprite.Size.Y / 4
g.sprite = sprite g.sprite = sprite
renderer, ok := goga.GetSystemByName("spriteRenderer").(*goga.SpriteRenderer) renderer := goga.GetSpriteRenderer()
if !ok {
panic("Could not find renderer")
}
renderer.Add(sprite.Actor, sprite.Pos2D, sprite.Tex) renderer.Add(sprite.Actor, sprite.Pos2D, sprite.Tex)
culling, ok := goga.GetSystemByName("culling2d").(*goga.Culling2D) culling := goga.GetCulling2DSystem()
if !ok {
panic("Could not find culling")
}
culling.Add(sprite.Actor, sprite.Pos2D) culling.Add(sprite.Actor, sprite.Pos2D)
// register input listeners // register input listeners

View File

@@ -39,12 +39,7 @@ func (g *Game) Setup() {
sprite.KeyframeAnimation = goga.NewKeyframeAnimation(0, 7, true, 20) sprite.KeyframeAnimation = goga.NewKeyframeAnimation(0, 7, true, 20)
// add to renderer // add to renderer
renderer, ok := goga.GetSystemByName("keyframeRenderer").(*goga.KeyframeRenderer) renderer := goga.GetKeyframeRenderer()
if !ok {
panic("Could not find renderer")
}
renderer.Add(sprite.Actor, sprite.Pos2D, sprite.Tex, sprite.KeyframeSet, sprite.KeyframeAnimation) renderer.Add(sprite.Actor, sprite.Pos2D, sprite.Tex, sprite.KeyframeSet, sprite.KeyframeAnimation)
} }

View File

@@ -36,12 +36,7 @@ func (g *Game) Setup() {
mesh := goga.NewMesh(ply.IndexBuffer, ply.VertexBuffer, ply.TexCoordBuffer) mesh := goga.NewMesh(ply.IndexBuffer, ply.VertexBuffer, ply.TexCoordBuffer)
model := goga.NewModel(mesh, tex) model := goga.NewModel(mesh, tex)
renderer, ok := goga.GetSystemByName("modelRenderer").(*goga.ModelRenderer) renderer := goga.GetModelRenderer()
if !ok {
panic("Could not find renderer")
}
renderer.Prepare(model) renderer.Prepare(model)
renderer.Add(model.Actor, model.Pos3D, model.Tex, model.Mesh) renderer.Add(model.Actor, model.Pos3D, model.Tex, model.Mesh)
g.model = model g.model = model

View File

@@ -26,20 +26,10 @@ func (g *Game) Setup() {
} }
sprite := goga.NewSprite(tex) sprite := goga.NewSprite(tex)
renderer, ok := goga.GetSystemByName("spriteRenderer").(*goga.SpriteRenderer) renderer := goga.GetSpriteRenderer()
if !ok {
panic("Could not find renderer")
}
renderer.Add(sprite.Actor, sprite.Pos2D, sprite.Tex) renderer.Add(sprite.Actor, sprite.Pos2D, sprite.Tex)
culling, ok := goga.GetSystemByName("culling2d").(*goga.Culling2D) culling := goga.GetCulling2DSystem()
if !ok {
panic("Could not find culling")
}
culling.Add(sprite.Actor, sprite.Pos2D) culling.Add(sprite.Actor, sprite.Pos2D)
} }

View File

@@ -45,12 +45,7 @@ func (g *Game) Setup() {
} }
// setup renderer // setup renderer
renderer, ok := goga.GetSystemByName("textRenderer").(*goga.TextRenderer) renderer := goga.GetTextRenderer()
if !ok {
panic("Could not find renderer")
}
renderer.Font = font renderer.Font = font
// create and add text // create and add text

28
game.go
View File

@@ -16,6 +16,20 @@ const (
default_exit_on_close = true default_exit_on_close = true
) )
var (
running = true
clearColor = Vec4{}
clearBuffer []uint32
viewportWidth int
viewportHeight int
// Default resources
DefaultCamera *Camera
Default2DShader *Shader
Default3DShader *Shader
DefaultTextShader *Shader
)
// If set in RunOptions, the function will be called on window resize. // If set in RunOptions, the function will be called on window resize.
type ResizeCallback func(width, height int) type ResizeCallback func(width, height int)
@@ -43,20 +57,6 @@ type Game interface {
Update(float64) Update(float64)
} }
var (
running = true
clearColor = Vec4{}
clearBuffer []uint32
viewportWidth int
viewportHeight int
// Default resources
DefaultCamera *Camera
Default2DShader *Shader
Default3DShader *Shader
DefaultTextShader *Shader
)
func init() { func init() {
// GL functions must be called from main thread, // GL functions must be called from main thread,
// so we disable multithreading by the runtime here. // so we disable multithreading by the runtime here.

View File

@@ -14,44 +14,6 @@ type Keyframe struct {
Min, Max Vec2 Min, Max Vec2
} }
// A set of keyframes making up an animation.
type KeyframeSet struct {
Keyframes []Keyframe
}
// Keyframe animation component.
// It has a start and an end frame, a play speed and option to loop.
type KeyframeAnimation struct {
Start, End int
Loop bool
Speed float64
Current int
Interpolation float64
}
// An animated sprite is a sprite with keyframe animation information.
// It will be updated and rendered by the KeyframeRenderer.
type AnimatedSprite struct {
*Actor
*Pos2D
*Tex
*KeyframeSet
*KeyframeAnimation
}
// The keyframe renderer renders animated sprites.
// It has a 2D position component, to move all sprites at once.
type KeyframeRenderer struct {
Pos2D
Shader *Shader
Camera *Camera
sprites []AnimatedSprite
index, vertex *VBO
vao *VAO
}
// Creates a new single keyframe with texture VBO. // Creates a new single keyframe with texture VBO.
func NewKeyframe(min, max Vec2) *Keyframe { func NewKeyframe(min, max Vec2) *Keyframe {
keyframe := &Keyframe{Min: min, Max: max} keyframe := &Keyframe{Min: min, Max: max}
@@ -74,6 +36,11 @@ func NewKeyframe(min, max Vec2) *Keyframe {
return keyframe return keyframe
} }
// A set of keyframes making up an animation.
type KeyframeSet struct {
Keyframes []Keyframe
}
// Creates a new empty keyframe set with given size. // Creates a new empty keyframe set with given size.
func NewKeyframeSet() *KeyframeSet { func NewKeyframeSet() *KeyframeSet {
set := &KeyframeSet{} set := &KeyframeSet{}
@@ -88,11 +55,31 @@ func (s *KeyframeSet) Add(frame *Keyframe) int {
return len(s.Keyframes) return len(s.Keyframes)
} }
// Keyframe animation component.
// It has a start and an end frame, a play speed and option to loop.
type KeyframeAnimation struct {
Start, End int
Loop bool
Speed float64
Current int
Interpolation float64
}
// Creates a new keyframe animation with given start, end and loop. // Creates a new keyframe animation with given start, end and loop.
func NewKeyframeAnimation(start, end int, loop bool, speed float64) *KeyframeAnimation { func NewKeyframeAnimation(start, end int, loop bool, speed float64) *KeyframeAnimation {
return &KeyframeAnimation{start, end, loop, speed, 0, 0} return &KeyframeAnimation{start, end, loop, speed, 0, 0}
} }
// An animated sprite is a sprite with keyframe animation information.
// It will be updated and rendered by the KeyframeRenderer.
type AnimatedSprite struct {
*Actor
*Pos2D
*Tex
*KeyframeSet
*KeyframeAnimation
}
// Creates a new animated sprite. // Creates a new animated sprite.
func NewAnimatedSprite(tex *Tex, set *KeyframeSet, width, height int) *AnimatedSprite { func NewAnimatedSprite(tex *Tex, set *KeyframeSet, width, height int) *AnimatedSprite {
sprite := &AnimatedSprite{} sprite := &AnimatedSprite{}
@@ -114,6 +101,19 @@ func NewAnimatedSprite(tex *Tex, set *KeyframeSet, width, height int) *AnimatedS
return sprite return sprite
} }
// The keyframe renderer renders animated sprites.
// It has a 2D position component, to move all sprites at once.
type KeyframeRenderer struct {
Pos2D
Shader *Shader
Camera *Camera
sprites []AnimatedSprite
index, vertex *VBO
vao *VAO
}
// Creates a new keyframe renderer using given shader and camera. // Creates a new keyframe renderer using given shader and camera.
// If shader and/or camera are nil, the default one will be used. // If shader and/or camera are nil, the default one will be used.
func NewKeyframeRenderer(shader *Shader, camera *Camera) *KeyframeRenderer { func NewKeyframeRenderer(shader *Shader, camera *Camera) *KeyframeRenderer {
@@ -206,22 +206,22 @@ func (s *KeyframeRenderer) GetName() string {
// Updates animation state and renders sprites. // Updates animation state and renders sprites.
func (s *KeyframeRenderer) Update(delta float64) { func (s *KeyframeRenderer) Update(delta float64) {
// update animation state // update animation state
for i := range s.sprites { for _, sprite := range s.sprites {
if s.sprites[i].KeyframeAnimation == nil { if sprite.KeyframeAnimation == nil {
continue continue
} }
s.sprites[i].Interpolation += delta * s.sprites[i].KeyframeAnimation.Speed sprite.Interpolation += delta * sprite.KeyframeAnimation.Speed
if s.sprites[i].Interpolation > 1 { if sprite.Interpolation > 1 {
s.sprites[i].Interpolation = 0 sprite.Interpolation = 0
s.sprites[i].Current++ sprite.Current++
if s.sprites[i].Current > s.sprites[i].KeyframeAnimation.End { if sprite.Current > sprite.KeyframeAnimation.End {
if s.sprites[i].KeyframeAnimation.Loop { if sprite.KeyframeAnimation.Loop {
s.sprites[i].Current = s.sprites[i].KeyframeAnimation.Start sprite.Current = sprite.KeyframeAnimation.Start
} else { } else {
s.sprites[i].Current = s.sprites[i].KeyframeAnimation.End sprite.Current = sprite.KeyframeAnimation.End
} }
} }
} }
@@ -233,17 +233,17 @@ func (s *KeyframeRenderer) Update(delta float64) {
s.Shader.SendUniform1i(Default_shader_2D_tex, 0) s.Shader.SendUniform1i(Default_shader_2D_tex, 0)
s.vao.Bind() s.vao.Bind()
for i := range s.sprites { for _, sprite := range s.sprites {
if !s.sprites[i].Visible { if !sprite.Visible {
continue continue
} }
texCoord := s.sprites[i].KeyframeSet.Keyframes[s.sprites[i].Current].texCoord texCoord := sprite.KeyframeSet.Keyframes[sprite.Current].texCoord
texCoord.Bind() texCoord.Bind()
texCoord.AttribPointer(s.Shader.GetAttribLocation(Default_shader_2D_texcoord_attrib), 2, gl.FLOAT, false, 0) texCoord.AttribPointer(s.Shader.GetAttribLocation(Default_shader_2D_texcoord_attrib), 2, gl.FLOAT, false, 0)
s.Shader.SendMat3(Default_shader_2D_model, *s.sprites[i].CalcModel()) s.Shader.SendMat3(Default_shader_2D_model, *sprite.CalcModel())
s.sprites[i].Tex.Bind() sprite.Tex.Bind()
gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil)
} }

View File

@@ -21,27 +21,6 @@ type PngLoader struct {
KeepData bool KeepData bool
} }
// Standford ply file resource.
type Ply struct {
name string
path string
ext string
firstLine, data, hasVertex, hasTexCoord, hasNormal bool
elements, faces int
indices []uint32
vertices, texCoords, normals []float32
IndexBuffer, VertexBuffer, TexCoordBuffer, NormalBuffer *VBO
}
// Loads ply files and creates VBOs within the Ply resource.
// The indices must be present as triangles.
// Expected type is float32. If it fails to parse, it will panic.
type PlyLoader struct {
VboUsage uint32
}
func (p *PngLoader) Load(file string) (Res, error) { func (p *PngLoader) Load(file string) (Res, error) {
// load texture // load texture
imgFile, err := os.Open(file) imgFile, err := os.Open(file)
@@ -82,6 +61,27 @@ func (p *PngLoader) Ext() string {
return "png" return "png"
} }
// Standford ply file resource.
type Ply struct {
name string
path string
ext string
firstLine, data, hasVertex, hasTexCoord, hasNormal bool
elements, faces int
indices []uint32
vertices, texCoords, normals []float32
IndexBuffer, VertexBuffer, TexCoordBuffer, NormalBuffer *VBO
}
// Loads ply files and creates VBOs within the Ply resource.
// The indices must be present as triangles.
// Expected type is float32. If it fails to parse, it will panic.
type PlyLoader struct {
VboUsage uint32
}
// Drops contained GL buffers. // Drops contained GL buffers.
func (p *Ply) Drop() { func (p *Ply) Drop() {
if p.IndexBuffer != nil { if p.IndexBuffer != nil {

View File

@@ -14,26 +14,6 @@ type Mesh struct {
Vao *VAO Vao *VAO
} }
// Model is an actor having a 3D position, a texture and a 3D mesh.
type Model struct {
*Actor
*Pos3D
*Tex
*Mesh
}
// The model renderer is a system rendering models.
// It has a 3D position component, to move all models at once.
type ModelRenderer struct {
Pos3D
Shader *Shader
Camera *Camera
ortho bool
models []Model
}
// Creates a new mesh with given GL buffers. // Creates a new mesh with given GL buffers.
// The VAO must be prepared by ModelRenderer. // The VAO must be prepared by ModelRenderer.
func NewMesh(index, vertex, texcoord *VBO) *Mesh { func NewMesh(index, vertex, texcoord *VBO) *Mesh {
@@ -56,6 +36,14 @@ func (m *Mesh) Drop() {
m.Vao.Drop() m.Vao.Drop()
} }
// Model is an actor having a 3D position, a texture and a 3D mesh.
type Model struct {
*Actor
*Pos3D
*Tex
*Mesh
}
// Creates a new model with given mesh and texture. // Creates a new model with given mesh and texture.
func NewModel(mesh *Mesh, tex *Tex) *Model { func NewModel(mesh *Mesh, tex *Tex) *Model {
model := &Model{} model := &Model{}
@@ -72,6 +60,18 @@ func NewModel(mesh *Mesh, tex *Tex) *Model {
return model return model
} }
// The model renderer is a system rendering models.
// It has a 3D position component, to move all models at once.
type ModelRenderer struct {
Pos3D
Shader *Shader
Camera *Camera
ortho bool
models []Model
}
// Creates a new model renderer using given shader and camera. // Creates a new model renderer using given shader and camera.
// If shader and/or camera are nil, the default one will be used. // If shader and/or camera are nil, the default one will be used.
// Orth can be set to true, to use orthogonal projection. // Orth can be set to true, to use orthogonal projection.
@@ -174,20 +174,20 @@ func (s *ModelRenderer) Update(delta float64) {
var tid uint32 var tid uint32
for i := range s.models { for _, model := range s.models {
if !s.models[i].Visible { if !model.Visible {
continue continue
} }
s.Shader.SendMat4(Default_shader_3D_model, *s.models[i].CalcModel()) s.Shader.SendMat4(Default_shader_3D_model, *model.CalcModel())
s.models[i].Vao.Bind() model.Vao.Bind()
// prevent texture switching when not neccessary // prevent texture switching when not neccessary
if tid != s.models[i].Tex.GetId() { if tid != model.Tex.GetId() {
tid = s.models[i].Tex.GetId() tid = model.Tex.GetId()
s.models[i].Tex.Bind() model.Tex.Bind()
} }
gl.DrawElements(gl.TRIANGLES, s.models[i].Index.Size(), gl.UNSIGNED_INT, nil) gl.DrawElements(gl.TRIANGLES, model.Index.Size(), gl.UNSIGNED_INT, nil)
} }
} }

14
pos.go
View File

@@ -8,13 +8,6 @@ type Pos2D struct {
M Mat3 M Mat3
} }
// Position component for 3D objects
type Pos3D struct {
Pos, Size, Scale, RotPoint, Rot Vec3
Visible bool
M Mat4
}
// Creates a default initialized Pos2D. // Creates a default initialized Pos2D.
func NewPos2D() *Pos2D { func NewPos2D() *Pos2D {
m := Mat3{} m := Mat3{}
@@ -45,6 +38,13 @@ func (p *Pos2D) PointInRect(point Vec2) bool {
return point.X > p.Pos.X && point.X < p.Pos.X+p.Size.X*p.Scale.X && point.Y > p.Pos.Y && point.Y < p.Pos.Y+p.Size.Y*p.Scale.Y return point.X > p.Pos.X && point.X < p.Pos.X+p.Size.X*p.Scale.X && point.Y > p.Pos.Y && point.Y < p.Pos.Y+p.Size.Y*p.Scale.Y
} }
// Position component for 3D objects
type Pos3D struct {
Pos, Size, Scale, RotPoint, Rot Vec3
Visible bool
M Mat4
}
// Creates a default initialized Pos3D. // Creates a default initialized Pos3D.
func NewPos3D() *Pos3D { func NewPos3D() *Pos3D {
m := Mat4{} m := Mat4{}

View File

@@ -4,6 +4,11 @@ import (
"log" "log"
) )
var (
scenes []Scene
activeScene Scene
)
// A scene used to switch between game states. // A scene used to switch between game states.
// The Cleanup() method is called when a scene is removed // The Cleanup() method is called when a scene is removed
// or the program is stopped. It can be used to cleanup open resources // or the program is stopped. It can be used to cleanup open resources
@@ -19,11 +24,6 @@ type Scene interface {
GetName() string GetName() string
} }
var (
scenes []Scene
activeScene Scene
)
// Adds a scene to game. // Adds a scene to game.
// Returns false if the scene exists already. // Returns false if the scene exists already.
// The first scene added will be set active. // The first scene added will be set active.

View File

@@ -15,19 +15,6 @@ type Sprite struct {
*Tex *Tex
} }
// The sprite renderer is a system rendering sprites.
// It has a 2D position component, to move all sprites at once.
type SpriteRenderer struct {
Pos2D
Shader *Shader
Camera *Camera
sprites []Sprite
index, vertex, texCoord *VBO
vao *VAO
}
// Creates a new sprite with given texture. // Creates a new sprite with given texture.
func NewSprite(tex *Tex) *Sprite { func NewSprite(tex *Tex) *Sprite {
sprite := &Sprite{} sprite := &Sprite{}
@@ -43,6 +30,19 @@ func NewSprite(tex *Tex) *Sprite {
return sprite return sprite
} }
// The sprite renderer is a system rendering sprites.
// It has a 2D position component, to move all sprites at once.
type SpriteRenderer struct {
Pos2D
Shader *Shader
Camera *Camera
sprites []Sprite
index, vertex, texCoord *VBO
vao *VAO
}
// Creates a new sprite renderer using given shader and camera. // Creates a new sprite renderer using given shader and camera.
// If shader and/or camera are nil, the default one will be used. // If shader and/or camera are nil, the default one will be used.
func NewSpriteRenderer(shader *Shader, camera *Camera, flip bool) *SpriteRenderer { func NewSpriteRenderer(shader *Shader, camera *Camera, flip bool) *SpriteRenderer {
@@ -140,17 +140,17 @@ func (s *SpriteRenderer) Update(delta float64) {
s.vao.Bind() s.vao.Bind()
var tid uint32 var tid uint32
for i := range s.sprites { for _, sprite := range s.sprites {
if !s.sprites[i].Visible { if !sprite.Visible {
continue continue
} }
s.Shader.SendMat3(Default_shader_2D_model, *s.sprites[i].CalcModel()) s.Shader.SendMat3(Default_shader_2D_model, *sprite.CalcModel())
// prevent texture switching when not neccessary // prevent texture switching when not neccessary
if tid != s.sprites[i].Tex.GetId() { if tid != sprite.Tex.GetId() {
tid = s.sprites[i].Tex.GetId() tid = sprite.Tex.GetId()
s.sprites[i].Tex.Bind() sprite.Tex.Bind()
} }
gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil) gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, nil)

View File

@@ -2,6 +2,10 @@ package goga
import () import ()
var (
systems []System
)
// A system provides logic for actors satisfying required components. // A system provides logic for actors satisfying required components.
// They are automatically updated on each frame. // They are automatically updated on each frame.
// When a system is removed from systems, the Cleanup() method will be called. // When a system is removed from systems, the Cleanup() method will be called.
@@ -17,10 +21,6 @@ type System interface {
GetName() string GetName() string
} }
var (
systems []System
)
// Adds a system to the game. // Adds a system to the game.
// Returns false if the system exists already. // Returns false if the system exists already.
func AddSystem(system System) bool { func AddSystem(system System) bool {

51
system_util.go Normal file
View File

@@ -0,0 +1,51 @@
package goga
func GetSpriteRenderer() *SpriteRenderer {
renderer, ok := GetSystemByName(sprite_renderer_name).(*SpriteRenderer)
if !ok {
panic("Could not obtain sprite renderer")
}
return renderer
}
func GetModelRenderer() *ModelRenderer {
renderer, ok := GetSystemByName(model_renderer_name).(*ModelRenderer)
if !ok {
panic("Could not obtain model renderer")
}
return renderer
}
func GetCulling2DSystem() *Culling2D {
system, ok := GetSystemByName(culling_2d_name).(*Culling2D)
if !ok {
panic("Could not obtain culling system")
}
return system
}
func GetKeyframeRenderer() *KeyframeRenderer {
renderer, ok := GetSystemByName(keyframe_sprite_renderer_name).(*KeyframeRenderer)
if !ok {
panic("Could not obtain keyframe renderer")
}
return renderer
}
func GetTextRenderer() *TextRenderer {
renderer, ok := GetSystemByName(text_renderer_name).(*TextRenderer)
if !ok {
panic("Could not obtain text renderer")
}
return renderer
}

154
text.go
View File

@@ -32,36 +32,6 @@ type Font struct {
chars []character chars []character
} }
// Renderable text component.
// Use together with Text and create using NewText().
type TextComponent struct {
Color Vec4
text string
bounds Vec2
index, vertex, texCoord *VBO
vao *VAO
}
// Text is an actor representing text rendered as texture mapped font.
// Each Text has a position and its own buffers.
type Text struct {
*Actor
*Pos2D
*TextComponent
}
// The text renderer is a system rendering 2D texture mapped font.
// It has a 2D position component, to move all texts at once.
type TextRenderer struct {
Pos2D
Shader *Shader
Camera *Camera
Font *Font
texts []Text
}
// Creates a new font for given texture. // Creates a new font for given texture.
// The tile size specifies the size of one character tile on texture. // The tile size specifies the size of one character tile on texture.
// Characters must be added afterwards. // Characters must be added afterwards.
@@ -78,47 +48,6 @@ func NewFont(tex *Tex, tileSize float64) *Font {
return &font return &font
} }
// Returns a new renderable text object.
func NewText(font *Font, textStr string) *Text {
text := Text{}
text.Actor = NewActor()
text.Pos2D = NewPos2D()
text.TextComponent = &TextComponent{}
text.index = NewVBO(gl.ELEMENT_ARRAY_BUFFER)
text.vertex = NewVBO(gl.ARRAY_BUFFER)
text.texCoord = NewVBO(gl.ARRAY_BUFFER)
text.vao = NewVAO()
text.SetText(font, textStr)
text.Color = Vec4{1, 1, 1, 1}
text.Size = Vec2{1, 1}
text.Scale = Vec2{1, 1}
text.Visible = true
return &text
}
// Creates a new text renderer using given shader, camera and font.
// If shader and/or camera are nil, the default one will be used.
func NewTextRenderer(shader *Shader, camera *Camera, font *Font) *TextRenderer {
if shader == nil {
shader = DefaultTextShader
}
if camera == nil {
camera = DefaultCamera
}
renderer := &TextRenderer{}
renderer.Shader = shader
renderer.Camera = camera
renderer.Font = font
renderer.texts = make([]Text, 0)
renderer.Size = Vec2{1, 1}
renderer.Scale = Vec2{1, 1}
return renderer
}
// Loads characters from JSON file. // Loads characters from JSON file.
// Format: // Format:
// //
@@ -229,6 +158,17 @@ func (f *Font) getChar(char byte) *character {
return nil return nil
} }
// Renderable text component.
// Use together with Text and create using NewText().
type TextComponent struct {
Color Vec4
text string
bounds Vec2
index, vertex, texCoord *VBO
vao *VAO
}
// Deletes GL buffers bound to this text component. // Deletes GL buffers bound to this text component.
func (t *TextComponent) Drop() { func (t *TextComponent) Drop() {
t.index.Drop() t.index.Drop()
@@ -237,6 +177,33 @@ func (t *TextComponent) Drop() {
t.vao.Drop() t.vao.Drop()
} }
// Text is an actor representing text rendered as texture mapped font.
// Each Text has a position and its own buffers.
type Text struct {
*Actor
*Pos2D
*TextComponent
}
// Returns a new renderable text object.
func NewText(font *Font, textStr string) *Text {
text := Text{}
text.Actor = NewActor()
text.Pos2D = NewPos2D()
text.TextComponent = &TextComponent{}
text.index = NewVBO(gl.ELEMENT_ARRAY_BUFFER)
text.vertex = NewVBO(gl.ARRAY_BUFFER)
text.texCoord = NewVBO(gl.ARRAY_BUFFER)
text.vao = NewVAO()
text.SetText(font, textStr)
text.Color = Vec4{1, 1, 1, 1}
text.Size = Vec2{1, 1}
text.Scale = Vec2{1, 1}
text.Visible = true
return &text
}
// Sets the given string as text and (re)creates buffers. // Sets the given string as text and (re)creates buffers.
func (t *Text) SetText(font *Font, text string) { func (t *Text) SetText(font *Font, text string) {
t.text = text t.text = text
@@ -345,6 +312,39 @@ func (t *Text) GetBounds() Vec2 {
return Vec2{t.bounds.X * t.Size.X * t.Scale.X, t.bounds.Y * t.Size.Y * t.Scale.Y} return Vec2{t.bounds.X * t.Size.X * t.Scale.X, t.bounds.Y * t.Size.Y * t.Scale.Y}
} }
// The text renderer is a system rendering 2D texture mapped font.
// It has a 2D position component, to move all texts at once.
type TextRenderer struct {
Pos2D
Shader *Shader
Camera *Camera
Font *Font
texts []Text
}
// Creates a new text renderer using given shader, camera and font.
// If shader and/or camera are nil, the default one will be used.
func NewTextRenderer(shader *Shader, camera *Camera, font *Font) *TextRenderer {
if shader == nil {
shader = DefaultTextShader
}
if camera == nil {
camera = DefaultCamera
}
renderer := &TextRenderer{}
renderer.Shader = shader
renderer.Camera = camera
renderer.Font = font
renderer.texts = make([]Text, 0)
renderer.Size = Vec2{1, 1}
renderer.Scale = Vec2{1, 1}
return renderer
}
// Prepares given text for rendering. // Prepares given text for rendering.
func (r *TextRenderer) Prepare(text *Text) { func (r *TextRenderer) Prepare(text *Text) {
text.vao = NewVAO() text.vao = NewVAO()
@@ -423,15 +423,15 @@ func (r *TextRenderer) Update(delta float64) {
r.Shader.SendUniform1i(Default_shader_text_tex, 0) r.Shader.SendUniform1i(Default_shader_text_tex, 0)
r.Font.Tex.Bind() r.Font.Tex.Bind()
for i := range r.texts { for _, text := range r.texts {
if !r.texts[i].Visible { if !text.Visible {
continue continue
} }
r.texts[i].vao.Bind() text.vao.Bind()
r.Shader.SendUniform4f(Default_shader_text_color, float32(r.texts[i].Color.X), float32(r.texts[i].Color.Y), float32(r.texts[i].Color.Z), float32(r.texts[i].Color.W)) r.Shader.SendUniform4f(Default_shader_text_color, float32(text.Color.X), float32(text.Color.Y), float32(text.Color.Z), float32(text.Color.W))
r.Shader.SendMat3(Default_shader_text_model, *r.texts[i].CalcModel()) r.Shader.SendMat3(Default_shader_text_model, *text.CalcModel())
gl.DrawElements(gl.TRIANGLES, r.texts[i].index.Size(), gl.UNSIGNED_INT, nil) gl.DrawElements(gl.TRIANGLES, text.index.Size(), gl.UNSIGNED_INT, nil)
} }
} }