Title for blocks

This commit is contained in:
Hajime Hoshi 2013-12-18 18:05:28 +09:00
parent 72ce849fbd
commit c35d0f85ec
22 changed files with 338 additions and 288 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
.DS_Store
*~

158
example/blocks/game.go Normal file
View File

@ -0,0 +1,158 @@
package blocks
import (
"fmt"
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/ui"
"image"
_ "image/png"
"os"
)
type Size struct {
Width int
Height int
}
var texturePaths = map[string]string{
"background": "images/blocks/background.png",
"font": "images/blocks/font.png",
}
var renderTargetSizes = map[string]Size{
"whole": Size{256, 254},
}
const ScreenWidth = 256
const ScreenHeight = 240
var drawInfo = struct {
textures map[string]graphics.TextureId
renderTargets map[string]graphics.RenderTargetId
}{
textures: map[string]graphics.TextureId{},
renderTargets: map[string]graphics.RenderTargetId{},
}
type Game struct {
sceneManager *SceneManager
}
func loadImage(path string) (image.Image, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return nil, err
}
return img, nil
}
func (game *Game) startLoadingTextures(textureFactory graphics.TextureFactory) {
for tag, path := range texturePaths {
tag := tag
path := path
go func() {
img, err := loadImage(path)
if err != nil {
panic(err)
}
textureFactory.CreateTexture(tag, img, graphics.FilterNearest)
}()
}
for tag, size := range renderTargetSizes {
tag := tag
size := size
go func() {
textureFactory.CreateRenderTarget(tag, size.Width, size.Height)
}()
}
}
func NewGame(textureFactory graphics.TextureFactory) *Game {
game := &Game{
sceneManager: NewSceneManager(NewTitleScene()),
}
game.startLoadingTextures(textureFactory)
return game
}
func (game *Game) HandleEvent(e interface{}) {
switch e := e.(type) {
case graphics.TextureCreatedEvent:
if e.Error != nil {
panic(e.Error)
}
drawInfo.textures[e.Tag.(string)] = e.Id
case graphics.RenderTargetCreatedEvent:
if e.Error != nil {
panic(e.Error)
}
drawInfo.renderTargets[e.Tag.(string)] = e.Id
case ui.KeyStateUpdatedEvent:
fmt.Printf("%v\n", e.Keys)
case ui.MouseStateUpdatedEvent:
}
}
func (game *Game) isInitialized() bool {
if len(drawInfo.textures) < len(texturePaths) {
return false
}
if len(drawInfo.renderTargets) < len(renderTargetSizes) {
return false
}
return true
}
func (game *Game) Update() {
if !game.isInitialized() {
return
}
game.sceneManager.Update()
}
func (game *Game) Draw(context graphics.Context) {
if !game.isInitialized() {
return
}
game.sceneManager.Draw(context)
}
/*func (game *Game) drawText(g graphics.Context, text string, x, y int, clr color.Color) {
const letterWidth = 6
const letterHeight = 16
parts := []graphics.TexturePart{}
textX := 0
textY := 0
for _, c := range text {
if c == '\n' {
textX = 0
textY += letterHeight
continue
}
code := int(c)
x := (code % 32) * letterWidth
y := (code / 32) * letterHeight
source := graphics.Rect{x, y, letterWidth, letterHeight}
parts = append(parts, graphics.TexturePart{
LocationX: textX,
LocationY: textY,
Source: source,
})
textX += letterWidth
}
geometryMatrix := matrix.IdentityGeometry()
geometryMatrix.Translate(float64(x), float64(y))
colorMatrix := matrix.IdentityColor()
colorMatrix.Scale(clr)
g.DrawTextureParts(drawInfo.textures["text"], parts,
geometryMatrix, colorMatrix)
}*/

View File

