From 139e668233eb0600d64a874b579c103478ed0574 Mon Sep 17 00:00:00 2001 From: Marvin Blum Date: Sat, 7 May 2016 20:26:36 +0200 Subject: [PATCH] Removed shader, added 3D rendering (no demo yet, coming next), started bitmap font rendering, a few fixes and improvements. --- README.md | 8 + demo/model/assets/cube.ply | 53 +++++ demo/model/assets/cube.png | Bin 0 -> 5810 bytes game.go | 117 +++++++++-- loader.go | 19 ++ model.go | 193 ++++++++++++++++++ res_util.go | 18 ++ shader/basic2D.fs | 12 -- shader/basic2D.vs | 13 -- shader/basic3D.fs | 12 -- shader/basic3D.vs | 13 -- shader/text.fs | 13 -- shader/text.vs | 13 -- sprite.go | 29 +-- text.go | 402 +++++++++++++++++++++++++++++++++++++ 15 files changed, 809 insertions(+), 106 deletions(-) create mode 100644 demo/model/assets/cube.ply create mode 100644 demo/model/assets/cube.png create mode 100644 model.go delete mode 100644 shader/basic2D.fs delete mode 100644 shader/basic2D.vs delete mode 100644 shader/basic3D.fs delete mode 100644 shader/basic3D.vs delete mode 100644 shader/text.fs delete mode 100644 shader/text.vs create mode 100644 text.go diff --git a/README.md b/README.md index 9132c1c..c5e4d4f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,11 @@ Game engine written in Go using OpenGL and GLFW. Mostly for 2D rendering, but al ## Install +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/glfw/v3.1/glfw go get github.com/DeKugelschieber/go-game ``` @@ -23,3 +27,7 @@ You can find some examples within the demo folder. For full reference visit: htt - 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. + +## License + +MIT diff --git a/demo/model/assets/cube.ply b/demo/model/assets/cube.ply new file mode 100644 index 0000000..fda7427 --- /dev/null +++ b/demo/model/assets/cube.ply @@ -0,0 +1,53 @@ +ply +format ascii 1.0 +comment Created by Blender 2.69 (sub 0) - www.blender.org, source file: '' +element vertex 26 +property float x +property float y +property float z +property float nx +property float ny +property float nz +property float s +property float t +element face 12 +property list uchar uint vertex_indices +end_header +1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000 0.499999 0.500000 +1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000 0.499999 0.749956 +-1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000 0.250043 0.749957 +1.000000 0.999999 1.000000 -0.000000 -0.000000 1.000000 0.499998 0.250043 +-1.000000 1.000000 1.000000 -0.000000 -0.000000 1.000000 0.250041 0.250044 +0.999999 -1.000001 1.000000 -0.000000 -0.000000 1.000000 0.499996 0.000087 +1.000000 1.000000 -1.000000 1.000000 0.000000 -0.000000 0.749956 0.749956 +1.000000 0.999999 1.000000 1.000000 0.000000 -0.000000 0.749956 0.999913 +1.000000 -1.000000 -1.000000 1.000000 0.000000 -0.000000 0.499999 0.749956 +1.000000 -1.000000 -1.000000 -0.000000 -1.000000 -0.000000 0.499999 0.749956 +0.999999 -1.000001 1.000000 -0.000000 -1.000000 -0.000000 0.500000 0.999913 +-1.000000 -1.000000 -1.000000 -0.000000 -1.000000 -0.000000 0.250043 0.749957 +-1.000000 -1.000000 -1.000000 -1.000000 0.000000 -0.000000 0.250043 0.749957 +-1.000000 -1.000000 1.000000 -1.000000 0.000000 -0.000000 0.250043 0.999913 +-1.000000 1.000000 1.000000 -1.000000 0.000000 -0.000000 0.000087 0.999913 +1.000000 0.999999 1.000000 0.000000 1.000000 0.000000 0.499998 0.250043 +1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000 0.499999 0.500000 +-1.000000 1.000000 1.000000 0.000000 1.000000 0.000000 0.250041 0.250044 +-1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000 0.250042 0.500001 +1.000000 0.999999 1.000000 1.000000 -0.000001 0.000000 0.749956 0.999913 +0.999999 -1.000001 1.000000 1.000000 -0.000001 0.000000 0.500000 0.999913 +1.000000 -1.000000 -1.000000 1.000000 -0.000001 0.000000 0.499999 0.749956 +-1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000 0.250042 0.500001 +-1.000000 -1.000000 1.000000 0.000000 -0.000000 1.000000 0.250040 0.000088 +-1.000000 1.000000 -1.000000 -1.000000 0.000000 -0.000000 0.000087 0.749957 +-1.000000 -1.000000 1.000000 -0.000000 -1.000000 0.000000 0.250043 0.999913 +3 0 1 2 +3 3 4 5 +3 6 7 8 +3 9 10 11 +3 12 13 14 +3 15 16 17 +3 18 0 2 +3 19 20 21 +3 16 22 17 +3 4 23 5 +3 24 12 14 +3 10 25 11 diff --git a/demo/model/assets/cube.png b/demo/model/assets/cube.png new file mode 100644 index 0000000000000000000000000000000000000000..530cdd44c98edba3adbe2a89294347bb010a6fff GIT binary patch literal 5810 zcmeH}KS&%w6vp3O4)r`PIf)#Hpbi!ZK@o)%TDg(+yo)GeQYcYK>_kLSAwd)eO%YLR z|6OeN)FliQ6hS~2_d&2qMRGFo}vcnw{j)@Psns2jbk ze;0f>H@5oz57gZbC3)|~Rt38l-w%A8*$_}E2Q19|(*Rb*Fo0ib$tql{KU|OKXlV+r zC)d%PqMQQvbJyWTJ~ae)ELAflDAy#)rBRHQwWi<{qshuCaDvgr5%DyuU?Z}9-tze? zZ2Wtb)--F_SqfHhDr&*rU z=GwB2Zc|3#lx?awA~+lthT@1Q28Z&2S769S^Va1s`x}|~4t>>6fIn}<7v-WTIvNvx zj7^z1#iopbVNj){Z5~++gNi5%I2NfsMXmxpxeT$cXBCT(5BSP;6qtf5GMlXK3Uhxw6r*LWDfoS1zI`alDR6?(g&mRO%$HE?=RppJ_rkzdA|MW9 zd#gU&f+qZ(Gh{hOA)0U|YYFd@%Lnw7Q{Z|;M|V?jf)|CIZHE{6l%U-8tipbZ(X!SQ nT%pmsB}F*}PB8kv8 maxX { + maxX = rx + } + + if ry < minY { + minY = ry + } else if ry > maxY { + maxY = ry + } + } + } + + minX -= char_padding + maxX += char_padding + minY -= char_padding + maxY += char_padding + + texSize := f.Tex.GetSize() + min := geo.Vec2{float64(minX) / texSize.X, float64(maxY) / texSize.Y} + max := geo.Vec2{float64(maxX) / texSize.X, float64(minY) / texSize.Y} + + // size + size := geo.Vec2{float64(maxX-minX) / f.tileSize, float64(maxY-minY) / f.tileSize} + + return min, max, size +} + +func (f *Font) getChar(char byte) *Character { + for _, character := range f.chars { + if character.char == char { + return &character + } + } + + return nil +} + +type Text struct { + *Actor + *Pos2D + + id int + text string + bounds geo.Vec2 + + index, vertex, texCoord *dp.VBO + vao *dp.VAO +} + +// Deletes GL buffers bound to this text. +func (t *Text) Drop() { + t.index.Drop() + t.vertex.Drop() + t.texCoord.Drop() + t.vao.Drop() +} + +// Sets the given string as text and (re)creates buffers. +func (t *Text) SetText(font *Font, text string) { + t.text = text + + indices := make([]uint32, len(text)*6) + vertices := make([]float32, len(text)*8) + texCoords := make([]float32, len(text)*8) + chars := 0 + + // create indices + var index uint32 = 0 + + for i := 0; i < len(text)*6; i += 6 { + indices[i] = index + indices[i+1] = index + 1 + indices[i+2] = index + 2 + indices[i+3] = index + 1 + indices[i+4] = index + 2 + indices[i+5] = index + 3 + + index += 4 + } + + // create vertices/texCoords + index = 0 + offset := geo.Vec2{} + var width, height float64 + + for i := 0; i < len(text)*8 && int(index) < len(text); i += 8 { + c := font.getChar(text[index]) + index++ + + // whitespace and new line + if text[index-1] == ' ' { + offset.X += font.Space + i -= 8 + continue + } + + if text[index-1] == '\n' { + offset.X = 0 + offset.Y -= font.Line + i -= 8 + continue + } + + if text[index-1] == '\t' { + offset.X += font.Tab + i -= 8 + continue + } + + // character not found + if c == nil { + i -= 8 + continue + } + + // usual character + vertices[i] = float32(offset.X) + vertices[i+1] = float32(offset.Y + c.offset) + vertices[i+2] = float32(offset.X + c.size.X) + vertices[i+3] = float32(offset.Y + c.offset) + vertices[i+4] = float32(offset.X) + vertices[i+5] = float32(offset.Y + c.size.Y + c.offset) + vertices[i+6] = float32(offset.X + c.size.X) + vertices[i+7] = float32(offset.Y + c.size.Y + c.offset) + + texCoords[i] = float32(c.min.X) + texCoords[i+1] = float32(c.min.Y) + texCoords[i+2] = float32(c.max.X) + texCoords[i+3] = float32(c.min.Y) + texCoords[i+4] = float32(c.min.X) + texCoords[i+5] = float32(c.max.Y) + texCoords[i+6] = float32(c.max.X) + texCoords[i+7] = float32(c.max.Y) + + offset.X += c.size.X + font.CharPadding.X + chars++ + + if offset.X > width { + width = offset.X + } + + if offset.Y*-1+font.Line > height { + height = offset.Y*-1 + font.Line + } + } + + t.bounds = geo.Vec2{width, height} + + // fill GL buffer + 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.texCoord.Fill(gl.Ptr(texCoords[:chars*8]), 4, chars*8, gl.STATIC_DRAW) + + util.CheckGLError() +} + +func (t *Text) GetId() int { + return t.id +} + +// Returns the text as string. +func (t *Text) GetText() string { + return t.text +} + +// Returns bounds of text, which is the size of characters. +func (t *Text) GetBounds() geo.Vec2 { + return geo.Vec2{t.bounds.X * t.Size.X * t.Scale.X, t.bounds.Y * t.Size.Y * t.Scale.Y} +} + +type TextRenderer struct { + Pos2D + + Shader *dp.Shader + Camera *Camera + Font *Font + Color geo.Vec4 + 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 *dp.Shader, camera *Camera, font *Font) *TextRenderer { + renderer := &TextRenderer{} + renderer.Shader = shader + renderer.Camera = camera + renderer.Font = font + renderer.Color = geo.Vec4{1, 1, 1, 1} + renderer.texts = make([]*Text, 0) + renderer.Size = geo.Vec2{1, 1} + renderer.Scale = geo.Vec2{1, 1} + + return renderer +} + +// Prepares a text for rendering. +func (r *TextRenderer) Prepare(text *Text) { + text.vao = dp.NewVAO() + text.vao.Bind() + r.Shader.EnableVertexAttribArrays() + text.index.Bind() + text.vertex.Bind() + text.vertex.AttribPointer(r.Shader.GetAttribLocation(TEXTRENDERER_VERTEX_ATTRIB), 2, gl.FLOAT, false, 0) + text.texCoord.Bind() + text.texCoord.AttribPointer(r.Shader.GetAttribLocation(TEXTRENDERER_TEXCOORD_ATTRIB), 2, gl.FLOAT, false, 0) + text.vao.Unbind() +} + +// Adds text to the renderer. +func (r *TextRenderer) Add(text *Text) { + r.texts = append(r.texts, text) +} + +// Returns text by ID. +func (r *TextRenderer) Get(id int) *Text { + for _, text := range r.texts { + if text.GetId() == id { + return text + } + } + + return nil +} + +// Removes text from renderer by ID. +func (r *TextRenderer) Remove(id int) *Text { + for i, text := range r.texts { + if text.GetId() == id { + r.texts = append(r.texts[:i], r.texts[i+1:]...) + return text + } + } + + return nil +} + +// Removes all sprites. +func (r *TextRenderer) Clear() { + r.texts = make([]*Text, 0) +} + +// Renders sprites. +func (r *TextRenderer) Render() { + r.Shader.Bind() + r.Shader.SendMat3(TEXTRENDERER_ORTHO, *geo.MultMat3(r.Camera.CalcOrtho(), r.CalcModel())) + r.Shader.SendUniform1i(TEXTRENDERER_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() + + for i := range r.texts { + if !r.texts[i].Visible { + continue + } + + r.texts[i].vao.Bind() + r.Shader.SendMat3(TEXTRENDERER_MODEL, *r.texts[i].CalcModel()) + + gl.DrawElements(gl.TRIANGLES, r.texts[i].index.Size(), gl.UNSIGNED_INT, nil) + } +} +*/