Refactoring

This commit is contained in:
Hajime Hoshi 2014-05-03 00:06:20 +09:00
parent 562d04cacc
commit f0356748be
11 changed files with 142 additions and 190 deletions

View File

@ -4,6 +4,19 @@ import (
"github.com/hajimehoshi/go-ebiten/graphics/matrix" "github.com/hajimehoshi/go-ebiten/graphics/matrix"
) )
type Rect struct {
X int
Y int
Width int
Height int
}
type TexturePart struct {
LocationX int
LocationY int
Source Rect
}
type Drawer interface { type Drawer interface {
Draw(geometryMatrix matrix.Geometry, Draw(geometryMatrix matrix.Geometry,
colorMatrix matrix.Color) colorMatrix matrix.Color)

View File

@ -1,31 +1,5 @@
package graphics package graphics
type Rect struct {
X int
Y int
Width int
Height int
}
type TexturePart struct {
LocationX int
LocationY int
Source Rect
}
type Filter int
const (
FilterNearest Filter = iota
FilterLinear
)
type TextureId int
// A render target is essentially same as a texture, but it is assumed that the
// all alpha of a render target is maximum.
type RenderTargetId int
func OrthoProjectionMatrix(left, right, bottom, top int) [4][4]float64 { func OrthoProjectionMatrix(left, right, bottom, top int) [4][4]float64 {
e11 := float64(2) / float64(right-left) e11 := float64(2) / float64(right-left)
e22 := float64(2) / float64(top-bottom) e22 := float64(2) / float64(top-bottom)

View File

@ -21,10 +21,10 @@ func newContext(ids *ids, screenWidth, screenHeight, screenScale int) *Context {
mainRenderTarget := newRTWithCurrentFramebuffer( mainRenderTarget := newRTWithCurrentFramebuffer(
screenWidth*screenScale, screenWidth*screenScale,
screenHeight*screenScale) screenHeight*screenScale)
context.mainId = context.ids.AddRenderTarget(mainRenderTarget) context.mainId = context.ids.addRenderTarget(mainRenderTarget)
var err error var err error
context.screenId, err = ids.CreateRenderTarget( context.screenId, err = ids.createRenderTarget(
screenWidth, screenHeight, graphics.FilterNearest) screenWidth, screenHeight, graphics.FilterNearest)
if err != nil { if err != nil {
panic("initializing the offscreen failed: " + err.Error()) panic("initializing the offscreen failed: " + err.Error())
@ -39,7 +39,7 @@ func newContext(ids *ids, screenWidth, screenHeight, screenScale int) *Context {
func (context *Context) Dispose() { func (context *Context) Dispose() {
// TODO: remove main framebuffer? // TODO: remove main framebuffer?
context.ids.DeleteRenderTarget(context.screenId) context.ids.deleteRenderTarget(context.screenId)
} }
func (context *Context) Update(draw func(graphics.Context)) { func (context *Context) Update(draw func(graphics.Context)) {
@ -54,7 +54,8 @@ func (context *Context) Update(draw func(graphics.Context)) {
scale := float64(context.screenScale) scale := float64(context.screenScale)
geometryMatrix := matrix.IdentityGeometry() geometryMatrix := matrix.IdentityGeometry()
geometryMatrix.Scale(scale, scale) geometryMatrix.Scale(scale, scale)
context.RenderTarget(context.screenId).Draw(geometryMatrix, matrix.IdentityColor()) context.RenderTarget(context.screenId).Draw(
geometryMatrix, matrix.IdentityColor())
flush() flush()
} }
@ -64,7 +65,7 @@ func (c *Context) Clear() {
} }
func (c *Context) Fill(r, g, b uint8) { func (c *Context) Fill(r, g, b uint8) {
c.ids.FillRenderTarget(c.currentId, r, g, b) c.ids.fillRenderTarget(c.currentId, r, g, b)
} }
func (c *Context) Texture(id graphics.TextureId) graphics.Drawer { func (c *Context) Texture(id graphics.TextureId) graphics.Drawer {
@ -72,7 +73,7 @@ func (c *Context) Texture(id graphics.TextureId) graphics.Drawer {
} }
func (c *Context) RenderTarget(id graphics.RenderTargetId) graphics.Drawer { func (c *Context) RenderTarget(id graphics.RenderTargetId) graphics.Drawer {
return &RenderTargetWithContext{id, c} return &TextureWithContext{c.ids.toTexture(id), c}
} }
func (context *Context) ResetOffscreen() { func (context *Context) ResetOffscreen() {
@ -89,22 +90,12 @@ type TextureWithContext struct {
} }
func (t *TextureWithContext) Draw(geo matrix.Geometry, color matrix.Color) { func (t *TextureWithContext) Draw(geo matrix.Geometry, color matrix.Color) {
t.context.ids.DrawTexture(t.context.currentId, t.id, geo, color) t.context.ids.drawTexture(t.context.currentId, t.id, geo, color)
} }
func (t *TextureWithContext) DrawParts(parts []graphics.TexturePart, geo matrix.Geometry, color matrix.Color) { func (t *TextureWithContext) DrawParts(
t.context.ids.DrawTextureParts(t.context.currentId, t.id, parts, geo, color) parts []graphics.TexturePart,
} geo matrix.Geometry,
color matrix.Color) {
type RenderTargetWithContext struct { t.context.ids.drawTextureParts(t.context.currentId, t.id, parts, geo, color)
id graphics.RenderTargetId
context *Context
}
func (r *RenderTargetWithContext) Draw(geo matrix.Geometry, color matrix.Color) {
r.context.ids.DrawRenderTarget(r.context.currentId, r.id, geo, color)
}
func (r *RenderTargetWithContext) DrawParts(parts []graphics.TexturePart, geo matrix.Geometry, color matrix.Color) {
r.context.ids.DrawRenderTargetParts(r.context.currentId, r.id, parts, geo, color)
} }

View File

@ -7,12 +7,31 @@ import (
"sync" "sync"
) )
var idsInstance *ids = newIds()
func CreateContext(
screenWidth, screenHeight, screenScale int) *Context {
return newContext(idsInstance, screenWidth, screenHeight, screenScale)
}
func CreateRenderTarget(
width, height int,
filter graphics.Filter) (graphics.RenderTargetId, error) {
return idsInstance.createRenderTarget(width, height, filter)
}
func CreateTexture(
img image.Image,
filter graphics.Filter) (graphics.TextureId, error) {
return idsInstance.createTexture(img, filter)
}
type ids struct { type ids struct {
lock sync.RWMutex
textures map[graphics.TextureId]*Texture textures map[graphics.TextureId]*Texture
renderTargets map[graphics.RenderTargetId]*RenderTarget renderTargets map[graphics.RenderTargetId]*RenderTarget
renderTargetToTexture map[graphics.RenderTargetId]graphics.TextureId renderTargetToTexture map[graphics.RenderTargetId]graphics.TextureId
counts chan int counts chan int
sync.RWMutex
} }
func newIds() *ids { func newIds() *ids {
@ -31,24 +50,24 @@ func newIds() *ids {
} }
func (i *ids) textureAt(id graphics.TextureId) *Texture { func (i *ids) textureAt(id graphics.TextureId) *Texture {
i.lock.RLock() i.RLock()
defer i.lock.RUnlock() defer i.RUnlock()
return i.textures[id] return i.textures[id]
} }
func (i *ids) renderTargetAt(id graphics.RenderTargetId) *RenderTarget { func (i *ids) renderTargetAt(id graphics.RenderTargetId) *RenderTarget {
i.lock.RLock() i.RLock()
defer i.lock.RUnlock() defer i.RUnlock()
return i.renderTargets[id] return i.renderTargets[id]
} }
func (i *ids) toTexture(id graphics.RenderTargetId) graphics.TextureId { func (i *ids) toTexture(id graphics.RenderTargetId) graphics.TextureId {
i.lock.RLock() i.RLock()
defer i.lock.RUnlock() defer i.RUnlock()
return i.renderTargetToTexture[id] return i.renderTargetToTexture[id]
} }
func (i *ids) CreateTexture(img image.Image, filter graphics.Filter) ( func (i *ids) createTexture(img image.Image, filter graphics.Filter) (
graphics.TextureId, error) { graphics.TextureId, error) {
texture, err := createTextureFromImage(img, filter) texture, err := createTextureFromImage(img, filter)
if err != nil { if err != nil {
@ -56,13 +75,13 @@ func (i *ids) CreateTexture(img image.Image, filter graphics.Filter) (
} }
textureId := graphics.TextureId(<-i.counts) textureId := graphics.TextureId(<-i.counts)
i.lock.Lock() i.Lock()
defer i.lock.Unlock() defer i.Unlock()
i.textures[textureId] = texture i.textures[textureId] = texture
return textureId, nil return textureId, nil
} }
func (i *ids) CreateRenderTarget(width, height int, filter graphics.Filter) ( func (i *ids) createRenderTarget(width, height int, filter graphics.Filter) (
graphics.RenderTargetId, error) { graphics.RenderTargetId, error) {
texture, err := createTexture(width, height, filter) texture, err := createTexture(width, height, filter)
@ -75,8 +94,8 @@ func (i *ids) CreateRenderTarget(width, height int, filter graphics.Filter) (
textureId := graphics.TextureId(<-i.counts) textureId := graphics.TextureId(<-i.counts)
renderTargetId := graphics.RenderTargetId(<-i.counts) renderTargetId := graphics.RenderTargetId(<-i.counts)
i.lock.Lock() i.Lock()
defer i.lock.Unlock() defer i.Unlock()
i.textures[textureId] = texture i.textures[textureId] = texture
i.renderTargets[renderTargetId] = renderTarget i.renderTargets[renderTargetId] = renderTarget
i.renderTargetToTexture[renderTargetId] = textureId i.renderTargetToTexture[renderTargetId] = textureId
@ -85,54 +104,52 @@ func (i *ids) CreateRenderTarget(width, height int, filter graphics.Filter) (
} }
// NOTE: renderTarget can't be used as a texture. // NOTE: renderTarget can't be used as a texture.
func (i *ids) AddRenderTarget(renderTarget *RenderTarget) graphics.RenderTargetId { func (i *ids) addRenderTarget(renderTarget *RenderTarget) graphics.RenderTargetId {
id := graphics.RenderTargetId(<-i.counts) id := graphics.RenderTargetId(<-i.counts)
i.lock.Lock() i.Lock()
defer i.lock.Unlock() defer i.Unlock()
i.renderTargets[id] = renderTarget i.renderTargets[id] = renderTarget
return id return id
} }
func (i *ids) DeleteRenderTarget(id graphics.RenderTargetId) { func (i *ids) deleteRenderTarget(id graphics.RenderTargetId) {
i.lock.Lock() i.Lock()
defer i.lock.Unlock() defer i.Unlock()
renderTarget := i.renderTargets[id] renderTarget := i.renderTargets[id]
textureId := i.renderTargetToTexture[id] textureId := i.renderTargetToTexture[id]
texture := i.textures[textureId] texture := i.textures[textureId]
renderTarget.Dispose() renderTarget.dispose()
texture.Dispose() texture.dispose()
delete(i.renderTargets, id) delete(i.renderTargets, id)
delete(i.renderTargetToTexture, id) delete(i.renderTargetToTexture, id)
delete(i.textures, textureId) delete(i.textures, textureId)
} }
func (i *ids) FillRenderTarget(id graphics.RenderTargetId, r, g, b uint8) { func (i *ids) fillRenderTarget(id graphics.RenderTargetId, r, g, b uint8) {
i.renderTargetAt(id).Fill(r, g, b) i.renderTargetAt(id).fill(r, g, b)
} }
func (i *ids) DrawTexture(target graphics.RenderTargetId, id graphics.TextureId, func (i *ids) drawTexture(
geo matrix.Geometry, color matrix.Color) { target graphics.RenderTargetId,
id graphics.TextureId,
geo matrix.Geometry,
color matrix.Color) {
texture := i.textureAt(id) texture := i.textureAt(id)
i.renderTargetAt(target).DrawTexture(texture, geo, color) parts := []graphics.TexturePart{
{0, 0, graphics.Rect{0, 0, texture.width, texture.height}},
}
i.renderTargetAt(target).drawTexture(texture, parts, geo, color)
} }
func (i *ids) DrawTextureParts(target graphics.RenderTargetId, id graphics.TextureId, func (i *ids) drawTextureParts(
target graphics.RenderTargetId,
id graphics.TextureId,
parts []graphics.TexturePart, geo matrix.Geometry, color matrix.Color) { parts []graphics.TexturePart, geo matrix.Geometry, color matrix.Color) {
texture := i.textureAt(id) texture := i.textureAt(id)
i.renderTargetAt(target).DrawTextureParts(texture, parts, geo, color) i.renderTargetAt(target).drawTexture(texture, parts, geo, color)
}
func (i *ids) DrawRenderTarget(target graphics.RenderTargetId, id graphics.RenderTargetId,
geo matrix.Geometry, color matrix.Color) {
i.DrawTexture(target, i.toTexture(id), geo, color)
}
func (i *ids) DrawRenderTargetParts(target graphics.RenderTargetId, id graphics.RenderTargetId,
parts []graphics.TexturePart, geo matrix.Geometry, color matrix.Color) {
i.DrawTextureParts(target, i.toTexture(id), parts, geo, color)
} }

View File

@ -8,9 +8,20 @@ import (
"fmt" "fmt"
"github.com/hajimehoshi/go-ebiten/graphics" "github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix" "github.com/hajimehoshi/go-ebiten/graphics/matrix"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/shader"
"math" "math"
) )
func glMatrix(matrix [4][4]float64) [16]float32 {
result := [16]float32{}
for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ {
result[i+j*4] = float32(matrix[i][j])
}
}
return result
}
type RenderTarget struct { type RenderTarget struct {
framebuffer C.GLuint framebuffer C.GLuint
width int width int
@ -84,11 +95,11 @@ func (r *RenderTarget) projectionMatrix() [4][4]float64 {
return matrix return matrix
} }
func (r *RenderTarget) Dispose() { func (r *RenderTarget) dispose() {
C.glDeleteFramebuffers(1, &r.framebuffer) C.glDeleteFramebuffers(1, &r.framebuffer)
} }
func (r *RenderTarget) Fill(red, green, blue uint8) { func (r *RenderTarget) fill(red, green, blue uint8) {
r.setAsViewport() r.setAsViewport()
const max = float64(math.MaxUint8) const max = float64(math.MaxUint8)
C.glClearColor( C.glClearColor(
@ -99,17 +110,18 @@ func (r *RenderTarget) Fill(red, green, blue uint8) {
C.glClear(C.GL_COLOR_BUFFER_BIT) C.glClear(C.GL_COLOR_BUFFER_BIT)
} }
func (r *RenderTarget) DrawTexture(texture *Texture, func (r *RenderTarget) drawTexture(
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { texture *Texture,
r.setAsViewport()
projectionMatrix := r.projectionMatrix()
texture.Draw(projectionMatrix, geometryMatrix, colorMatrix)
}
func (r *RenderTarget) DrawTextureParts(texture *Texture,
parts []graphics.TexturePart, parts []graphics.TexturePart,
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { geometryMatrix matrix.Geometry,
colorMatrix matrix.Color) {
r.setAsViewport() r.setAsViewport()
projectionMatrix := r.projectionMatrix() projectionMatrix := r.projectionMatrix()
texture.DrawParts(parts, projectionMatrix, geometryMatrix, colorMatrix) quads := graphics.TextureQuads(parts, texture.width, texture.height)
shader.DrawTexture(
shader.NativeTexture(texture.native),
glMatrix(projectionMatrix),
quads,
geometryMatrix,
colorMatrix)
} }

View File

@ -1,34 +0,0 @@
package opengl
import (
"github.com/hajimehoshi/go-ebiten/graphics"
"image"
)
type SharedContext struct {
ids *ids
}
var sharedContext *SharedContext = nil
func Initialize() *SharedContext {
if sharedContext != nil {
panic("OpenGL is already initialized")
}
sharedContext = &SharedContext{
ids: newIds(),
}
return sharedContext
}
func (s *SharedContext) CreateContext(screenWidth, screenHeight, screenScale int) *Context {
return newContext(s.ids, screenWidth, screenHeight, screenScale)
}
func (s *SharedContext) CreateRenderTarget(width, height int, filter graphics.Filter) (graphics.RenderTargetId, error) {
return s.ids.CreateRenderTarget(width, height, filter)
}
func (s *SharedContext) CreateTexture(img image.Image, filter graphics.Filter) (graphics.TextureId, error) {
return s.ids.CreateTexture(img, filter)
}

View File

@ -6,8 +6,6 @@ package opengl
import "C" import "C"
import ( import (
"github.com/hajimehoshi/go-ebiten/graphics" "github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/shader"
"image" "image"
"unsafe" "unsafe"
) )
@ -18,17 +16,9 @@ type Texture struct {
height int height int
} }
func glMatrix(matrix [4][4]float64) [16]float32 { func createNativeTexture(
result := [16]float32{} textureWidth, textureHeight int,
for j := 0; j < 4; j++ { pixels []uint8,
for i := 0; i < 4; i++ {
result[i+j*4] = float32(matrix[i][j])
}
}
return result
}
func createNativeTexture(textureWidth, textureHeight int, pixels []uint8,
filter graphics.Filter) C.GLuint { filter graphics.Filter) C.GLuint {
nativeTexture := C.GLuint(0) nativeTexture := C.GLuint(0)
@ -63,35 +53,26 @@ func createNativeTexture(textureWidth, textureHeight int, pixels []uint8,
return nativeTexture return nativeTexture
} }
func createTexture(width, height int, filter graphics.Filter) (*Texture, error) { func createTexture(
width, height int,
filter graphics.Filter) (*Texture, error) {
native := createNativeTexture( native := createNativeTexture(
graphics.AdjustSizeForTexture(width), graphics.AdjustSizeForTexture(width),
graphics.AdjustSizeForTexture(height), nil, filter) graphics.AdjustSizeForTexture(height),
nil,
filter)
return &Texture{native, width, height}, nil return &Texture{native, width, height}, nil
} }
func createTextureFromImage(img image.Image, filter graphics.Filter) (*Texture, error) { func createTextureFromImage(
img image.Image,
filter graphics.Filter) (*Texture, error) {
adjustedImage := graphics.AdjustImageForTexture(img) adjustedImage := graphics.AdjustImageForTexture(img)
size := adjustedImage.Bounds().Size() size := adjustedImage.Bounds().Size()
native := createNativeTexture(size.X, size.Y, adjustedImage.Pix, filter) native := createNativeTexture(size.X, size.Y, adjustedImage.Pix, filter)
return &Texture{native, size.X, size.Y}, nil return &Texture{native, size.X, size.Y}, nil
} }
func (t *Texture) Draw(projectionMatrix [4][4]float64, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) { func (t *Texture) dispose() {
quad := graphics.TextureQuadForTexture(t.width, t.height)
shader.DrawTexture(shader.NativeTexture(t.native),
glMatrix(projectionMatrix), []graphics.TextureQuad{quad},
geometryMatrix, colorMatrix)
}
func (t *Texture) DrawParts(parts []graphics.TexturePart, projectionMatrix [4][4]float64,
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
quads := graphics.TextureQuadsForTextureParts(parts, t.width, t.height)
shader.DrawTexture(shader.NativeTexture(t.native),
glMatrix(projectionMatrix), quads,
geometryMatrix, colorMatrix)
}
func (t *Texture) Dispose() {
C.glDeleteTextures(1, &t.native) C.glDeleteTextures(1, &t.native)
} }

View File

@ -4,6 +4,19 @@ import (
"image" "image"
) )
type Filter int
const (
FilterNearest Filter = iota
FilterLinear
)
type TextureId int
// A render target is essentially same as a texture, but it is assumed that the
// all alpha of a render target is maximum.
type RenderTargetId int
type TextureCreatedEvent struct { type TextureCreatedEvent struct {
Tag interface{} Tag interface{}
Id TextureId Id TextureId

View File

@ -62,20 +62,7 @@ func v(y int, height int) float32 {
return float32(y) / float32(AdjustSizeForTexture(height)) return float32(y) / float32(AdjustSizeForTexture(height))
} }
// TODO: Remove this if possible func TextureQuads(parts []TexturePart, width, height int) []TextureQuad {
func TextureQuadForTexture(width, height int) TextureQuad {
x1 := float32(0)
x2 := float32(width)
y1 := float32(0)
y2 := float32(height)
u1 := u(0, width)
u2 := u(width, width)
v1 := v(0, height)
v2 := v(height, height)
return TextureQuad{x1, x2, y1, y2, u1, u2, v1, v2}
}
func TextureQuadsForTextureParts(parts []TexturePart, width, height int) []TextureQuad {
quads := []TextureQuad{} quads := []TextureQuad{}
for _, part := range parts { for _, part := range parts {
x1 := float32(part.LocationX) x1 := float32(part.LocationX)

View File

@ -53,7 +53,7 @@ func newGameWindow(width, height, scale int, title string) *GameWindow {
} }
} }
func (w *GameWindow) run(graphicsSharedContext *opengl.SharedContext, sharedGLContext *C.NSOpenGLContext) { func (w *GameWindow) run(sharedGLContext *C.NSOpenGLContext) {
cTitle := C.CString(w.title) cTitle := C.CString(w.title)
defer C.free(unsafe.Pointer(cTitle)) defer C.free(unsafe.Pointer(cTitle))
@ -69,7 +69,7 @@ func (w *GameWindow) run(graphicsSharedContext *opengl.SharedContext, sharedGLCo
close(ch) close(ch)
C.UseGLContext(glContext) C.UseGLContext(glContext)
context := graphicsSharedContext.CreateContext( context := opengl.CreateContext(
w.screenWidth, w.screenHeight, w.screenScale) w.screenWidth, w.screenHeight, w.screenScale)
C.UnuseGLContext() C.UnuseGLContext()

View File

@ -15,12 +15,11 @@ import (
) )
type sharedContext struct { type sharedContext struct {
inited chan struct{} inited chan struct{}
sharedContext *opengl.SharedContext events chan interface{}
events chan interface{} funcs chan func()
funcs chan func() funcsDone chan struct{}
funcsDone chan struct{} gameWindows chan *GameWindow
gameWindows chan *GameWindow
} }
func newSharedContext() *sharedContext { func newSharedContext() *sharedContext {
@ -36,7 +35,6 @@ func (t *sharedContext) run() {
var sharedGLContext *C.NSOpenGLContext var sharedGLContext *C.NSOpenGLContext
go func() { go func() {
runtime.LockOSThread() runtime.LockOSThread()
t.sharedContext = opengl.Initialize()
sharedGLContext = C.CreateGLContext(nil) sharedGLContext = C.CreateGLContext(nil)
close(t.inited) close(t.inited)
t.loop(sharedGLContext) t.loop(sharedGLContext)
@ -44,7 +42,7 @@ func (t *sharedContext) run() {
<-t.inited <-t.inited
go func() { go func() {
for w := range t.gameWindows { for w := range t.gameWindows {
w.run(t.sharedContext, sharedGLContext) w.run(sharedGLContext)
} }
}() }()
} }
@ -88,7 +86,7 @@ func (t *sharedContext) CreateTexture(tag interface{}, img image.Image, filter g
var id graphics.TextureId var id graphics.TextureId
var err error var err error
t.useGLContext(func() { t.useGLContext(func() {
id, err = t.sharedContext.CreateTexture(img, filter) id, err = opengl.CreateTexture(img, filter)
}) })
if t.events == nil { if t.events == nil {
return return
@ -107,7 +105,7 @@ func (t *sharedContext) CreateRenderTarget(tag interface{}, width, height int, f
var id graphics.RenderTargetId var id graphics.RenderTargetId
var err error var err error
t.useGLContext(func() { t.useGLContext(func() {
id, err = t.sharedContext.CreateRenderTarget(width, height, filter) id, err = opengl.CreateRenderTarget(width, height, filter)
}) })
if t.events == nil { if t.events == nil {
return return