@ -0,0 +1,43 @@
package blocks
import (
"github.com/hajimehoshi/go-ebiten/graphics"
)
type GameState struct {
SceneManager *SceneManager
}
type Scene interface {
Update(state GameState)
Draw(context graphics.Context)
}
type SceneManager struct {
current Scene
next Scene
}
func NewSceneManager(initScene Scene) *SceneManager {
return &SceneManager{
current: initScene,
}
}
func (s *SceneManager) Update() {
if s.next != nil {
s.current = s.next
s.next = nil
}
s.current.Update(GameState{
SceneManager: s,
})
}
func (s *SceneManager) Draw(context graphics.Context) {
s.current.Draw(context)
}
func (s *SceneManager) GoTo(scene Scene) {
s.next = scene
}

View File

@ -0,0 +1,81 @@
package blocks
import (
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
"image/color"
)
type TitleScene struct {
count int
}
func NewTitleScene() *TitleScene {
return &TitleScene{}
}
func (s *TitleScene) Update(state GameState) {
s.count++
}
func (s *TitleScene) Draw(context graphics.Context) {
drawTitleBackground(context, s.count)
drawLogo(context, "BLOCKS")
}
func drawTitleBackground(context graphics.Context, c int) {
const textureWidth = 32
const textureHeight = 32
backgroundTextureId := drawInfo.textures["background"]
parts := []graphics.TexturePart{}
for j := -1; j < ScreenHeight/textureHeight+1; j++ {
for i := 0; i < ScreenWidth/textureWidth+1; i++ {
parts = append(parts, graphics.TexturePart{
LocationX: i*textureWidth,
LocationY: j*textureHeight,
Source: graphics.Rect{0, 0, textureWidth, textureHeight},
})
}
}
dx := -c % textureWidth / 2
dy := c % textureHeight / 2
geo := matrix.IdentityGeometry()
geo.Translate(float64(dx), float64(dy))
context.DrawTextureParts(backgroundTextureId, parts, geo, matrix.IdentityColor())
}
func drawLogo(context graphics.Context, str string) {
const charWidth = 8
const charHeight = 8
fontTextureId := drawInfo.textures["font"]
parts := []graphics.TexturePart{}
locationX := 0
locationY := 0
for _, c := range str {
if c == '\n' {
locationX = 0
locationY += charHeight
continue
}
code := int(c)
x := (code % 16) * charWidth
y := ((code - 32) / 16) * charHeight
parts = append(parts, graphics.TexturePart{
LocationX: locationX,
LocationY: locationY,
Source: graphics.Rect{x, y, charWidth, charHeight},
})
locationX += charWidth
}
geo := matrix.IdentityGeometry()
geo.Scale(4, 4)
clr := matrix.IdentityColor()
clr.Scale(color.RGBA{0x00, 0x00, 0x60, 0xff})
context.DrawTextureParts(fontTextureId, parts, geo, clr)
}

View File

