mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
Refactoring: removing new* functions
This commit is contained in:
parent
1c52a28a83
commit
1c3273e0a6
@ -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() {
|
||||
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() {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -43,62 +43,40 @@ func initialize() {
|
||||
programColorMatrix.native.Use()
|
||||
}
|
||||
|
||||
type qualifierVariableType int
|
||||
|
||||
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 {
|
||||
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
|
||||
|
||||
return location
|
||||
}
|
||||
// NOTE: This caches are now used only for programColorMatrix
|
||||
var attribLocationCache = map[string]gl.AttribLocation{}
|
||||
var uniformLocationCache = map[string]gl.UniformLocation{}
|
||||
|
||||
func getAttributeLocation(program gl.Program, name string) gl.AttribLocation {
|
||||
return getLocation(program, name, qualifierVariableTypeAttribute)
|
||||
if location, ok := attribLocationCache[name]; ok {
|
||||
return location
|
||||
}
|
||||
location := program.GetAttribLocation(name)
|
||||
attribLocationCache[name] = location
|
||||
return location
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user