Add cocoa.textureFactory

This commit is contained in:
Hajime Hoshi 2013-12-07 02:20:48 +09:00
parent 24a735dd0b
commit e55060c239
10 changed files with 213 additions and 85 deletions

View File

@ -79,7 +79,6 @@ func New() *Sprites {
func (game *Sprites) OnScreenSizeUpdated(e ui.ScreenSizeUpdatedEvent) { func (game *Sprites) OnScreenSizeUpdated(e ui.ScreenSizeUpdatedEvent) {
go func() { go func() {
e := e
game.screenSizeUpdatedCh <- e game.screenSizeUpdatedCh <- e
}() }()
} }

View File

@ -57,7 +57,11 @@ func main() {
const fps = 60 const fps = 60
const title = "Ebiten Demo" const title = "Ebiten Demo"
var u ui.UI = cocoa.New(screenWidth, screenHeight, screenScale, title) type UI interface {
ui.UI
//graphics.TextureFactory
}
var u UI = cocoa.New(screenWidth, screenHeight, screenScale, title)
// TODO: Get a map or something // TODO: Get a map or something
u.LoadResources(game.InitTextures) u.LoadResources(game.InitTextures)
inputStateUpdated := u.InputStateUpdated() inputStateUpdated := u.InputStateUpdated()
@ -72,10 +76,9 @@ func main() {
case e, ok := <-inputStateUpdated: case e, ok := <-inputStateUpdated:
// TODO: Use Adaptor? // TODO: Use Adaptor?
if ok { if ok {
type Handler interface { if game2, ok := game.(interface {
OnInputStateUpdated(ui.InputStateUpdatedEvent) OnInputStateUpdated(ui.InputStateUpdatedEvent)
} }); ok {
if game2, ok := game.(Handler); ok {
game2.OnInputStateUpdated(e) game2.OnInputStateUpdated(e)
} }
} else { } else {
@ -83,10 +86,9 @@ func main() {
} }
case e, ok := <-screenSizeUpdated: case e, ok := <-screenSizeUpdated:
if ok { if ok {
type Handler interface { if game2, ok := game.(interface {
OnScreenSizeUpdated(ui.ScreenSizeUpdatedEvent) OnScreenSizeUpdated(ui.ScreenSizeUpdatedEvent)
} }); ok {
if game2, ok := game.(Handler); ok {
game2.OnScreenSizeUpdated(e) game2.OnScreenSizeUpdated(e)
} }
} else { } else {

View File

@ -3,6 +3,7 @@ package opengl
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/matrix"
"image"
) )
type Device struct { type Device struct {
@ -18,8 +19,8 @@ func NewDevice(screenWidth, screenHeight, screenScale int) *Device {
} }
} }
func (device *Device) Update(draw func(graphics.Canvas)) { func (d *Device) Update(draw func(graphics.Canvas)) {
context := device.context context := d.context
context.Init() context.Init()
context.ResetOffscreen() context.ResetOffscreen()
context.Clear() context.Clear()
@ -30,7 +31,7 @@ func (device *Device) Update(draw func(graphics.Canvas)) {
context.setMainFramebufferOffscreen() context.setMainFramebufferOffscreen()
context.Clear() context.Clear()
scale := float64(device.screenScale) scale := float64(d.screenScale)
geometryMatrix := matrix.IdentityGeometry() geometryMatrix := matrix.IdentityGeometry()
geometryMatrix.Scale(scale, scale) geometryMatrix.Scale(scale, scale)
context.DrawRenderTarget(context.screenId, context.DrawRenderTarget(context.screenId,
@ -38,6 +39,10 @@ func (device *Device) Update(draw func(graphics.Canvas)) {
context.flush() context.flush()
} }
func (device *Device) TextureFactory() graphics.TextureFactory { func (d *Device) CreateRenderTarget(tag string, width, height int) (graphics.RenderTargetId, error) {
return device.context return d.context.CreateRenderTarget(tag, width, height)
}
func (d *Device) CreateTextureFromImage(tag string, img image.Image) (graphics.TextureId, error) {
return d.context.CreateTextureFromImage(tag, img)
} }

View File

@ -21,6 +21,13 @@ type TextureFactoryEvents interface {
RenderTargetCreated() <-chan RenderTargetCreatedEvent RenderTargetCreated() <-chan RenderTargetCreatedEvent
} }
// TODO: Rename this later
type TextureFactory2 interface {
CreateRenderTarget(tag string, width, height int)
CreateTexture(tag string, img image.Image)
TextureFactoryEvents
}
type TextureFactory interface { type TextureFactory interface {
CreateRenderTarget(tag string, width, height int) (RenderTargetId, error) CreateRenderTarget(tag string, width, height int) (RenderTargetId, error)
CreateTextureFromImage(tag string, img image.Image) (TextureId, error) CreateTextureFromImage(tag string, img image.Image) (TextureId, error)

View File

@ -3,13 +3,9 @@ package cocoa
// #cgo CFLAGS: -x objective-c // #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Cocoa -framework OpenGL // #cgo LDFLAGS: -framework Cocoa -framework OpenGL
// //
// #include <stdlib.h>
// #include "input.h" // #include "input.h"
// //
// void StartApplication(void); // void StartApplication(void);
// void* CreateGLContext(void* sharedGLContext);
// void SetCurrentGLContext(void* glContext);
// void* CreateWindow(size_t width, size_t height, const char* title, void* sharedGLContext);
// void PollEvents(void); // void PollEvents(void);
// void BeginDrawing(void* window); // void BeginDrawing(void* window);
// void EndDrawing(void* window); // void EndDrawing(void* window);
@ -19,18 +15,19 @@ import (
"github.com/hajimehoshi/go-ebiten/graphics" "github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/opengl" "github.com/hajimehoshi/go-ebiten/graphics/opengl"
"github.com/hajimehoshi/go-ebiten/ui" "github.com/hajimehoshi/go-ebiten/ui"
"image"
"unsafe" "unsafe"
) )
type UI struct { type UI struct {
screenWidth int screenWidth int
screenHeight int screenHeight int
screenScale int screenScale int
graphicsDevice *opengl.Device graphicsDevice *opengl.Device
window unsafe.Pointer window unsafe.Pointer
initialEventSent bool initialEventSent bool
screenSizeUpdated chan ui.ScreenSizeUpdatedEvent // initialized lazily textureFactory *textureFactory
inputStateUpdated chan ui.InputStateUpdatedEvent // initialized lazily uiEvents
} }
var currentUI *UI var currentUI *UI
@ -46,22 +43,22 @@ func New(screenWidth, screenHeight, screenScale int, title string) *UI {
initialEventSent: false, initialEventSent: false,
} }
cTitle := C.CString(title)
defer C.free(unsafe.Pointer(cTitle))
C.StartApplication() C.StartApplication()
context := C.CreateGLContext(unsafe.Pointer(nil)) u.textureFactory = runTextureFactory()
C.SetCurrentGLContext(context)
u.graphicsDevice = opengl.NewDevice( u.textureFactory.UseContext(func() {
u.screenWidth, u.graphicsDevice = opengl.NewDevice(
u.screenHeight, u.screenWidth,
u.screenScale) u.screenHeight,
u.screenScale)
})
u.window = u.textureFactory.CreateWindow(
u.screenWidth*u.screenScale,
u.screenHeight*u.screenScale,
title)
u.window = C.CreateWindow(C.size_t(u.screenWidth*u.screenScale),
C.size_t(u.screenHeight*u.screenScale),
cTitle,
context)
currentUI = u currentUI = u
return u return u
@ -71,19 +68,20 @@ func (u *UI) PollEvents() {
C.PollEvents() C.PollEvents()
if !u.initialEventSent { if !u.initialEventSent {
e := ui.ScreenSizeUpdatedEvent{u.screenWidth, u.screenHeight} e := ui.ScreenSizeUpdatedEvent{u.screenWidth, u.screenHeight}
u.notifyScreenSizeUpdated(e) u.uiEvents.notifyScreenSizeUpdated(e)
u.initialEventSent = true u.initialEventSent = true
} }
} }
func (u *UI) LoadTextures(map[int]string) { func (u *UI) CreateRenderTarget(tag string, width, height int) {
// TODO: Implement }
func (u *UI) CreateTexture(tag string, img image.Image) {
} }
func (u *UI) LoadResources(f func(graphics.TextureFactory)) { func (u *UI) LoadResources(f func(graphics.TextureFactory)) {
C.BeginDrawing(u.window) // This should be executed on the shared-context context
f(u.graphicsDevice) f(u.graphicsDevice)
C.EndDrawing(u.window)
} }
func (u *UI) Draw(f func(graphics.Canvas)) { func (u *UI) Draw(f func(graphics.Canvas)) {
@ -92,45 +90,11 @@ func (u *UI) Draw(f func(graphics.Canvas)) {
C.EndDrawing(u.window) C.EndDrawing(u.window)
} }
func (u *UI) ScreenSizeUpdated() <-chan ui.ScreenSizeUpdatedEvent {
if u.screenSizeUpdated != nil {
return u.screenSizeUpdated
}
u.screenSizeUpdated = make(chan ui.ScreenSizeUpdatedEvent)
return u.screenSizeUpdated
}
func (u *UI) notifyScreenSizeUpdated(e ui.ScreenSizeUpdatedEvent) {
if u.screenSizeUpdated == nil {
return
}
go func() {
u.screenSizeUpdated <- e
}()
}
func (u *UI) InputStateUpdated() <-chan ui.InputStateUpdatedEvent {
if u.inputStateUpdated != nil {
return u.inputStateUpdated
}
u.inputStateUpdated = make(chan ui.InputStateUpdatedEvent)
return u.inputStateUpdated
}
func (u *UI) notifyInputStateUpdated(e ui.InputStateUpdatedEvent) {
if u.inputStateUpdated == nil {
return
}
go func() {
u.inputStateUpdated <- e
}()
}
//export ebiten_ScreenSizeUpdated //export ebiten_ScreenSizeUpdated
func ebiten_ScreenSizeUpdated(width, height int) { func ebiten_ScreenSizeUpdated(width, height int) {
u := currentUI u := currentUI
e := ui.ScreenSizeUpdatedEvent{width, height} e := ui.ScreenSizeUpdatedEvent{width, height}
u.notifyScreenSizeUpdated(e) u.uiEvents.notifyScreenSizeUpdated(e)
} }
//export ebiten_InputUpdated //export ebiten_InputUpdated
@ -139,7 +103,7 @@ func ebiten_InputUpdated(inputType C.InputType, cx, cy C.int) {
if inputType == C.InputTypeMouseUp { if inputType == C.InputTypeMouseUp {
e := ui.InputStateUpdatedEvent{-1, -1} e := ui.InputStateUpdatedEvent{-1, -1}
u.notifyInputStateUpdated(e) u.uiEvents.notifyInputStateUpdated(e)
return return
} }
@ -157,5 +121,5 @@ func ebiten_InputUpdated(inputType C.InputType, cx, cy C.int) {
y = u.screenHeight - 1 y = u.screenHeight - 1
} }
e := ui.InputStateUpdatedEvent{x, y} e := ui.InputStateUpdatedEvent{x, y}
u.notifyInputStateUpdated(e) u.uiEvents.notifyInputStateUpdated(e)
} }

View File

@ -32,10 +32,6 @@ void* CreateGLContext(void* sharedGLContext) {
return glContext; return glContext;
} }
void SetCurrentGLContext(void* glContext) {
[(NSOpenGLContext*)glContext makeCurrentContext];
}
void* CreateWindow(size_t width, size_t height, const char* title, void* sharedGLContext) { void* CreateWindow(size_t width, size_t height, const char* title, void* sharedGLContext) {
NSOpenGLContext* glContext = CreateGLContext(sharedGLContext); NSOpenGLContext* glContext = CreateGLContext(sharedGLContext);
[glContext makeCurrentContext]; [glContext makeCurrentContext];
@ -66,7 +62,13 @@ void PollEvents(void) {
} }
} }
void UseGLContext(void* glContext) {
// TODO: CGLLock
[(NSOpenGLContext*)glContext makeCurrentContext];
}
void BeginDrawing(void* window) { void BeginDrawing(void* window) {
// TODO: CGLLock
[[(EbitenWindow*)window glContext] makeCurrentContext]; [[(EbitenWindow*)window glContext] makeCurrentContext];
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
} }

View File

@ -0,0 +1,62 @@
package cocoa
// #include <stdlib.h>
//
// void* CreateGLContext(void* sharedGLContext);
// void* CreateWindow(size_t width, size_t height, const char* title, void* sharedGLContext);
// void UseGLContext(void* glContext);
//
import "C"
import (
//"github.com/hajimehoshi/go-ebiten/graphics"
"unsafe"
)
type textureFactory struct {
sharedContext unsafe.Pointer
funcs chan func()
funcsDone chan struct{}
textureFactoryEvents
}
func runTextureFactory() *textureFactory {
t := &textureFactory{
funcs: make(chan func()),
funcsDone: make(chan struct{}),
}
ch := make(chan struct{})
go func() {
t.sharedContext = C.CreateGLContext(unsafe.Pointer(nil))
close(ch)
t.loop()
}()
<-ch
return t
}
func (t *textureFactory) loop() {
for {
select {
case f := <-t.funcs:
C.UseGLContext(t.sharedContext)
f()
t.funcsDone <- struct{}{}
// TODO: Unuse
}
}
}
func (t *textureFactory) UseContext(f func()) {
t.funcs <- f
<-t.funcsDone
}
func (t *textureFactory) CreateWindow(width, height int, title string) unsafe.Pointer {
cTitle := C.CString(title)
defer C.free(unsafe.Pointer(cTitle))
return C.CreateWindow(C.size_t(width),
C.size_t(height),
cTitle,
t.sharedContext)
}

View File

@ -0,0 +1,44 @@
package cocoa
import (
"github.com/hajimehoshi/go-ebiten/graphics"
)
type textureFactoryEvents struct {
textureCreated chan graphics.TextureCreatedEvent
renderTargetCreated chan graphics.RenderTargetCreatedEvent
}
func (t *textureFactoryEvents) TextureCreated() <-chan graphics.TextureCreatedEvent {
if t.textureCreated != nil {
return t.textureCreated
}
t.textureCreated = make(chan graphics.TextureCreatedEvent)
return t.textureCreated
}
func (t *textureFactoryEvents) notifyTextureCreated(e graphics.TextureCreatedEvent) {
if t.textureCreated == nil {
return
}
go func() {
t.textureCreated <- e
}()
}
func (t *textureFactoryEvents) RenderTargetCreated() <-chan graphics.RenderTargetCreatedEvent {
if t.renderTargetCreated != nil {
return t.renderTargetCreated
}
t.renderTargetCreated = make(chan graphics.RenderTargetCreatedEvent)
return t.renderTargetCreated
}
func (t *textureFactoryEvents) notifyRenderTargetCreated(e graphics.RenderTargetCreatedEvent) {
if t.renderTargetCreated == nil {
return
}
go func() {
t.renderTargetCreated <- e
}()
}

44
ui/cocoa/ui_events.go Normal file
View File

@ -0,0 +1,44 @@
package cocoa
import (
"github.com/hajimehoshi/go-ebiten/ui"
)
type uiEvents struct {
screenSizeUpdated chan ui.ScreenSizeUpdatedEvent // initialized lazily
inputStateUpdated chan ui.InputStateUpdatedEvent // initialized lazily
}
func (u *uiEvents) ScreenSizeUpdated() <-chan ui.ScreenSizeUpdatedEvent {
if u.screenSizeUpdated != nil {
return u.screenSizeUpdated
}
u.screenSizeUpdated = make(chan ui.ScreenSizeUpdatedEvent)
return u.screenSizeUpdated
}
func (u *uiEvents) notifyScreenSizeUpdated(e ui.ScreenSizeUpdatedEvent) {
if u.screenSizeUpdated == nil {
return
}
go func() {
u.screenSizeUpdated <- e
}()
}
func (u *uiEvents) InputStateUpdated() <-chan ui.InputStateUpdatedEvent {
if u.inputStateUpdated != nil {
return u.inputStateUpdated
}
u.inputStateUpdated = make(chan ui.InputStateUpdatedEvent)
return u.inputStateUpdated
}
func (u *uiEvents) notifyInputStateUpdated(e ui.InputStateUpdatedEvent) {
if u.inputStateUpdated == nil {
return
}
go func() {
u.inputStateUpdated <- e
}()
}

View File

@ -22,7 +22,6 @@ type UIEvents interface {
type UI interface { type UI interface {
PollEvents() PollEvents()
LoadResources(func(graphics.TextureFactory)) LoadResources(func(graphics.TextureFactory))
LoadTextures(map[int]string)
Draw(func(graphics.Canvas)) Draw(func(graphics.Canvas))
UIEvents UIEvents
} }