@ -1,183 +0,0 @@
package main
import (
"fmt"
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
"github.com/hajimehoshi/go-ebiten/ui"
"image/color"
"math"
)
var TexturePaths = map[string]string{
"ebiten": "images/ebiten.png",
"text": "images/text.png",
}
type Size struct {
Width int
Height int
}
var RenderTargetSizes = map[string]Size{
"whole": Size{256, 254},
}
type drawInfo struct {
textures map[string]graphics.TextureId
renderTargets map[string]graphics.RenderTargetId
inputStr string
textureX int
textureY int
textureAngle float64
textureGeo matrix.Geometry
}
type Game struct {
mouseX int
mouseY int
mousePrevX int
mousePrevY int
counter int
drawInfo
}
func NewGame() *Game {
return &Game{
mouseX: -1,
mouseY: -1,
mousePrevX: -1,
mousePrevY: -1,
counter: 0,
drawInfo: drawInfo{
textures: map[string]graphics.TextureId{},
renderTargets: map[string]graphics.RenderTargetId{},
textureX: 0,
textureY: 0,
textureAngle: 0,
textureGeo: matrix.IdentityGeometry(),
},
}
}
func (game *Game) HandleEvent(e interface{}) {
switch e := e.(type) {
case graphics.TextureCreatedEvent:
if e.Error != nil {
panic(e.Error)
}
game.textures[e.Tag.(string)] = e.Id
case graphics.RenderTargetCreatedEvent:
if e.Error != nil {
panic(e.Error)
}
game.renderTargets[e.Tag.(string)] = e.Id
case ui.KeyStateUpdatedEvent:
fmt.Printf("%v\n", e.Keys)
case ui.MouseStateUpdatedEvent:
game.mouseX, game.mouseY = e.X, e.Y
}
}
func (game *Game) isInitialized() bool {
if len(game.drawInfo.textures) < len(TexturePaths) {
return false
}
if len(game.drawInfo.renderTargets) < len(RenderTargetSizes) {
return false
}
return true
}
func (game *Game) Update() {
if !game.isInitialized() {
return
}
const textureWidth = 57
const textureHeight = 26
game.counter++
game.drawInfo.inputStr = fmt.Sprintf(`Input State:
X: %d
Y: %d`, game.mouseX, game.mouseY)
if game.mousePrevX != -1 && game.mousePrevY != -1 &&
game.mouseX != -1 && game.mouseY != -1 {
dx, dy := game.mouseX-game.mousePrevX, game.mouseY-game.mousePrevY
game.textureX += dx
game.textureY += dy
}
game.drawInfo.textureAngle = 2 * math.Pi * float64(game.counter) / 600
geo := matrix.IdentityGeometry()
geo.Translate(-textureWidth/2, -textureHeight/2)
geo.Rotate(game.drawInfo.textureAngle)
geo.Translate(textureWidth/2, textureHeight/2)
geo.Translate(float64(game.textureX), float64(game.textureY))
game.drawInfo.textureGeo = geo
// Update for the next frame.
game.mousePrevX, game.mousePrevY = game.mouseX, game.mouseY
}
func (game *Game) Draw(g graphics.Context) {
if !game.isInitialized() {
return
}
whole := game.drawInfo.renderTargets["whole"]
g.SetOffscreen(whole)
g.Fill(0x70, 0x90, 0xe0)
game.drawTexture(g, game.drawInfo.textureGeo, matrix.IdentityColor())
game.drawText(g, game.drawInfo.inputStr, 6, 6, &color.RGBA{0x0, 0x0, 0x0, 0x80})
game.drawText(g, game.drawInfo.inputStr, 5, 5, color.White)
g.ResetOffscreen()
g.DrawRenderTarget(whole, matrix.IdentityGeometry(), matrix.IdentityColor())
wholeGeo := matrix.IdentityGeometry()
wholeGeo.Scale(0.5, 0.5)
wholeGeo.Translate(256/2, 240/2)
wholeColor := matrix.IdentityColor()
wholeColor.Scale(&color.RGBA{0x80, 0x80, 0x80, 0x80})
g.DrawRenderTarget(whole, wholeGeo, wholeColor)
}
func (game *Game) drawText(g graphics.Context, text string, x, y int, clr color.Color) {
const letterWidth = 6
const letterHeight = 16
parts := []graphics.TexturePart{}
textX := 0
textY := 0
for _, c := range text {
if c == '\n' {
textX = 0
textY += letterHeight
continue
}
code := int(c)
x := (code % 32) * letterWidth
y := (code / 32) * letterHeight
source := graphics.Rect{x, y, letterWidth, letterHeight}
parts = append(parts, graphics.TexturePart{
LocationX: textX,
LocationY: textY,
Source: source,
})
textX += letterWidth
}
geometryMatrix := matrix.IdentityGeometry()
geometryMatrix.Translate(float64(x), float64(y))
colorMatrix := matrix.IdentityColor()
colorMatrix.Scale(clr)
g.DrawTextureParts(game.drawInfo.textures["text"], parts,
geometryMatrix, colorMatrix)
}
func (game *Game) drawTexture(g graphics.Context, geo matrix.Geometry, color matrix.Color) {
g.DrawTexture(game.drawInfo.textures["ebiten"], geo, color)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,38 +1,28 @@
package main
import (
"github.com/hajimehoshi/go-ebiten/example/blocks"
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/ui"
"github.com/hajimehoshi/go-ebiten/ui/cocoa"
"image"
_ "image/png"
"os"
"runtime"
"time"
)
type Game interface {
HandleEvent(e interface{})
Update()
Draw(c graphics.Context)
}
func init() {
runtime.LockOSThread()
}
func loadImage(path string) (image.Image, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return nil, err
}
return img, nil
}
func main() {
const screenWidth = 256
const screenHeight = 240
const screenScale = 3
const screenWidth = blocks.ScreenWidth
const screenHeight = blocks.ScreenHeight
const screenScale = 2
const fps = 60
const title = "Ebiten Demo"
@ -42,33 +32,13 @@ func main() {
textureFactoryEvents := textureFactory.Events()
for tag, path := range TexturePaths {
tag := tag
path := path
go func() {
img, err := loadImage(path)
if err != nil {
panic(err)
}
textureFactory.CreateTexture(tag, img)
}()
}
for tag, size := range RenderTargetSizes {
tag := tag
size := size
go func() {
textureFactory.CreateRenderTarget(tag, size.Width, size.Height)
}()
}
drawing := make(chan *graphics.LazyContext)
quit := make(chan struct{})
go func() {
defer close(quit)
windowEvents := window.Events()
game := NewGame()
var game Game = blocks.NewGame(textureFactory)
frameTime := time.Duration(int64(time.Second) / int64(fps))
tick := time.Tick(frameTime)
for {
@ -76,10 +46,10 @@ func main() {
case e := <-textureFactoryEvents:
game.HandleEvent(e)
case e := <-windowEvents:
game.HandleEvent(e)
if _, ok := e.(ui.WindowClosedEvent); ok {
return
}
game.HandleEvent(e)
case <-tick:
game.Update()
case context := <-drawing:

View File

@ -1,9 +1,5 @@
package graphics
import (
"image/color"
)
type Rect struct {
X int
Y int
@ -17,11 +13,12 @@ type TexturePart struct {
Source Rect
}
type Line struct {
X1, Y1 int
X2, Y2 int
Color color.Color
}
type Filter int
const (
FilterNearest Filter = iota
FilterLinear
)
type TextureId int

View File

@ -9,7 +9,6 @@ import (
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/offscreen"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/texture"
"math"
)
@ -29,10 +28,11 @@ func newContext(ids *ids, screenWidth, screenHeight, screenScale int) *Context {
var err error
context.screenId, err = ids.CreateRenderTarget(
screenWidth, screenHeight, texture.FilterNearest)
screenWidth, screenHeight, graphics.FilterNearest)
if err != nil {
panic("initializing the offscreen failed: " + err.Error())
}
context.Clear()
return context
}
@ -98,10 +98,6 @@ func (context *Context) DrawRenderTargetParts(
context.DrawTextureParts(context.ids.ToTexture(id), parts, geometryMatrix, colorMatrix)
}
func (context *Context) DrawLines(lines []graphics.Line) {
context.offscreen.DrawLines(lines)
}
func (context *Context) ResetOffscreen() {
context.SetOffscreen(context.screenId)
}

View File

@ -2,7 +2,6 @@ package opengl
import (
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/texture"
"image"
)
@ -26,13 +25,13 @@ func (d *Device) Update(context *Context, draw func(graphics.Context)) {
}
func (d *Device) CreateRenderTarget(width, height int) (graphics.RenderTargetId, error) {
renderTargetId, err := d.ids.CreateRenderTarget(width, height, texture.FilterLinear)
renderTargetId, err := d.ids.CreateRenderTarget(width, height, graphics.FilterLinear)
if err != nil {
return 0, err
}
return renderTargetId, nil
}
func (d *Device) CreateTexture(img image.Image) (graphics.TextureId, error) {
return d.ids.CreateTextureFromImage(img)
func (d *Device) CreateTexture(img image.Image, filter graphics.Filter) (graphics.TextureId, error) {
return d.ids.CreateTexture(img, filter)
}

View File

@ -50,9 +50,9 @@ func (i *ids) ToTexture(id graphics.RenderTargetId) graphics.TextureId {
return i.renderTargetToTexture[id]
}
func (i *ids) CreateTextureFromImage(img image.Image) (
func (i *ids) CreateTexture(img image.Image, filter graphics.Filter) (
graphics.TextureId, error) {
texture, err := texture.CreateFromImage(img)
texture, err := texture.CreateFromImage(img, filter)
if err != nil {
return 0, err
}
@ -64,7 +64,7 @@ func (i *ids) CreateTextureFromImage(img image.Image) (
return textureId, nil
}
func (i *ids) CreateRenderTarget(width, height int, filter texture.Filter) (
func (i *ids) CreateRenderTarget(width, height int, filter graphics.Filter) (
graphics.RenderTargetId, error) {
renderTarget, texture, err := rendertarget.Create(width, height, filter)
if err != nil {

View File

@ -63,10 +63,6 @@ func (o *Offscreen) DrawTextureParts(texture *gtexture.Texture,
texture.DrawParts(parts, &drawable{o, geometryMatrix, colorMatrix})
}
func (o *Offscreen) DrawLines(lines []graphics.Line) {
// TODO: Implement!
}
type setter struct {
offscreen *Offscreen
usingMainFramebuffer bool

View File

@ -5,6 +5,7 @@ package rendertarget
// #include <OpenGL/gl.h>
import "C"
import (
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/opengl/texture"
gtexture "github.com/hajimehoshi/go-ebiten/graphics/texture"
)
@ -43,7 +44,7 @@ func (f *framebufferCreator) Create(native interface{}) interface{} {
return createFramebuffer(C.GLuint(native.(texture.Native)))
}
func Create(width, height int, filter texture.Filter) (
func Create(width, height int, filter graphics.Filter) (
*gtexture.RenderTarget, *gtexture.Texture, error) {
tex, err := texture.Create(width, height, filter)
if err != nil {

View File

@ -5,6 +5,7 @@ package texture
// #include <OpenGL/gl.h>
import "C"
import (
"github.com/hajimehoshi/go-ebiten/graphics"
gtexture "github.com/hajimehoshi/go-ebiten/graphics/texture"
"image"
"unsafe"
@ -12,15 +13,8 @@ import (
type Native C.GLuint
type Filter int
const (
FilterLinear Filter = iota
FilterNearest
)
func createNativeTexture(textureWidth, textureHeight int, pixels []uint8,
filter Filter) Native {
filter graphics.Filter) Native {
nativeTexture := C.GLuint(0)
C.glGenTextures(1, (*C.GLuint)(&nativeTexture))
@ -33,9 +27,9 @@ func createNativeTexture(textureWidth, textureHeight int, pixels []uint8,
glFilter := C.GLint(0)
switch filter {
case FilterLinear:
case graphics.FilterLinear:
glFilter = C.GL_LINEAR
case FilterNearest:
case graphics.FilterNearest:
glFilter = C.GL_NEAREST
default:
panic("not reached")
@ -54,17 +48,12 @@ func createNativeTexture(textureWidth, textureHeight int, pixels []uint8,
return Native(nativeTexture)
}
func create(textureWidth, textureHeight int, filter Filter) (
func create(textureWidth, textureHeight int, filter graphics.Filter) (
interface{}, error) {
return createNativeTexture(textureWidth, textureHeight, nil, filter), nil
}
func createFromImage(img *image.NRGBA) (interface{}, error) {
size := img.Bounds().Size()
return createNativeTexture(size.X, size.Y, img.Pix, FilterLinear), nil
}
func Create(width, height int, filter Filter) (*gtexture.Texture, error) {
func Create(width, height int, filter graphics.Filter) (*gtexture.Texture, error) {
native, err := create(gtexture.AdjustSize(width),
gtexture.AdjustSize(height), filter)
if err != nil {
@ -73,11 +62,9 @@ func Create(width, height int, filter Filter) (*gtexture.Texture, error) {
return gtexture.New(native, width, height), nil
}
func CreateFromImage(img image.Image) (*gtexture.Texture, error) {
native, err := createFromImage(gtexture.AdjustImage(img))
if err != nil {
return nil, err
}
size := img.Bounds().Size()
func CreateFromImage(img image.Image, filter graphics.Filter) (*gtexture.Texture, error) {
adjustedImage := gtexture.AdjustImage(img)
size := adjustedImage.Bounds().Size()
native := createNativeTexture(size.X, size.Y, adjustedImage.Pix, filter)
return gtexture.New(native, size.X, size.Y), nil
}

View File

@ -36,7 +36,7 @@ func AdjustImage(img image.Image) *image.NRGBA {
AdjustSize(height),
},
}
if nrgba := img.(*image.NRGBA); nrgba != nil &&
if nrgba, ok := img.(*image.NRGBA); ok &&
img.Bounds() == adjustedImageBounds {
return nrgba
}

View File

@ -18,6 +18,6 @@ type RenderTargetCreatedEvent struct {
type TextureFactory interface {
CreateRenderTarget(tag interface{}, width, height int)
CreateTexture(tag interface{}, img image.Image)
CreateTexture(tag interface{}, img image.Image, filter Filter)
Events() <-chan interface{}
}

View File

@ -15,9 +15,9 @@ import (
)
type cocoaUI struct {
textureFactory *textureFactory
textureFactory *textureFactory
textureFactoryEvents chan interface{}
graphicsDevice *opengl.Device
graphicsDevice *opengl.Device
}
var currentUI *cocoaUI
@ -63,12 +63,12 @@ func (u *cocoaUI) Events() <-chan interface{} {
return u.textureFactoryEvents
}
func (u *cocoaUI) CreateTexture(tag interface{}, img image.Image) {
func (u *cocoaUI) CreateTexture(tag interface{}, img image.Image, filter graphics.Filter) {
go func() {
var id graphics.TextureId
var err error
u.textureFactory.useGLContext(func() {
id, err = u.graphicsDevice.CreateTexture(img)
id, err = u.graphicsDevice.CreateTexture(img, filter)
})
if u.textureFactoryEvents == nil {
return

View File

@ -114,12 +114,13 @@ func (w *Window) notify(e interface{}) {
}()
}
/*//export ebiten_ScreenSizeUpdated
func ebiten_ScreenSizeUpdated(nativeWindow unsafe.Pointer, width, height int) {
u := currentUI
e := ui.ScreenSizeUpdatedEvent{width, height}
u.windowEvents.notifyScreenSizeUpdated(e)
}*/
// Now this function is not used anywhere.
//export ebiten_WindowSizeUpdated
func ebiten_WindowSizeUpdated(nativeWindow unsafe.Pointer, width, height int) {
w := windows[nativeWindow]
e := ui.WindowSizeUpdatedEvent{width, height}
w.notify(e)
}
func (w *Window) keyStateUpdatedEvent() ui.KeyStateUpdatedEvent {
keys := []ui.Key{}
@ -132,6 +133,7 @@ func (w *Window) keyStateUpdatedEvent() ui.KeyStateUpdatedEvent {
}
var cocoaKeyCodeToKey = map[int]ui.Key{
49: ui.KeySpace,
123: ui.KeyLeft,
124: ui.KeyRight,
125: ui.KeyUp,

View File

@ -11,9 +11,10 @@ const (
KeyDown
KeyLeft
KeyRight
KeySpace
)
type ScreenSizeUpdatedEvent struct {
type WindowSizeUpdatedEvent struct {
Width int
Height int
}