mirror of
https://github.com/Kugelschieber/go-game.git
synced 2026-01-18 14:50:28 +00:00
Compare commits
8 Commits
text-rende
...
0.2_beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e88c163725 | ||
|
|
bc624295be | ||
|
|
69886eff00 | ||
|
|
6ffa5aa431 | ||
|
|
25814cf022 | ||
|
|
092ad543e5 | ||
|
|
3c1fb484b9 | ||
|
|
ed39081300 |
10
CHANGELOG.md
Normal file
10
CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 0.2_beta
|
||||||
|
|
||||||
|
* code restructuring
|
||||||
|
* added system access functions (like GetSpriteRenderer())
|
||||||
|
|
||||||
|
## 0.1_beta
|
||||||
|
|
||||||
|
* beta release
|
||||||
11
README.md
11
README.md
@@ -1,15 +1,14 @@
|
|||||||
# go-game (package "goga")
|
# go-game (package "goga")
|
||||||
|
|
||||||
Game engine written in Go using OpenGL and GLFW. Mostly for 2D rendering, but also capable of rendering 3D, providing everything to get you started.
|
Game engine written in Go using OpenGL and GLFW. Mostly for 2D rendering, but also capable of rendering 3D, providing everything to get you started.
|
||||||
**Under heavy development, do not use yet!**
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
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/v4.5-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
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -17,18 +16,16 @@ You also need a cgo compiler (typically gcc) and GL/GLFW development libraries a
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
*WIP*
|
|
||||||
|
|
||||||
Examples can be found within the demo folder. For full reference visit: https://godoc.org/github.com/DeKugelschieber/go-game
|
Examples can be found within the demo folder. For full reference visit: https://godoc.org/github.com/DeKugelschieber/go-game
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
* https://github.com/go-gl/gl
|
* https://github.com/go-gl/gl
|
||||||
- 4.5-core
|
- 3.1-core
|
||||||
* https://github.com/go-gl/glfw
|
* https://github.com/go-gl/glfw
|
||||||
- 3.1
|
- 3.1
|
||||||
|
|
||||||
To use an older GL version, you need to replace the GL imports in package goga. It should mostly be compatible down to 3.x.
|
To use a different GL version, you need to replace the GL imports in package goga.
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
|
|||||||
9
ToDo.md
9
ToDo.md
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
* ~~cleanup resources~~
|
* ~~cleanup resources~~
|
||||||
* more logging
|
* more logging
|
||||||
* limit FPS
|
* ~~limit FPS~~
|
||||||
* fullscreen
|
- does this really work?
|
||||||
* simple access to default resources like GetTex()
|
* ~~fullscreen~~
|
||||||
|
* ~~simple access to default resources like GetTex()~~
|
||||||
|
* ~~text rendering + font loading~~
|
||||||
|
* more options for GLFW
|
||||||
|
|||||||
8
actor.go
8
actor.go
@@ -1,6 +1,8 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import ()
|
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.
|
||||||
@@ -12,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++
|
||||||
|
|||||||
14
culling.go
14
culling.go
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
default_shader.go
Normal file
83
default_shader.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package goga
|
||||||
|
|
||||||
|
const (
|
||||||
|
// constants for default 2D shader
|
||||||
|
Default_shader_2D_vertex_attrib = "vertex"
|
||||||
|
Default_shader_2D_texcoord_attrib = "texCoord"
|
||||||
|
Default_shader_2D_ortho = "o"
|
||||||
|
Default_shader_2D_model = "m"
|
||||||
|
Default_shader_2D_tex = "tex"
|
||||||
|
|
||||||
|
// source for 2D shader
|
||||||
|
default_shader_2d_vertex_src = `#version 130
|
||||||
|
uniform mat3 o, m;
|
||||||
|
in vec2 vertex;
|
||||||
|
in vec2 texCoord;
|
||||||
|
out vec2 tc;
|
||||||
|
void main(){
|
||||||
|
tc = texCoord;
|
||||||
|
gl_Position = vec4(o*m*vec3(vertex, 1.0), 1.0);
|
||||||
|
}`
|
||||||
|
default_shader_2d_fragment_src = `#version 130
|
||||||
|
precision highp float;
|
||||||
|
uniform sampler2D tex;
|
||||||
|
in vec2 tc;
|
||||||
|
out vec4 color;
|
||||||
|
void main(){
|
||||||
|
color = texture(tex, tc);
|
||||||
|
}`
|
||||||
|
|
||||||
|
// constants for default 3D shader
|
||||||
|
Default_shader_3D_vertex_attrib = "vertex"
|
||||||
|
Default_shader_3D_texcoord_attrib = "texCoord"
|
||||||
|
Default_shader_3D_pv = "pv"
|
||||||
|
Default_shader_3D_model = "m"
|
||||||
|
Default_shader_3D_tex = "tex"
|
||||||
|
|
||||||
|
// source for 3D shader
|
||||||
|
default_shader_3d_vertex_src = `#version 130
|
||||||
|
uniform mat4 pv, m;
|
||||||
|
in vec3 vertex;
|
||||||
|
in vec2 texCoord;
|
||||||
|
out vec2 tc;
|
||||||
|
void main(){
|
||||||
|
tc = texCoord;
|
||||||
|
gl_Position = pv*m*vec4(vertex, 1.0);
|
||||||
|
}`
|
||||||
|
default_shader_3d_fragment_src = `#version 130
|
||||||
|
precision highp float;
|
||||||
|
uniform sampler2D tex;
|
||||||
|
in vec2 tc;
|
||||||
|
out vec4 color;
|
||||||
|
void main(){
|
||||||
|
color = texture(tex, tc);
|
||||||
|
}`
|
||||||
|
|
||||||
|
// constants for default text shader
|
||||||
|
Default_shader_text_vertex_attrib = "vertex"
|
||||||
|
Default_shader_text_texcoord_attrib = "texCoord"
|
||||||
|
Default_shader_text_ortho = "o"
|
||||||
|
Default_shader_text_model = "m"
|
||||||
|
Default_shader_text_tex = "tex"
|
||||||
|
Default_shader_text_color = "color"
|
||||||
|
|
||||||
|
// source for text shader
|
||||||
|
default_shader_text_vertex_src = `#version 130
|
||||||
|
uniform mat3 o, m;
|
||||||
|
in vec2 vertex;
|
||||||
|
in vec2 texCoord;
|
||||||
|
out vec2 tc;
|
||||||
|
void main(){
|
||||||
|
tc = texCoord;
|
||||||
|
gl_Position = vec4(o*m*vec3(vertex, 1.0), 1.0);
|
||||||
|
}`
|
||||||
|
default_shader_text_fragment_src = `#version 130
|
||||||
|
precision highp float;
|
||||||
|
uniform sampler2D tex;
|
||||||
|
uniform vec4 color;
|
||||||
|
in vec2 tc;
|
||||||
|
out vec4 c;
|
||||||
|
void main(){
|
||||||
|
c = texture(tex, tc)*color;
|
||||||
|
}`
|
||||||
|
)
|
||||||
BIN
demo/input/assets/gopher.png
Normal file
BIN
demo/input/assets/gopher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
77
demo/input/input.go
Normal file
77
demo/input/input.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/DeKugelschieber/go-game"
|
||||||
|
"github.com/go-gl/glfw/v3.2/glfw"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
gopher_path = "src/github.com/DeKugelschieber/go-game/demo/input/assets/gopher.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
mouseX, mouseY float64
|
||||||
|
sprite *goga.Sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Setup() {
|
||||||
|
// load texture
|
||||||
|
_, err := goga.LoadRes(gopher_path)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create sprite
|
||||||
|
tex, err := goga.GetTex("gopher.png")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite := goga.NewSprite(tex)
|
||||||
|
sprite.Size.X = sprite.Size.X / 4
|
||||||
|
sprite.Size.Y = sprite.Size.Y / 4
|
||||||
|
g.sprite = sprite
|
||||||
|
renderer := goga.GetSpriteRenderer()
|
||||||
|
renderer.Add(sprite.Actor, sprite.Pos2D, sprite.Tex)
|
||||||
|
|
||||||
|
culling := goga.GetCulling2DSystem()
|
||||||
|
culling.Add(sprite.Actor, sprite.Pos2D)
|
||||||
|
|
||||||
|
// register input listeners
|
||||||
|
goga.AddKeyboardListener(g)
|
||||||
|
goga.AddMouseListener(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Update(delta float64) {}
|
||||||
|
|
||||||
|
func (g *Game) OnKeyEvent(key glfw.Key, code int, action glfw.Action, mod glfw.ModifierKey) {
|
||||||
|
// ESC
|
||||||
|
if key == 256 {
|
||||||
|
goga.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) OnMouseButton(button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
|
||||||
|
if button == 0 {
|
||||||
|
g.sprite.Pos.X = g.mouseX
|
||||||
|
g.sprite.Pos.Y = g.mouseY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) OnMouseMove(x float64, y float64) {
|
||||||
|
g.mouseX = x
|
||||||
|
g.mouseY = y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) OnMouseScroll(x float64, y float64) {}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
game := Game{}
|
||||||
|
options := goga.RunOptions{ClearColor: goga.Vec4{1, 1, 1, 0},
|
||||||
|
Resizable: true,
|
||||||
|
SetViewportOnResize: true,
|
||||||
|
ExitOnClose: true}
|
||||||
|
goga.Run(&game, &options)
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +50,7 @@ func main() {
|
|||||||
options := goga.RunOptions{ClearColor: goga.Vec4{0, 0, 0, 0},
|
options := goga.RunOptions{ClearColor: goga.Vec4{0, 0, 0, 0},
|
||||||
Resizable: true,
|
Resizable: true,
|
||||||
SetViewportOnResize: true,
|
SetViewportOnResize: true,
|
||||||
ExitOnClose: true}
|
ExitOnClose: true,
|
||||||
|
Fullscreen: true}
|
||||||
goga.Run(&game, &options)
|
goga.Run(&game, &options)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
113
demo/text/assets/victor.json
Normal file
113
demo/text/assets/victor.json
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
[
|
||||||
|
{"char":"a", "x": 0, "y": 0, "offset": 0},
|
||||||
|
{"char":"b", "x": 1, "y": 0, "offset": 0},
|
||||||
|
{"char":"c", "x": 2, "y": 0, "offset": 0},
|
||||||
|
{"char":"d", "x": 3, "y": 0, "offset": 0},
|
||||||
|
{"char":"e", "x": 4, "y": 0, "offset": 0},
|
||||||
|
{"char":"f", "x": 5, "y": 0, "offset": 0},
|
||||||
|
{"char":"g", "x": 6, "y": 0, "offset": 0},
|
||||||
|
{"char":"h", "x": 7, "y": 0, "offset": 0},
|
||||||
|
{"char":"i", "x": 8, "y": 0, "offset": 0},
|
||||||
|
{"char":"j", "x": 9, "y": 0, "offset": 0},
|
||||||
|
{"char":"k", "x": 10, "y": 0, "offset": 0},
|
||||||
|
{"char":"l", "x": 11, "y": 0, "offset": 0},
|
||||||
|
{"char":"m", "x": 12, "y": 0, "offset": 0},
|
||||||
|
{"char":"n", "x": 13, "y": 0, "offset": 0},
|
||||||
|
{"char":"o", "x": 14, "y": 0, "offset": 0},
|
||||||
|
{"char":"p", "x": 15, "y": 0, "offset": 0},
|
||||||
|
{"char":"q", "x": 16, "y": 0, "offset": 0},
|
||||||
|
{"char":"r", "x": 17, "y": 0, "offset": 0},
|
||||||
|
{"char":"s", "x": 18, "y": 0, "offset": 0},
|
||||||
|
{"char":"t", "x": 19, "y": 0, "offset": 0},
|
||||||
|
{"char":"u", "x": 20, "y": 0, "offset": 0},
|
||||||
|
{"char":"v", "x": 21, "y": 0, "offset": 0},
|
||||||
|
{"char":"w", "x": 22, "y": 0, "offset": 0},
|
||||||
|
{"char":"x", "x": 23, "y": 0, "offset": 0},
|
||||||
|
{"char":"y", "x": 24, "y": 0, "offset": 0},
|
||||||
|
{"char":"z", "x": 25, "y": 0, "offset": 0},
|
||||||
|
|
||||||
|
{"char":"A", "x": 0, "y": 0, "offset": 0},
|
||||||
|
{"char":"B", "x": 1, "y": 0, "offset": 0},
|
||||||
|
{"char":"C", "x": 2, "y": 0, "offset": 0},
|
||||||
|
{"char":"D", "x": 3, "y": 0, "offset": 0},
|
||||||
|
{"char":"E", "x": 4, "y": 0, "offset": 0},
|
||||||
|
{"char":"F", "x": 5, "y": 0, "offset": 0},
|
||||||
|
{"char":"G", "x": 6, "y": 0, "offset": 0},
|
||||||
|
{"char":"H", "x": 7, "y": 0, "offset": 0},
|
||||||
|
{"char":"I", "x": 8, "y": 0, "offset": 0},
|
||||||
|
{"char":"J", "x": 9, "y": 0, "offset": 0},
|
||||||
|
{"char":"K", "x": 10, "y": 0, "offset": 0},
|
||||||
|
{"char":"L", "x": 11, "y": 0, "offset": 0},
|
||||||
|
{"char":"M", "x": 12, "y": 0, "offset": 0},
|
||||||
|
{"char":"N", "x": 13, "y": 0, "offset": 0},
|
||||||
|
{"char":"O", "x": 14, "y": 0, "offset": 0},
|
||||||
|
{"char":"P", "x": 15, "y": 0, "offset": 0},
|
||||||
|
{"char":"Q", "x": 16, "y": 0, "offset": 0},
|
||||||
|
{"char":"R", "x": 17, "y": 0, "offset": 0},
|
||||||
|
{"char":"S", "x": 18, "y": 0, "offset": 0},
|
||||||
|
{"char":"T", "x": 19, "y": 0, "offset": 0},
|
||||||
|
{"char":"U", "x": 20, "y": 0, "offset": 0},
|
||||||
|
{"char":"V", "x": 21, "y": 0, "offset": 0},
|
||||||
|
{"char":"W", "x": 22, "y": 0, "offset": 0},
|
||||||
|
{"char":"X", "x": 23, "y": 0, "offset": 0},
|
||||||
|
{"char":"Y", "x": 24, "y": 0, "offset": 0},
|
||||||
|
{"char":"Z", "x": 25, "y": 0, "offset": 0},
|
||||||
|
|
||||||
|
{"char":"0", "x": 26, "y": 0, "offset": 0},
|
||||||
|
{"char":"1", "x": 27, "y": 0, "offset": 0},
|
||||||
|
{"char":"2", "x": 28, "y": 0, "offset": 0},
|
||||||
|
{"char":"3", "x": 29, "y": 0, "offset": 0},
|
||||||
|
{"char":"4", "x": 30, "y": 0, "offset": 0},
|
||||||
|
{"char":"5", "x": 31, "y": 0, "offset": 0},
|
||||||
|
{"char":"6", "x": 32, "y": 0, "offset": 0},
|
||||||
|
{"char":"7", "x": 33, "y": 0, "offset": 0},
|
||||||
|
{"char":"8", "x": 34, "y": 0, "offset": 0},
|
||||||
|
{"char":"9", "x": 35, "y": 0, "offset": 0},
|
||||||
|
|
||||||
|
{"char":"ö", "x": 36, "y": 0, "offset": 0},
|
||||||
|
{"char":"ä", "x": 37, "y": 0, "offset": 0},
|
||||||
|
{"char":"ü", "x": 38, "y": 0, "offset": 0},
|
||||||
|
{"char":"ß", "x": 39, "y": 0, "offset": 0},
|
||||||
|
|
||||||
|
{"char":"Ö", "x": 36, "y": 0, "offset": 0},
|
||||||
|
{"char":"Ä", "x": 37, "y": 0, "offset": 0},
|
||||||
|
{"char":"Ü", "x": 38, "y": 0, "offset": 0},
|
||||||
|
|
||||||
|
{"char":",", "x": 68, "y": 0, "offset": -0.25},
|
||||||
|
{"char":";", "x": 69, "y": 0, "offset": 0},
|
||||||
|
{"char":".", "x": 70, "y": 0, "offset": 0},
|
||||||
|
{"char":":", "x": 71, "y": 0, "offset": 0},
|
||||||
|
{"char":"-", "x": 72, "y": 0, "offset": 0},
|
||||||
|
{"char":"_", "x": 73, "y": 0, "offset": 0},
|
||||||
|
|
||||||
|
{"char":"^", "x": 40, "y": 0, "offset": 0},
|
||||||
|
{"char":"°", "x": 41, "y": 0, "offset": 0},
|
||||||
|
{"char":"!", "x": 42, "y": 0, "offset": 0},
|
||||||
|
{"char":"\"", "x": 43, "y": 0, "offset": 0},
|
||||||
|
{"char":"§", "x": 44, "y": 0, "offset": 0},
|
||||||
|
{"char":"$", "x": 45, "y": 0, "offset": 0},
|
||||||
|
{"char":"%", "x": 46, "y": 0, "offset": 0},
|
||||||
|
{"char":"&", "x": 47, "y": 0, "offset": 0},
|
||||||
|
{"char":"/", "x": 48, "y": 0, "offset": 0},
|
||||||
|
{"char":"(", "x": 49, "y": 0, "offset": 0},
|
||||||
|
{"char":")", "x": 50, "y": 0, "offset": 0},
|
||||||
|
{"char":"=", "x": 51, "y": 0, "offset": 0},
|
||||||
|
{"char":"?", "x": 52, "y": 0, "offset": 0},
|
||||||
|
{"char":"`", "x": 53, "y": 0, "offset": 0},
|
||||||
|
{"char":"²", "x": 54, "y": 0, "offset": 0},
|
||||||
|
{"char":"³", "x": 55, "y": 0, "offset": 0},
|
||||||
|
{"char":"{", "x": 56, "y": 0, "offset": 0},
|
||||||
|
{"char":"[", "x": 57, "y": 0, "offset": 0},
|
||||||
|
{"char":"]", "x": 58, "y": 0, "offset": 0},
|
||||||
|
{"char":"}", "x": 59, "y": 0, "offset": 0},
|
||||||
|
{"char":"\\", "x": 60, "y": 0, "offset": 0},
|
||||||
|
{"char":"+", "x": 61, "y": 0, "offset": 0},
|
||||||
|
{"char":"*", "x": 62, "y": 0, "offset": 0},
|
||||||
|
{"char":"~", "x": 63, "y": 0, "offset": 0},
|
||||||
|
{"char":"#", "x": 64, "y": 0, "offset": 0},
|
||||||
|
{"char":"<", "x": 65, "y": 0, "offset": 0},
|
||||||
|
{"char":">", "x": 66, "y": 0, "offset": 0},
|
||||||
|
{"char":"|", "x": 67, "y": 0, "offset": 0},
|
||||||
|
{"char":"'", "x": 68, "y": 0, "offset": 0},
|
||||||
|
{"char":"'", "x": 69, "y": 0, "offset": 0}
|
||||||
|
]
|
||||||
BIN
demo/text/assets/victor.png
Normal file
BIN
demo/text/assets/victor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
68
demo/text/text.go
Normal file
68
demo/text/text.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/DeKugelschieber/go-game"
|
||||||
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
font_path = "src/github.com/DeKugelschieber/go-game/demo/text/assets/victor.png"
|
||||||
|
font_json = "src/github.com/DeKugelschieber/go-game/demo/text/assets/victor.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Game struct{}
|
||||||
|
|
||||||
|
func (g *Game) Setup() {
|
||||||
|
// load texture
|
||||||
|
pngLoader, ok := goga.GetLoaderByExt("png").(*goga.PngLoader)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
panic("Could not get PNG loader")
|
||||||
|
}
|
||||||
|
|
||||||
|
pngLoader.KeepData = true
|
||||||
|
pngLoader.Filter = gl.NEAREST
|
||||||
|
_, err := goga.LoadRes(font_path)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pngLoader.KeepData = false
|
||||||
|
pngLoader.Filter = gl.LINEAR
|
||||||
|
|
||||||
|
// create font
|
||||||
|
tex, err := goga.GetTex("victor.png")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
font := goga.NewFont(tex, 16)
|
||||||
|
|
||||||
|
if err := font.FromJson(font_json, true); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup renderer
|
||||||
|
renderer := goga.GetTextRenderer()
|
||||||
|
renderer.Font = font
|
||||||
|
|
||||||
|
// create and add text
|
||||||
|
text := goga.NewText(font, "Hello, World!_")
|
||||||
|
text.Size = goga.Vec2{16, 16}
|
||||||
|
text.Pos = goga.Vec2{20, 20}
|
||||||
|
renderer.Prepare(text)
|
||||||
|
renderer.Add(text.Actor, text.Pos2D, text.TextComponent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Update(delta float64) {}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
game := Game{}
|
||||||
|
options := goga.RunOptions{ClearColor: goga.Vec4{0, 0, 0, 0},
|
||||||
|
Resizable: true,
|
||||||
|
SetViewportOnResize: true,
|
||||||
|
ExitOnClose: true}
|
||||||
|
goga.Run(&game, &options)
|
||||||
|
}
|
||||||
2
drop.go
2
drop.go
@@ -7,7 +7,7 @@ type Dropable interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Drops given GL objects.
|
// Drops given GL objects.
|
||||||
// Objects must implement the Dropable inteface.
|
// Objects must implement the Dropable interface.
|
||||||
func Drop(objects []Dropable) {
|
func Drop(objects []Dropable) {
|
||||||
for _, obj := range objects {
|
for _, obj := range objects {
|
||||||
obj.Drop()
|
obj.Drop()
|
||||||
|
|||||||
2
fbo.go
2
fbo.go
@@ -1,7 +1,7 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Frame Buffer Object.
|
// Frame Buffer Object.
|
||||||
|
|||||||
195
game.go
195
game.go
@@ -1,8 +1,8 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
"github.com/go-gl/glfw/v3.1/glfw"
|
"github.com/go-gl/glfw/v3.2/glfw"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -14,112 +14,8 @@ const (
|
|||||||
default_height = uint32(400)
|
default_height = uint32(400)
|
||||||
default_title = "Game"
|
default_title = "Game"
|
||||||
default_exit_on_close = true
|
default_exit_on_close = true
|
||||||
|
|
||||||
// constants for default 2D shader
|
|
||||||
Default_shader_2D_vertex_attrib = "vertex"
|
|
||||||
Default_shader_2D_texcoord_attrib = "texCoord"
|
|
||||||
Default_shader_2D_ortho = "o"
|
|
||||||
Default_shader_2D_model = "m"
|
|
||||||
Default_shader_2D_tex = "tex"
|
|
||||||
|
|
||||||
// source for 2D shader
|
|
||||||
default_shader_2d_vertex_src = `#version 130
|
|
||||||
uniform mat3 o, m;
|
|
||||||
in vec2 vertex;
|
|
||||||
in vec2 texCoord;
|
|
||||||
out vec2 tc;
|
|
||||||
void main(){
|
|
||||||
tc = texCoord;
|
|
||||||
gl_Position = vec4(o*m*vec3(vertex, 1.0), 1.0);
|
|
||||||
}`
|
|
||||||
default_shader_2d_fragment_src = `#version 130
|
|
||||||
precision highp float;
|
|
||||||
uniform sampler2D tex;
|
|
||||||
in vec2 tc;
|
|
||||||
out vec4 color;
|
|
||||||
void main(){
|
|
||||||
color = texture(tex, tc);
|
|
||||||
}`
|
|
||||||
|
|
||||||
// constants for default 3D shader
|
|
||||||
Default_shader_3D_vertex_attrib = "vertex"
|
|
||||||
Default_shader_3D_texcoord_attrib = "texCoord"
|
|
||||||
Default_shader_3D_pv = "pv"
|
|
||||||
Default_shader_3D_model = "m"
|
|
||||||
Default_shader_3D_tex = "tex"
|
|
||||||
|
|
||||||
// source for 3D shader
|
|
||||||
default_shader_3d_vertex_src = `#version 130
|
|
||||||
uniform mat4 pv, m;
|
|
||||||
in vec3 vertex;
|
|
||||||
in vec2 texCoord;
|
|
||||||
out vec2 tc;
|
|
||||||
void main(){
|
|
||||||
tc = texCoord;
|
|
||||||
gl_Position = pv*m*vec4(vertex, 1.0);
|
|
||||||
}`
|
|
||||||
default_shader_3d_fragment_src = `#version 130
|
|
||||||
precision highp float;
|
|
||||||
uniform sampler2D tex;
|
|
||||||
in vec2 tc;
|
|
||||||
out vec4 color;
|
|
||||||
void main(){
|
|
||||||
color = texture(tex, tc);
|
|
||||||
}`
|
|
||||||
|
|
||||||
// constants for default text shader
|
|
||||||
Default_shader_text_vertex_attrib = "vertex"
|
|
||||||
Default_shader_text_texcoord_attrib = "texCoord"
|
|
||||||
Default_shader_text_ortho = "o"
|
|
||||||
Default_shader_text_model = "m"
|
|
||||||
Default_shader_text_tex = "tex"
|
|
||||||
Default_shader_text_color = "color"
|
|
||||||
|
|
||||||
// source for text shader
|
|
||||||
default_shader_text_vertex_src = `#version 130
|
|
||||||
uniform mat3 o, m;
|
|
||||||
in vec2 vertex;
|
|
||||||
in vec2 texCoord;
|
|
||||||
out vec2 tc;
|
|
||||||
void main(){
|
|
||||||
tc = texCoord;
|
|
||||||
gl_Position = vec4(o*m*vec3(vertex, 1.0), 1.0);
|
|
||||||
}`
|
|
||||||
default_shader_text_fragment_src = `#version 130
|
|
||||||
precision highp float;
|
|
||||||
uniform sampler2D tex;
|
|
||||||
uniform vec4 color;
|
|
||||||
in vec2 tc;
|
|
||||||
out vec4 c;
|
|
||||||
void main(){
|
|
||||||
c = texture(tex, tc)*color;
|
|
||||||
}`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// If set in RunOptions, the function will be called on window resize.
|
|
||||||
type ResizeCallback func(width, height int)
|
|
||||||
|
|
||||||
// Run options allow to set some parameters on startup.
|
|
||||||
type RunOptions struct {
|
|
||||||
Title string
|
|
||||||
Width uint32
|
|
||||||
Height uint32
|
|
||||||
ClearColor Vec4
|
|
||||||
Resizable bool
|
|
||||||
SetViewportOnResize bool
|
|
||||||
ResizeCallbackFunc ResizeCallback
|
|
||||||
ExitOnClose bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main game object.
|
|
||||||
// Setup will be called before the main loop and after GL context has been created.
|
|
||||||
// Update will be called each frame. This can be used to switch scenes or end game on win state.
|
|
||||||
// For game logic, System should be used.
|
|
||||||
type Game interface {
|
|
||||||
Setup()
|
|
||||||
Update(float64)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
running = true
|
running = true
|
||||||
clearColor = Vec4{}
|
clearColor = Vec4{}
|
||||||
@@ -134,8 +30,36 @@ var (
|
|||||||
DefaultTextShader *Shader
|
DefaultTextShader *Shader
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// If set in RunOptions, the function will be called on window resize.
|
||||||
|
type ResizeCallback func(width, height int)
|
||||||
|
|
||||||
|
// Run options allow to set some parameters on startup.
|
||||||
|
type RunOptions struct {
|
||||||
|
Title string
|
||||||
|
Width uint32
|
||||||
|
Height uint32
|
||||||
|
ClearColor Vec4
|
||||||
|
Resizable bool
|
||||||
|
SetViewportOnResize bool
|
||||||
|
ResizeCallbackFunc ResizeCallback
|
||||||
|
ExitOnClose bool
|
||||||
|
RefreshRate int
|
||||||
|
Fullscreen bool
|
||||||
|
MonitorId uint // index
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main game object.
|
||||||
|
// Setup will be called before the main loop and after GL context has been created.
|
||||||
|
// Update will be called each frame. This can be used to switch scenes or end game on win state.
|
||||||
|
// For game logic, System should be used.
|
||||||
|
type Game interface {
|
||||||
|
Setup()
|
||||||
|
Update(float64)
|
||||||
|
}
|
||||||
|
|
||||||
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.
|
||||||
log.Print("Locking OS thread")
|
log.Print("Locking OS thread")
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
}
|
}
|
||||||
@@ -168,32 +92,52 @@ func Run(game Game, options *RunOptions) {
|
|||||||
title := default_title
|
title := default_title
|
||||||
exitOnClose := default_exit_on_close
|
exitOnClose := default_exit_on_close
|
||||||
|
|
||||||
if options != nil && options.Width > 0 {
|
|
||||||
width = options.Width
|
|
||||||
}
|
|
||||||
|
|
||||||
if options != nil && options.Height > 0 {
|
|
||||||
height = options.Height
|
|
||||||
}
|
|
||||||
|
|
||||||
if options != nil && len(options.Title) > 0 {
|
|
||||||
title = options.Title
|
|
||||||
}
|
|
||||||
|
|
||||||
if options != nil {
|
if options != nil {
|
||||||
|
if options.Width > 0 {
|
||||||
|
width = options.Width
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.Height > 0 {
|
||||||
|
height = options.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(options.Title) > 0 {
|
||||||
|
title = options.Title
|
||||||
|
}
|
||||||
|
|
||||||
exitOnClose = options.ExitOnClose
|
exitOnClose = options.ExitOnClose
|
||||||
|
|
||||||
|
if !options.Resizable {
|
||||||
|
glfw.WindowHint(glfw.Resizable, glfw.False)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if options != nil && !options.Resizable {
|
var monitor *glfw.Monitor
|
||||||
glfw.WindowHint(glfw.Resizable, glfw.False)
|
|
||||||
|
if options != nil && options.Fullscreen {
|
||||||
|
monitors := glfw.GetMonitors()
|
||||||
|
|
||||||
|
if int(options.MonitorId) < len(monitors) {
|
||||||
|
monitor = monitors[options.MonitorId]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wnd, err := glfw.CreateWindow(int(width), int(height), title, nil, nil)
|
if monitor != nil {
|
||||||
|
videoMode := monitor.GetVideoMode()
|
||||||
|
width = uint32(videoMode.Width)
|
||||||
|
height = uint32(videoMode.Height)
|
||||||
|
}
|
||||||
|
|
||||||
|
wnd, err := glfw.CreateWindow(int(width), int(height), title, monitor, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("Error creating GLFW window: " + err.Error())
|
panic("Error creating GLFW window: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options != nil && options.RefreshRate != 0 {
|
||||||
|
glfw.WindowHint(glfw.RefreshRate, options.RefreshRate)
|
||||||
|
}
|
||||||
|
|
||||||
// window event handlers
|
// window event handlers
|
||||||
wnd.SetSizeCallback(func(w *glfw.Window, width, height int) {
|
wnd.SetSizeCallback(func(w *glfw.Window, width, height int) {
|
||||||
if options == nil {
|
if options == nil {
|
||||||
@@ -211,6 +155,8 @@ func Run(game Game, options *RunOptions) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
initInput(wnd)
|
||||||
|
|
||||||
// make GL context current
|
// make GL context current
|
||||||
wnd.MakeContextCurrent()
|
wnd.MakeContextCurrent()
|
||||||
|
|
||||||
@@ -235,8 +181,8 @@ func Run(game Game, options *RunOptions) {
|
|||||||
delta := time.Duration(0)
|
delta := time.Duration(0)
|
||||||
var deltaSec float64
|
var deltaSec float64
|
||||||
|
|
||||||
for running {
|
for {
|
||||||
if exitOnClose && wnd.ShouldClose() {
|
if !running || exitOnClose && wnd.ShouldClose() {
|
||||||
cleanup()
|
cleanup()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -310,6 +256,7 @@ func initGoga(width, height int) {
|
|||||||
AddSystem(NewModelRenderer(nil, nil, false))
|
AddSystem(NewModelRenderer(nil, nil, false))
|
||||||
AddSystem(NewCulling2D(0, 0, width, height))
|
AddSystem(NewCulling2D(0, 0, width, height))
|
||||||
AddSystem(NewKeyframeRenderer(nil, nil))
|
AddSystem(NewKeyframeRenderer(nil, nil))
|
||||||
|
AddSystem(NewTextRenderer(nil, nil, nil)) // font must be set outside!
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanup() {
|
func cleanup() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
98
input.go
Normal file
98
input.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package goga
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-gl/glfw/v3.2/glfw"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
keyboardListener []KeyboardListener
|
||||||
|
mouseListener []MouseListener
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface for keyboard input events.
|
||||||
|
// Implement and register to receive keyboard input.
|
||||||
|
type KeyboardListener interface {
|
||||||
|
OnKeyEvent(glfw.Key, int, glfw.Action, glfw.ModifierKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface for mouse input events.
|
||||||
|
// Implement and register to receive mouse input.
|
||||||
|
type MouseListener interface {
|
||||||
|
OnMouseButton(glfw.MouseButton, glfw.Action, glfw.ModifierKey)
|
||||||
|
OnMouseMove(float64, float64)
|
||||||
|
OnMouseScroll(float64, float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initInput(wnd *glfw.Window) {
|
||||||
|
wnd.SetKeyCallback(keyboardCallback)
|
||||||
|
wnd.SetMouseButtonCallback(mouseButtonCallback)
|
||||||
|
wnd.SetCursorPosCallback(mouseMoveCallback)
|
||||||
|
wnd.SetScrollCallback(mouseScrollCallback)
|
||||||
|
|
||||||
|
keyboardListener = make([]KeyboardListener, 0)
|
||||||
|
mouseListener = make([]MouseListener, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func keyboardCallback(wnd *glfw.Window, key glfw.Key, code int, action glfw.Action, mod glfw.ModifierKey) {
|
||||||
|
for _, listener := range keyboardListener {
|
||||||
|
listener.OnKeyEvent(key, code, action, mod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mouseButtonCallback(wnd *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
|
||||||
|
for _, listener := range mouseListener {
|
||||||
|
listener.OnMouseButton(button, action, mod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mouseMoveCallback(wnd *glfw.Window, x float64, y float64) {
|
||||||
|
for _, listener := range mouseListener {
|
||||||
|
listener.OnMouseMove(x, float64(viewportHeight)-y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mouseScrollCallback(wnd *glfw.Window, x float64, y float64) {
|
||||||
|
for _, listener := range mouseListener {
|
||||||
|
listener.OnMouseScroll(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a new keyboard listener.
|
||||||
|
func AddKeyboardListener(listener KeyboardListener) {
|
||||||
|
keyboardListener = append(keyboardListener, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes given keyboard listener if found.
|
||||||
|
func RemoveKeyboardListener(listener KeyboardListener) {
|
||||||
|
for i, l := range keyboardListener {
|
||||||
|
if l == listener {
|
||||||
|
keyboardListener = append(keyboardListener[:i], keyboardListener[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes all registered keyboard listeners.
|
||||||
|
func RemoveAllKeyboardListener() {
|
||||||
|
keyboardListener = make([]KeyboardListener, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a new mouse listener.
|
||||||
|
func AddMouseListener(listener MouseListener) {
|
||||||
|
mouseListener = append(mouseListener, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes given mouse listener if found.
|
||||||
|
func RemoveMouseListener(listener MouseListener) {
|
||||||
|
for i, l := range mouseListener {
|
||||||
|
if l == listener {
|
||||||
|
mouseListener = append(mouseListener[:i], mouseListener[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes all registered mouse listeners.
|
||||||
|
func RemoveAllMouseListener() {
|
||||||
|
mouseListener = make([]MouseListener, 0)
|
||||||
|
}
|
||||||
32
keyframe.go
32
keyframe.go
@@ -1,7 +1,7 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
16
loader.go
16
loader.go
@@ -3,7 +3,7 @@ package goga
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
"image/png"
|
"image/png"
|
||||||
@@ -75,6 +75,13 @@ type Ply struct {
|
|||||||
IndexBuffer, VertexBuffer, TexCoordBuffer, NormalBuffer *VBO
|
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 {
|
||||||
@@ -124,13 +131,6 @@ func (p *Ply) SetExt(ext string) {
|
|||||||
p.ext = ext
|
p.ext = ext
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *PlyLoader) Load(file string) (Res, error) {
|
func (p *PlyLoader) Load(file string) (Res, error) {
|
||||||
handle, err := os.Open(file)
|
handle, err := os.Open(file)
|
||||||
defer handle.Close()
|
defer handle.Close()
|
||||||
|
|||||||
18
model.go
18
model.go
@@ -1,7 +1,7 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
scene.go
10
scene.go
@@ -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.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package goga
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|||||||
14
sprite.go
14
sprite.go
@@ -1,7 +1,7 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
51
system_util.go
Normal 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
|
||||||
|
}
|
||||||
2
tex.go
2
tex.go
@@ -1,7 +1,7 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
"image"
|
"image"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
263
text.go
263
text.go
@@ -1,69 +1,51 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
/*
|
|
||||||
import (
|
import (
|
||||||
"core"
|
|
||||||
"dp"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"geo"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
char_padding = 2
|
char_padding = 2
|
||||||
|
text_renderer_name = "textRenderer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns a new renderable text object.
|
type character struct {
|
||||||
func NewText(font *Font, text string) *Text {
|
|
||||||
t := &Text{id: core.NextId()}
|
|
||||||
t.text = text
|
|
||||||
t.index = dp.NewVBO(gl.ELEMENT_ARRAY_BUFFER)
|
|
||||||
t.vertex = dp.NewVBO(gl.ARRAY_BUFFER)
|
|
||||||
t.texCoord = dp.NewVBO(gl.ARRAY_BUFFER)
|
|
||||||
t.vao = dp.NewVAO()
|
|
||||||
t.SetText(font, text)
|
|
||||||
t.Size = geo.Vec2{1, 1}
|
|
||||||
t.Scale = geo.Vec2{1, 1}
|
|
||||||
t.Visible = true
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
type Character struct {
|
|
||||||
char byte
|
char byte
|
||||||
min, max, size geo.Vec2
|
min, max, size Vec2
|
||||||
offset float64
|
offset float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Font struct {
|
|
||||||
Tex *dp.Tex
|
|
||||||
tileSize float64
|
|
||||||
CharPadding geo.Vec2
|
|
||||||
Space, Tab, Line float64
|
|
||||||
chars []Character
|
|
||||||
}
|
|
||||||
|
|
||||||
type jsonChar struct {
|
type jsonChar struct {
|
||||||
Char string
|
Char string
|
||||||
X, Y, Offset float64
|
X, Y, Offset float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new font from texture. Characters must be added afterwards.
|
// Font represents a texture mapped font.
|
||||||
// The characters must be placed within a grid,
|
// It can be loaded from JSON together with a texture.
|
||||||
// the second parameter describes the width and height of one tile in pixel.
|
type Font struct {
|
||||||
func NewFont(tex *dp.Tex, tileSize int) *Font {
|
Tex *Tex
|
||||||
font := &Font{}
|
tileSize float64
|
||||||
|
CharPadding Vec2
|
||||||
|
Space, Tab, Line float64
|
||||||
|
chars []character
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new font for given texture.
|
||||||
|
// The tile size specifies the size of one character tile on texture.
|
||||||
|
// Characters must be added afterwards.
|
||||||
|
func NewFont(tex *Tex, tileSize float64) *Font {
|
||||||
|
font := Font{}
|
||||||
font.Tex = tex
|
font.Tex = tex
|
||||||
font.tileSize = float64(tileSize)
|
font.tileSize = tileSize
|
||||||
font.CharPadding = geo.Vec2{0.05, 0.05}
|
font.CharPadding = Vec2{0.05, 0.05}
|
||||||
font.Space = 0.3
|
font.Space = 0.3
|
||||||
font.Tab = 1.2
|
font.Tab = 1.2
|
||||||
font.Line = 1
|
font.Line = 1
|
||||||
font.chars = make([]Character, 0)
|
font.chars = make([]character, 0)
|
||||||
|
|
||||||
return font
|
return &font
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads characters from JSON file.
|
// Loads characters from JSON file.
|
||||||
@@ -82,7 +64,7 @@ func NewFont(tex *dp.Tex, tileSize int) *Font {
|
|||||||
// Where x and y start in the upper left corner of the texture, both of type int.
|
// Where x and y start in the upper left corner of the texture, both of type int.
|
||||||
// Offset is optional and can be used to move a character up or down (relative to others).
|
// Offset is optional and can be used to move a character up or down (relative to others).
|
||||||
// If cut is set to true, the characters will be true typed.
|
// If cut is set to true, the characters will be true typed.
|
||||||
func (f *Font) LoadFromJson(path string, cut bool) error {
|
func (f *Font) FromJson(path string, cut bool) error {
|
||||||
// load file content
|
// load file content
|
||||||
content, err := ioutil.ReadFile(path)
|
content, err := ioutil.ReadFile(path)
|
||||||
|
|
||||||
@@ -108,21 +90,22 @@ func (f *Font) extractChars(chars []jsonChar, cut bool) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var min, max, size geo.Vec2
|
var min, max, size Vec2
|
||||||
|
|
||||||
if !cut {
|
if !cut {
|
||||||
min = geo.Vec2{char.X * f.tileSize, char.Y * f.tileSize}
|
min = Vec2{char.X * f.tileSize, char.Y * f.tileSize}
|
||||||
max = geo.Vec2{min.X + f.tileSize, min.Y + f.tileSize}
|
max = Vec2{min.X + f.tileSize, min.Y + f.tileSize}
|
||||||
size = geo.Vec2{1, 1}
|
size = Vec2{1, 1}
|
||||||
} else {
|
} else {
|
||||||
min, max, size = f.cutChar(int(char.X), int(char.Y))
|
min, max, size = f.cutChar(int(char.X), int(char.Y))
|
||||||
}
|
}
|
||||||
|
|
||||||
f.chars = append(f.chars, Character{char.Char[0], min, max, size, char.Offset})
|
f.chars = append(f.chars, character{char.Char[0], min, max, size, char.Offset})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Font) cutChar(x, y int) (geo.Vec2, geo.Vec2, geo.Vec2) {
|
func (f *Font) cutChar(x, y int) (Vec2, Vec2, Vec2) {
|
||||||
|
// find min/max corners of character on texture
|
||||||
minX := int(f.Tex.GetSize().X)
|
minX := int(f.Tex.GetSize().X)
|
||||||
minY := int(f.Tex.GetSize().Y)
|
minY := int(f.Tex.GetSize().Y)
|
||||||
maxX := 0
|
maxX := 0
|
||||||
@@ -151,22 +134,21 @@ func (f *Font) cutChar(x, y int) (geo.Vec2, geo.Vec2, geo.Vec2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add padding
|
||||||
minX -= char_padding
|
minX -= char_padding
|
||||||
maxX += char_padding
|
maxX += char_padding
|
||||||
minY -= char_padding
|
minY -= char_padding
|
||||||
maxY += char_padding
|
maxY += char_padding
|
||||||
|
|
||||||
texSize := f.Tex.GetSize()
|
texSize := f.Tex.GetSize()
|
||||||
min := geo.Vec2{float64(minX) / texSize.X, float64(maxY) / texSize.Y}
|
min := Vec2{float64(minX) / texSize.X, float64(maxY) / texSize.Y}
|
||||||
max := geo.Vec2{float64(maxX) / texSize.X, float64(minY) / texSize.Y}
|
max := Vec2{float64(maxX) / texSize.X, float64(minY) / texSize.Y}
|
||||||
|
size := Vec2{float64(maxX-minX) / f.tileSize, float64(maxY-minY) / f.tileSize}
|
||||||
// size
|
|
||||||
size := geo.Vec2{float64(maxX-minX) / f.tileSize, float64(maxY-minY) / f.tileSize}
|
|
||||||
|
|
||||||
return min, max, size
|
return min, max, size
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Font) getChar(char byte) *Character {
|
func (f *Font) getChar(char byte) *character {
|
||||||
for _, character := range f.chars {
|
for _, character := range f.chars {
|
||||||
if character.char == char {
|
if character.char == char {
|
||||||
return &character
|
return &character
|
||||||
@@ -176,30 +158,55 @@ func (f *Font) getChar(char byte) *Character {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Text struct {
|
// Renderable text component.
|
||||||
*Actor
|
// Use together with Text and create using NewText().
|
||||||
*Pos2D
|
type TextComponent struct {
|
||||||
|
Color Vec4
|
||||||
|
|
||||||
id int
|
text string
|
||||||
text string
|
bounds Vec2
|
||||||
bounds geo.Vec2
|
index, vertex, texCoord *VBO
|
||||||
|
vao *VAO
|
||||||
index, vertex, texCoord *dp.VBO
|
|
||||||
vao *dp.VAO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes GL buffers bound to this text.
|
// Deletes GL buffers bound to this text component.
|
||||||
func (t *Text) Drop() {
|
func (t *TextComponent) Drop() {
|
||||||
t.index.Drop()
|
t.index.Drop()
|
||||||
t.vertex.Drop()
|
t.vertex.Drop()
|
||||||
t.texCoord.Drop()
|
t.texCoord.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
|
||||||
|
|
||||||
indices := make([]uint32, len(text)*6)
|
indices := make([]uint32, len(text)*6)
|
||||||
vertices := make([]float32, len(text)*8)
|
vertices := make([]float32, len(text)*8)
|
||||||
texCoords := make([]float32, len(text)*8)
|
texCoords := make([]float32, len(text)*8)
|
||||||
@@ -221,7 +228,7 @@ func (t *Text) SetText(font *Font, text string) {
|
|||||||
|
|
||||||
// create vertices/texCoords
|
// create vertices/texCoords
|
||||||
index = 0
|
index = 0
|
||||||
offset := geo.Vec2{}
|
offset := Vec2{}
|
||||||
var width, height float64
|
var width, height float64
|
||||||
|
|
||||||
for i := 0; i < len(text)*8 && int(index) < len(text); i += 8 {
|
for i := 0; i < len(text)*8 && int(index) < len(text); i += 8 {
|
||||||
@@ -285,18 +292,14 @@ func (t *Text) SetText(font *Font, text string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.bounds = geo.Vec2{width, height}
|
t.bounds = Vec2{width, height}
|
||||||
|
|
||||||
// fill GL buffer
|
// fill GL buffer
|
||||||
t.index.Fill(gl.Ptr(indices[:chars*6]), 4, chars*6, gl.STATIC_DRAW)
|
t.index.Fill(gl.Ptr(indices[:chars*6]), 4, chars*6, gl.STATIC_DRAW)
|
||||||
t.vertex.Fill(gl.Ptr(vertices[:chars*8]), 4, chars*8, gl.STATIC_DRAW)
|
t.vertex.Fill(gl.Ptr(vertices[:chars*8]), 4, chars*8, gl.STATIC_DRAW)
|
||||||
t.texCoord.Fill(gl.Ptr(texCoords[:chars*8]), 4, chars*8, gl.STATIC_DRAW)
|
t.texCoord.Fill(gl.Ptr(texCoords[:chars*8]), 4, chars*8, gl.STATIC_DRAW)
|
||||||
|
|
||||||
util.CheckGLError()
|
CheckGLError()
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Text) GetId() int {
|
|
||||||
return t.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the text as string.
|
// Returns the text as string.
|
||||||
@@ -305,98 +308,130 @@ func (t *Text) GetText() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns bounds of text, which is the size of characters.
|
// Returns bounds of text, which is the size of characters.
|
||||||
func (t *Text) GetBounds() geo.Vec2 {
|
func (t *Text) GetBounds() Vec2 {
|
||||||
return geo.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 {
|
type TextRenderer struct {
|
||||||
Pos2D
|
Pos2D
|
||||||
|
|
||||||
Shader *dp.Shader
|
Shader *Shader
|
||||||
Camera *Camera
|
Camera *Camera
|
||||||
Font *Font
|
Font *Font
|
||||||
Color geo.Vec4
|
texts []Text
|
||||||
texts []*Text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new text renderer using given shader, camera and font.
|
// Creates a new text renderer using given shader, camera and font.
|
||||||
// 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 NewTextRenderer(shader *dp.Shader, camera *Camera, font *Font) *TextRenderer {
|
func NewTextRenderer(shader *Shader, camera *Camera, font *Font) *TextRenderer {
|
||||||
|
if shader == nil {
|
||||||
|
shader = DefaultTextShader
|
||||||
|
}
|
||||||
|
|
||||||
|
if camera == nil {
|
||||||
|
camera = DefaultCamera
|
||||||
|
}
|
||||||
|
|
||||||
renderer := &TextRenderer{}
|
renderer := &TextRenderer{}
|
||||||
renderer.Shader = shader
|
renderer.Shader = shader
|
||||||
renderer.Camera = camera
|
renderer.Camera = camera
|
||||||
renderer.Font = font
|
renderer.Font = font
|
||||||
renderer.Color = geo.Vec4{1, 1, 1, 1}
|
renderer.texts = make([]Text, 0)
|
||||||
renderer.texts = make([]*Text, 0)
|
renderer.Size = Vec2{1, 1}
|
||||||
renderer.Size = geo.Vec2{1, 1}
|
renderer.Scale = Vec2{1, 1}
|
||||||
renderer.Scale = geo.Vec2{1, 1}
|
|
||||||
|
|
||||||
return renderer
|
return renderer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepares a text for rendering.
|
// Prepares given text for rendering.
|
||||||
func (r *TextRenderer) Prepare(text *Text) {
|
func (r *TextRenderer) Prepare(text *Text) {
|
||||||
text.vao = dp.NewVAO()
|
text.vao = NewVAO()
|
||||||
text.vao.Bind()
|
text.vao.Bind()
|
||||||
r.Shader.EnableVertexAttribArrays()
|
r.Shader.EnableVertexAttribArrays()
|
||||||
text.index.Bind()
|
text.index.Bind()
|
||||||
text.vertex.Bind()
|
text.vertex.Bind()
|
||||||
text.vertex.AttribPointer(r.Shader.GetAttribLocation(TEXTRENDERER_VERTEX_ATTRIB), 2, gl.FLOAT, false, 0)
|
text.vertex.AttribPointer(r.Shader.GetAttribLocation(Default_shader_text_vertex_attrib), 2, gl.FLOAT, false, 0)
|
||||||
text.texCoord.Bind()
|
text.texCoord.Bind()
|
||||||
text.texCoord.AttribPointer(r.Shader.GetAttribLocation(TEXTRENDERER_TEXCOORD_ATTRIB), 2, gl.FLOAT, false, 0)
|
text.texCoord.AttribPointer(r.Shader.GetAttribLocation(Default_shader_text_texcoord_attrib), 2, gl.FLOAT, false, 0)
|
||||||
text.vao.Unbind()
|
text.vao.Unbind()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds text to the renderer.
|
// Frees recources created by text component.
|
||||||
func (r *TextRenderer) Add(text *Text) {
|
// This is called automatically when system gets removed.
|
||||||
r.texts = append(r.texts, text)
|
func (r *TextRenderer) Cleanup() {
|
||||||
|
for _, text := range r.texts {
|
||||||
|
text.Drop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns text by ID.
|
// Adds text to the renderer.
|
||||||
func (r *TextRenderer) Get(id int) *Text {
|
func (r *TextRenderer) Add(actor *Actor, pos *Pos2D, text *TextComponent) bool {
|
||||||
|
id := actor.GetId()
|
||||||
|
|
||||||
for _, text := range r.texts {
|
for _, text := range r.texts {
|
||||||
if text.GetId() == id {
|
if id == text.Actor.GetId() {
|
||||||
return text
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
r.texts = append(r.texts, Text{actor, pos, text})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes text from renderer.
|
||||||
|
func (r *TextRenderer) Remove(actor *Actor) bool {
|
||||||
|
return r.RemoveById(actor.GetId())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes text from renderer by ID.
|
// Removes text from renderer by ID.
|
||||||
func (r *TextRenderer) Remove(id int) *Text {
|
func (r *TextRenderer) RemoveById(id ActorId) bool {
|
||||||
for i, text := range r.texts {
|
for i, text := range r.texts {
|
||||||
if text.GetId() == id {
|
if text.Actor.GetId() == id {
|
||||||
r.texts = append(r.texts[:i], r.texts[i+1:]...)
|
r.texts = append(r.texts[:i], r.texts[i+1:]...)
|
||||||
return text
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes all sprites.
|
// Removes all texts.
|
||||||
func (r *TextRenderer) Clear() {
|
func (r *TextRenderer) RemoveAll() {
|
||||||
r.texts = make([]*Text, 0)
|
r.texts = make([]Text, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renders sprites.
|
// Returns number of texts.
|
||||||
func (r *TextRenderer) Render() {
|
func (r *TextRenderer) Len() int {
|
||||||
|
return len(r.texts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *TextRenderer) GetName() string {
|
||||||
|
return text_renderer_name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renders texts.
|
||||||
|
func (r *TextRenderer) Update(delta float64) {
|
||||||
|
if r.Font == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.Shader.Bind()
|
r.Shader.Bind()
|
||||||
r.Shader.SendMat3(TEXTRENDERER_ORTHO, *geo.MultMat3(r.Camera.CalcOrtho(), r.CalcModel()))
|
r.Shader.SendMat3(Default_shader_text_ortho, *MultMat3(r.Camera.CalcOrtho(), r.CalcModel()))
|
||||||
r.Shader.SendUniform1i(TEXTRENDERER_TEX, 0)
|
r.Shader.SendUniform1i(Default_shader_text_tex, 0)
|
||||||
r.Shader.SendUniform4f(TEXTRENDERER_COLOR, float32(r.Color.X), float32(r.Color.Y), float32(r.Color.Z), float32(r.Color.W))
|
|
||||||
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.SendMat3(TEXTRENDERER_MODEL, *r.texts[i].CalcModel())
|
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, *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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
2
vao.go
2
vao.go
@@ -1,7 +1,7 @@
|
|||||||
package goga
|
package goga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-gl/gl/v4.5-core/gl"
|
"github.com/go-gl/gl/v3.2-core/gl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Vertex Array Object.
|
// Vertex Array Object.
|
||||||
|
|||||||
Reference in New Issue
Block a user