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"
)
type Rect struct {
X int
Y int
Width int
Height int
}
type TexturePart struct {
LocationX int
LocationY int
Source Rect
}
type Drawer interface {
Draw(geometryMatrix matrix.Geometry,
colorMatrix matrix.Color)

View File

@ -1,31 +1,5 @@
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 {
e11 := float64(2) / float64(right-left)
e22 := float64(2) / float64(top-bottom)

View File

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

View File

@ -7,12 +7,31 @@ import (
"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 {
lock sync.RWMutex
textures map[graphics.TextureId]*Texture
renderTargets map[graphics.RenderTargetId]*RenderTarget
renderTargetToTexture map[graphics.RenderTargetId]graphics.TextureId
counts chan int
sync.RWMutex
}
func newIds() *ids {
@ -31,24 +50,24 @@ func newIds() *ids {
}
func (i *ids) textureAt(id graphics.TextureId) *Texture {
i.lock.RLock()
defer i.lock.RUnlock()
i.RLock()
defer i.RUnlock()
return i.textures[id]
}
func (i *ids) renderTargetAt(id graphics.RenderTargetId) *RenderTarget {
i.lock.RLock()
defer i.lock.RUnlock()
i.RLock()
defer i.RUnlock()
return i.renderTargets[id]
}
func (i *ids) toTexture(id graphics.RenderTargetId) graphics.TextureId {
i.lock.RLock()
defer i.lock.RUnlock()
i.RLock()
defer i.RUnlock()
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) {
texture, err := createTextureFromImage(img, filter)
if err != nil {
@ -56,13 +75,13 @@ func (i *ids) CreateTexture(img image.Image, filter graphics.Filter) (
}
textureId := graphics.TextureId(<-i.counts)
i.lock.Lock()
defer i.lock.Unlock()
i.Lock()
defer i.Unlock()
i.textures[textureId] = texture
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) {
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)
renderTargetId := graphics.RenderTargetId(<-i.counts)
i.lock.Lock()
defer i.lock.Unlock()
i.Lock()
defer i.Unlock()
i.textures[textureId] = texture
i.renderTargets[renderTargetId] = renderTarget
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.
func (i *ids) AddRenderTarget(renderTarget *RenderTarget) graphics.RenderTargetId {
func (i *ids) addRenderTarget(renderTarget *RenderTarget) graphics.RenderTargetId {
id := graphics.RenderTargetId(<-i.counts)
i.lock.Lock()
defer i.lock.Unlock()
i.Lock()
defer i.Unlock()
i.renderTargets[id] = renderTarget
return id
}
func (i *ids) DeleteRenderTarget(id graphics.RenderTargetId) {
i.lock.Lock()
defer i.lock.Unlock()
func (i *ids) deleteRenderTarget(id graphics.RenderTargetId) {
i.Lock()
defer i.Unlock()
renderTarget := i.renderTargets[id]
textureId := i.renderTargetToTexture[id]
texture := i.textures[textureId]
renderTarget.Dispose()
texture.Dispose()
renderTarget.dispose()
texture.dispose()
delete(i.renderTargets, id)
delete(i.renderTargetToTexture, id)
delete(i.textures, textureId)
}
func (i *ids) FillRenderTarget(id graphics.RenderTargetId, r, g, b uint8) {
i.renderTargetAt(id).Fill(r, g, b)
func (i *ids) fillRenderTarget(id graphics.RenderTargetId, r, g, b uint8) {
i.renderTargetAt(id).fill(r, g, b)
}
func (i *ids) DrawTexture(target graphics.RenderTargetId, id graphics.TextureId,
geo matrix.Geometry, color matrix.Color) {
func (i *ids) drawTexture(
target graphics.RenderTargetId,
id graphics.TextureId,
geo matrix.Geometry,
color matrix.Color) {
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) {
texture := i.textureAt(id)
i.renderTargetAt(target).DrawTextureParts(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)
i.renderTargetAt(target).drawTexture(texture, parts, geo, color)
}

View File

@ -8,9 +8,20 @@ import (
"fmt"
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/shader"
"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 {
framebuffer C.GLuint
width int
@ -84,11 +95,11 @@ func (r *RenderTarget) projectionMatrix() [4][4]float64 {
return matrix
}
func (r *RenderTarget) Dispose() {
func (r *RenderTarget) dispose() {
C.glDeleteFramebuffers(1, &r.framebuffer)
}
func (r *RenderTarget) Fill(red, green, blue uint8) {
func (r *RenderTarget) fill(red, green, blue uint8) {
r.setAsViewport()
const max = float64(math.MaxUint8)
C.glClearColor(
@ -99,17 +110,18 @@ func (r *RenderTarget) Fill(red, green, blue uint8) {
C.glClear(C.GL_COLOR_BUFFER_BIT)
}
func (r *RenderTarget) DrawTexture(texture *Texture,
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
r.setAsViewport()
projectionMatrix := r.projectionMatrix()
texture.Draw(projectionMatrix, geometryMatrix, colorMatrix)
}
func (r *RenderTarget) DrawTextureParts(texture *Texture,
func (r *RenderTarget) drawTexture(
texture *Texture,
parts []graphics.TexturePart,
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
geometryMatrix matrix.Geometry,
colorMatrix matrix.Color) {
r.setAsViewport()
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 (
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/shader"
"image"
"unsafe"
)
@ -18,17 +16,9 @@ type Texture struct {
height int
}
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
}
func createNativeTexture(textureWidth, textureHeight int, pixels []uint8,
func createNativeTexture(
textureWidth, textureHeight int,
pixels []uint8,
filter graphics.Filter) C.GLuint {
nativeTexture := C.GLuint(0)
@ -63,35 +53,26 @@ func createNativeTexture(textureWidth, textureHeight int, pixels []uint8,
return nativeTexture
}
func createTexture(width, height int, filter graphics.Filter) (*Texture, error) {
func createTexture(
width, height int,
filter graphics.Filter) (*Texture, error) {
native := createNativeTexture(
graphics.AdjustSizeForTexture(width),
graphics.AdjustSizeForTexture(height), nil, filter)
graphics.AdjustSizeForTexture(height),
nil,
filter)
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)
size := adjustedImage.Bounds().Size()
native := createNativeTexture(size.X, size.Y, adjustedImage.Pix, filter)
return &Texture{native, size.X, size.Y}, nil
}
func (t *Texture) Draw(projectionMatrix [4][4]float64, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
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() {
func (t *Texture) dispose() {
C.glDeleteTextures(1, &t.native)
}

View File

@ -4,6 +4,19 @@ import (
"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 {
Tag interface{}
Id TextureId

View File

@ -62,20 +62,7 @@ func v(y int, height int) float32 {
return float32(y) / float32(AdjustSizeForTexture(height))
}
// TODO: Remove this if possible
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 {
func TextureQuads(parts []TexturePart, width, height int) []TextureQuad {
quads := []TextureQuad{}
for _, part := range parts {
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)
defer C.free(unsafe.Pointer(cTitle))
@ -69,7 +69,7 @@ func (w *GameWindow) run(graphicsSharedContext *opengl.SharedContext, sharedGLCo
close(ch)
C.UseGLContext(glContext)
context := graphicsSharedContext.CreateContext(
context := opengl.CreateContext(
w.screenWidth, w.screenHeight, w.screenScale)
C.UnuseGLContext()

View File

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