From 1c3273e0a61dff3bdc9487590db79cef9911cc43 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Mon, 8 Dec 2014 04:22:50 +0900 Subject: [PATCH] Refactoring: removing new* functions --- graphics/opengl/context.go | 56 +++++++--------- graphics/opengl/ids.go | 24 +++---- .../opengl/internal/shader/drawtexture.go | 6 +- graphics/opengl/internal/shader/program.go | 64 ++++++------------- .../opengl/internal/shader/texturequad.go | 8 +-- graphics/opengl/rendertarget.go | 5 +- graphics/opengl/texture.go | 13 ++-- ui/glfw/canvas.go | 31 +-------- ui/glfw/keyboard.go | 17 +---- ui/glfw/ui.go | 32 +++++++++- 10 files changed, 103 insertions(+), 153 deletions(-) diff --git a/graphics/opengl/context.go b/graphics/opengl/context.go index 6e90ed58e..f44282afe 100644 --- a/graphics/opengl/context.go +++ b/graphics/opengl/context.go @@ -5,40 +5,16 @@ import ( "github.com/hajimehoshi/ebiten/graphics" "github.com/hajimehoshi/ebiten/graphics/matrix" "github.com/hajimehoshi/ebiten/ui" - "sync" ) type ContextUpdater struct { context *context } -func NewContextUpdater(screenWidth, screenHeight, screenScale int) *ContextUpdater { - return &ContextUpdater{ - context: newContext(screenWidth, screenHeight, screenScale), - } -} - -func (u *ContextUpdater) Update(drawer ui.Drawer) error { - return u.context.update(drawer) -} - -var onceInit sync.Once - -type context struct { - screenId graphics.RenderTargetID - defaultId graphics.RenderTargetID - currentId graphics.RenderTargetID - screenWidth int - screenHeight int - screenScale int -} - -func newContext(screenWidth, screenHeight, screenScale int) *context { - onceInit.Do(func() { - gl.Init() - gl.Enable(gl.TEXTURE_2D) - gl.Enable(gl.BLEND) - }) +func Initialize(screenWidth, screenHeight, screenScale int) (*ContextUpdater, error) { + gl.Init() + gl.Enable(gl.TEXTURE_2D) + gl.Enable(gl.BLEND) c := &context{ screenWidth: screenWidth, @@ -47,22 +23,34 @@ func newContext(screenWidth, screenHeight, screenScale int) *context { } // The defualt framebuffer should be 0. - defaultRenderTarget := &renderTarget{ + c.defaultId = idsInstance.addRenderTarget(&renderTarget{ width: screenWidth * screenScale, height: screenHeight * screenScale, flipY: true, - } - c.defaultId = idsInstance.addRenderTarget(defaultRenderTarget) + }) var err error - c.screenId, err = idsInstance.newRenderTarget(screenWidth, screenHeight, graphics.FilterNearest) + c.screenId, err = idsInstance.createRenderTarget(screenWidth, screenHeight, graphics.FilterNearest) if err != nil { - panic("opengl.newContext: initializing the offscreen failed: " + err.Error()) + return nil, err } c.ResetOffscreen() c.Clear() - return c + return &ContextUpdater{c}, nil +} + +func (u *ContextUpdater) Update(drawer ui.Drawer) error { + return u.context.update(drawer) +} + +type context struct { + screenId graphics.RenderTargetID + defaultId graphics.RenderTargetID + currentId graphics.RenderTargetID + screenWidth int + screenHeight int + screenScale int } func (c *context) dispose() { diff --git a/graphics/opengl/ids.go b/graphics/opengl/ids.go index 346b2ede7..457039e21 100644 --- a/graphics/opengl/ids.go +++ b/graphics/opengl/ids.go @@ -27,11 +27,11 @@ var idsInstance = &ids{ } func NewRenderTargetID(width, height int, filter graphics.Filter) (graphics.RenderTargetID, error) { - return idsInstance.newRenderTarget(width, height, filter) + return idsInstance.createRenderTarget(width, height, filter) } func NewTextureID(img image.Image, filter graphics.Filter) (graphics.TextureID, error) { - return idsInstance.newTexture(img, filter) + return idsInstance.createTexture(img, filter) } func (i *ids) textureAt(id graphics.TextureID) *texture { @@ -52,8 +52,8 @@ func (i *ids) toTexture(id graphics.RenderTargetID) graphics.TextureID { return i.renderTargetToTexture[id] } -func (i *ids) newTexture(img image.Image, filter graphics.Filter) (graphics.TextureID, error) { - texture, err := newTextureFromImage(img, filter) +func (i *ids) createTexture(img image.Image, filter graphics.Filter) (graphics.TextureID, error) { + texture, err := createTextureFromImage(img, filter) if err != nil { return 0, err } @@ -66,12 +66,12 @@ func (i *ids) newTexture(img image.Image, filter graphics.Filter) (graphics.Text return textureId, nil } -func (i *ids) newRenderTarget(width, height int, filter graphics.Filter) (graphics.RenderTargetID, error) { - texture, err := newTexture(width, height, filter) +func (i *ids) createRenderTarget(width, height int, filter graphics.Filter) (graphics.RenderTargetID, error) { + texture, err := createTexture(width, height, filter) if err != nil { return 0, err } - framebuffer := newFramebuffer(gl.Texture(texture.native)) + framebuffer := createFramebuffer(gl.Texture(texture.native)) // The current binded framebuffer can be changed. i.currentRenderTargetId = -1 r := &renderTarget{ @@ -128,18 +128,12 @@ func (i *ids) fillRenderTarget(id graphics.RenderTargetID, r, g, b uint8) { gl.Clear(gl.COLOR_BUFFER_BIT) } -func (i *ids) drawTexture( - target graphics.RenderTargetID, - id graphics.TextureID, - parts []graphics.TexturePart, - geo matrix.Geometry, - color matrix.Color) { +func (i *ids) drawTexture(target graphics.RenderTargetID, id graphics.TextureID, parts []graphics.TexturePart, geo matrix.Geometry, color matrix.Color) { texture := i.textureAt(id) i.setViewportIfNeeded(target) r := i.renderTargetAt(target) projectionMatrix := r.projectionMatrix() - quads := shader.TextureQuads(parts, texture.width, texture.height) - shader.DrawTexture(texture.native, projectionMatrix, quads, geo, color) + shader.DrawTexture(texture.native, texture.width, texture.height, projectionMatrix, parts, geo, color) } func (i *ids) setViewportIfNeeded(id graphics.RenderTargetID) { diff --git a/graphics/opengl/internal/shader/drawtexture.go b/graphics/opengl/internal/shader/drawtexture.go index f84e99866..0afc79166 100644 --- a/graphics/opengl/internal/shader/drawtexture.go +++ b/graphics/opengl/internal/shader/drawtexture.go @@ -2,6 +2,7 @@ package shader import ( "github.com/go-gl/gl" + "github.com/hajimehoshi/ebiten/graphics" "github.com/hajimehoshi/ebiten/graphics/matrix" "sync" ) @@ -18,14 +19,15 @@ func glMatrix(matrix [4][4]float64) [16]float32 { var once sync.Once -func DrawTexture(native gl.Texture, projectionMatrix [4][4]float64, quads []TextureQuad, geo matrix.Geometry, color matrix.Color) { +func DrawTexture(native gl.Texture, width, height int, projectionMatrix [4][4]float64, parts []graphics.TexturePart, geo matrix.Geometry, color matrix.Color) { once.Do(func() { initialize() }) - if len(quads) == 0 { + if len(parts) == 0 { return } + quads := textureQuads(parts, width, height) // TODO: Check performance shaderProgram := use(glMatrix(projectionMatrix), geo, color) diff --git a/graphics/opengl/internal/shader/program.go b/graphics/opengl/internal/shader/program.go index f37d0a59b..ab181418b 100644 --- a/graphics/opengl/internal/shader/program.go +++ b/graphics/opengl/internal/shader/program.go @@ -43,62 +43,40 @@ func initialize() { programColorMatrix.native.Use() } -type qualifierVariableType int +// NOTE: This caches are now used only for programColorMatrix +var attribLocationCache = map[string]gl.AttribLocation{} +var uniformLocationCache = map[string]gl.UniformLocation{} -const ( - qualifierVariableTypeAttribute qualifierVariableType = iota - qualifierVariableTypeUniform -) - -var ( - shaderLocationCache = map[qualifierVariableType]map[string]gl.AttribLocation{ - qualifierVariableTypeAttribute: {}, - qualifierVariableTypeUniform: {}, - } -) - -func getLocation(program gl.Program, name string, qvType qualifierVariableType) gl.AttribLocation { - if location, ok := shaderLocationCache[qvType][name]; ok { +func getAttributeLocation(program gl.Program, name string) gl.AttribLocation { + if location, ok := attribLocationCache[name]; ok { return location } - - location := gl.AttribLocation(-1) - switch qvType { - case qualifierVariableTypeAttribute: - location = program.GetAttribLocation(name) - case qualifierVariableTypeUniform: - location = gl.AttribLocation(program.GetUniformLocation(name)) - default: - panic("no reach") - } - if location == -1 { - panic("GetAttribLocation failed") - } - shaderLocationCache[qvType][name] = location - + location := program.GetAttribLocation(name) + attribLocationCache[name] = location return location } -func getAttributeLocation(program gl.Program, name string) gl.AttribLocation { - return getLocation(program, name, qualifierVariableTypeAttribute) -} - func getUniformLocation(program gl.Program, name string) gl.UniformLocation { - return gl.UniformLocation(getLocation(program, name, qualifierVariableTypeUniform)) + if location, ok := uniformLocationCache[name]; ok { + return location + } + location := program.GetUniformLocation(name) + uniformLocationCache[name] = location + return location } -func use(projectionMatrix [16]float32, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) gl.Program { +func use(projectionMatrix [16]float32, geo matrix.Geometry, color matrix.Color) gl.Program { // TODO: Check the performance. program := programColorMatrix getUniformLocation(program.native, "projection_matrix").UniformMatrix4fv(false, projectionMatrix) - a := float32(geometryMatrix.Elements[0][0]) - b := float32(geometryMatrix.Elements[0][1]) - c := float32(geometryMatrix.Elements[1][0]) - d := float32(geometryMatrix.Elements[1][1]) - tx := float32(geometryMatrix.Elements[0][2]) - ty := float32(geometryMatrix.Elements[1][2]) + a := float32(geo.Elements[0][0]) + b := float32(geo.Elements[0][1]) + c := float32(geo.Elements[1][0]) + d := float32(geo.Elements[1][1]) + tx := float32(geo.Elements[0][2]) + ty := float32(geo.Elements[1][2]) glModelviewMatrix := [...]float32{ a, c, 0, 0, b, d, 0, 0, @@ -112,7 +90,7 @@ func use(projectionMatrix [16]float32, geometryMatrix matrix.Geometry, colorMatr e := [4][5]float32{} for i := 0; i < 4; i++ { for j := 0; j < 5; j++ { - e[i][j] = float32(colorMatrix.Elements[i][j]) + e[i][j] = float32(color.Elements[i][j]) } } diff --git a/graphics/opengl/internal/shader/texturequad.go b/graphics/opengl/internal/shader/texturequad.go index efa3ea210..e7654037f 100644 --- a/graphics/opengl/internal/shader/texturequad.go +++ b/graphics/opengl/internal/shader/texturequad.go @@ -4,7 +4,7 @@ import ( "github.com/hajimehoshi/ebiten/graphics" ) -type TextureQuad struct { +type textureQuad struct { VertexX1 float32 VertexX2 float32 VertexY1 float32 @@ -38,8 +38,8 @@ func v(y int, height int) float32 { return float32(y) / float32(AdjustSizeForTexture(height)) } -func TextureQuads(parts []graphics.TexturePart, width, height int) []TextureQuad { - quads := []TextureQuad{} +func textureQuads(parts []graphics.TexturePart, width, height int) []textureQuad { + quads := []textureQuad{} for _, part := range parts { x1 := float32(part.LocationX) x2 := float32(part.LocationX + part.Source.Width) @@ -49,7 +49,7 @@ func TextureQuads(parts []graphics.TexturePart, width, height int) []TextureQuad u2 := u(part.Source.X+part.Source.Width, width) v1 := v(part.Source.Y, height) v2 := v(part.Source.Y+part.Source.Height, height) - quad := TextureQuad{x1, x2, y1, y2, u1, u2, v1, v2} + quad := textureQuad{x1, x2, y1, y2, u1, u2, v1, v2} quads = append(quads, quad) } return quads diff --git a/graphics/opengl/rendertarget.go b/graphics/opengl/rendertarget.go index 35ef016e8..cc44eb339 100644 --- a/graphics/opengl/rendertarget.go +++ b/graphics/opengl/rendertarget.go @@ -27,12 +27,11 @@ type renderTarget struct { flipY bool } -func newFramebuffer(nativeTexture gl.Texture) gl.Framebuffer { +func createFramebuffer(nativeTexture gl.Texture) gl.Framebuffer { framebuffer := gl.GenFramebuffer() framebuffer.Bind() - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, - gl.TEXTURE_2D, nativeTexture, 0) + gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, nativeTexture, 0) if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE { panic("creating framebuffer failed") } diff --git a/graphics/opengl/texture.go b/graphics/opengl/texture.go index b8067a34e..5984c11c8 100644 --- a/graphics/opengl/texture.go +++ b/graphics/opengl/texture.go @@ -17,8 +17,7 @@ func adjustImageForTexture(img image.Image) *image.NRGBA { shader.AdjustSizeForTexture(height), }, } - if nrgba, ok := img.(*image.NRGBA); ok && - img.Bounds() == adjustedImageBounds { + if nrgba, ok := img.(*image.NRGBA); ok && img.Bounds() == adjustedImageBounds { return nrgba } @@ -37,7 +36,7 @@ type texture struct { height int } -func newNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter graphics.Filter) gl.Texture { +func createNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter graphics.Filter) gl.Texture { nativeTexture := gl.GenTexture() if nativeTexture < 0 { panic("glGenTexture failed") @@ -67,17 +66,17 @@ func newNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter gr return nativeTexture } -func newTexture(width, height int, filter graphics.Filter) (*texture, error) { +func createTexture(width, height int, filter graphics.Filter) (*texture, error) { w := shader.AdjustSizeForTexture(width) h := shader.AdjustSizeForTexture(height) - native := newNativeTexture(w, h, nil, filter) + native := createNativeTexture(w, h, nil, filter) return &texture{native, width, height}, nil } -func newTextureFromImage(img image.Image, filter graphics.Filter) (*texture, error) { +func createTextureFromImage(img image.Image, filter graphics.Filter) (*texture, error) { adjustedImage := adjustImageForTexture(img) size := adjustedImage.Bounds().Size() - native := newNativeTexture(size.X, size.Y, adjustedImage.Pix, filter) + native := createNativeTexture(size.X, size.Y, adjustedImage.Pix, filter) return &texture{native, size.X, size.Y}, nil } diff --git a/ui/glfw/canvas.go b/ui/glfw/canvas.go index 987b218ee..a7494773f 100644 --- a/ui/glfw/canvas.go +++ b/ui/glfw/canvas.go @@ -4,7 +4,6 @@ import ( glfw "github.com/go-gl/glfw3" "github.com/hajimehoshi/ebiten/graphics" "github.com/hajimehoshi/ebiten/graphics/opengl" - "github.com/hajimehoshi/ebiten/input" "github.com/hajimehoshi/ebiten/ui" "image" "runtime" @@ -13,37 +12,11 @@ import ( type canvas struct { window *glfw.Window contextUpdater *opengl.ContextUpdater - keyboard *keyboard + keyboard keyboard funcs chan func() funcsDone chan struct{} } -func newCanvas(width, height, scale int, title string) *canvas { - window, err := glfw.CreateWindow(width*scale, height*scale, title, nil, nil) - if err != nil { - panic(err) - } - canvas := &canvas{ - window: window, - keyboard: newKeyboard(), - funcs: make(chan func()), - funcsDone: make(chan struct{}), - } - - input.SetKeyboard(canvas.keyboard) - graphics.SetTextureFactory(canvas) - - // For retina displays, recalculate the scale with the framebuffer size. - windowWidth, _ := window.GetFramebufferSize() - realScale := windowWidth / width - - canvas.run() - canvas.use(func() { - canvas.contextUpdater = opengl.NewContextUpdater(width, height, realScale) - }) - return canvas -} - func (c *canvas) Draw(d ui.Drawer) (err error) { c.use(func() { err = c.contextUpdater.Update(d) @@ -74,7 +47,7 @@ func (c *canvas) NewRenderTargetID(width, height int, filter graphics.Filter) (g return id, err } -func (c *canvas) run() { +func (c *canvas) run(width, height, scale int) { go func() { runtime.LockOSThread() c.window.MakeContextCurrent() diff --git a/ui/glfw/keyboard.go b/ui/glfw/keyboard.go index 3e99432e1..ce779377f 100644 --- a/ui/glfw/keyboard.go +++ b/ui/glfw/keyboard.go @@ -6,18 +6,11 @@ import ( ) type keyboard struct { - pressedKeys map[input.Key]struct{} -} - -func newKeyboard() *keyboard { - return &keyboard{ - pressedKeys: map[input.Key]struct{}{}, - } + keyPressed [input.KeyMax]bool } func (k *keyboard) IsKeyPressed(key input.Key) bool { - _, ok := k.pressedKeys[key] - return ok + return k.keyPressed[key] } var glfwKeyCodeToKey = map[glfw.Key]input.Key{ @@ -30,10 +23,6 @@ var glfwKeyCodeToKey = map[glfw.Key]input.Key{ func (k *keyboard) update(window *glfw.Window) { for g, u := range glfwKeyCodeToKey { - if window.GetKey(g) == glfw.Press { - k.pressedKeys[u] = struct{}{} - } else { - delete(k.pressedKeys, u) - } + k.keyPressed[u] = window.GetKey(g) == glfw.Press } } diff --git a/ui/glfw/ui.go b/ui/glfw/ui.go index e9be7063a..7fd86e28c 100644 --- a/ui/glfw/ui.go +++ b/ui/glfw/ui.go @@ -4,6 +4,9 @@ import ( "errors" "fmt" glfw "github.com/go-gl/glfw3" + "github.com/hajimehoshi/ebiten/graphics" + "github.com/hajimehoshi/ebiten/graphics/opengl" + "github.com/hajimehoshi/ebiten/input" "github.com/hajimehoshi/ebiten/ui" ) @@ -22,8 +25,33 @@ func (u *UI) Start(width, height, scale int, title string) (ui.Canvas, error) { return nil, errors.New("glfw.Init() fails") } glfw.WindowHint(glfw.Resizable, glfw.False) - u.canvas = newCanvas(width, height, scale, title) - return u.canvas, nil + window, err := glfw.CreateWindow(width*scale, height*scale, title, nil, nil) + if err != nil { + return nil, err + } + + c := &canvas{ + window: window, + funcs: make(chan func()), + funcsDone: make(chan struct{}), + } + input.SetKeyboard(&c.keyboard) + graphics.SetTextureFactory(c) + + c.run(width, height, scale) + + // For retina displays, recalculate the scale with the framebuffer size. + windowWidth, _ := window.GetFramebufferSize() + realScale := windowWidth / width + c.use(func() { + c.contextUpdater, err = opengl.Initialize(width, height, realScale) + }) + if err != nil { + return nil, err + } + + u.canvas = c + return c, nil } func (u *UI) DoEvents() {