Added grahpics/opengl

This commit is contained in:
Hajime Hoshi 2013-06-19 08:49:54 +09:00
parent 0ab7dca5e4
commit 493748ec9e
9 changed files with 100 additions and 44 deletions

View File

@ -3,19 +3,20 @@ package ebiten
import ( import (
"time" "time"
"github.com/hajimehoshi/go-ebiten/graphics" "github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/opengl"
"github.com/hajimehoshi/go-ebiten/ui" "github.com/hajimehoshi/go-ebiten/ui"
) )
type Game interface { type Game interface {
Update() Update()
Draw(g *graphics.GraphicsContext, offscreen *graphics.Texture) Draw(g graphics.GraphicsContext, offscreen graphics.Texture)
} }
func Run(game Game, u ui.UI) { func Run(game Game, u ui.UI) {
ch := make(chan bool, 1) ch := make(chan bool, 1)
device := graphics.NewDevice( device := opengl.NewDevice(
u.ScreenWidth(), u.ScreenHeight(), u.ScreenScale(), u.ScreenWidth(), u.ScreenHeight(), u.ScreenScale(),
func(g *graphics.GraphicsContext, offscreen *graphics.Texture) { func(g graphics.GraphicsContext, offscreen graphics.Texture) {
ticket := <-ch ticket := <-ch
game.Draw(g, offscreen) game.Draw(g, offscreen)
ch<- ticket ch<- ticket

View File

@ -28,7 +28,7 @@ type GlutUI struct{
screenWidth int screenWidth int
screenHeight int screenHeight int
screenScale int screenScale int
device *graphics.Device device graphics.Device
} }
var currentUI *GlutUI var currentUI *GlutUI
@ -85,13 +85,13 @@ func (ui *GlutUI) ScreenScale() int {
return ui.screenScale return ui.screenScale
} }
func (ui *GlutUI) Run(device *graphics.Device) { func (ui *GlutUI) Run(device graphics.Device) {
ui.device = device ui.device = device
C.glutMainLoop() C.glutMainLoop()
} }
type DemoGame struct { type DemoGame struct {
ebitenTexture *graphics.Texture ebitenTexture graphics.Texture
x int x int
} }
@ -108,12 +108,13 @@ func (game *DemoGame) Update() {
panic(err) panic(err)
} }
// TODO: It looks strange to get a texture from the device.
game.ebitenTexture = currentUI.device.NewTextureFromImage(img) game.ebitenTexture = currentUI.device.NewTextureFromImage(img)
} }
game.x++ game.x++
} }
func (game *DemoGame) Draw(g *graphics.GraphicsContext, offscreen *graphics.Texture) { func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen graphics.Texture) {
g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255}) g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255})
if game.ebitenTexture == nil { if game.ebitenTexture == nil {
return return
@ -122,7 +123,7 @@ func (game *DemoGame) Draw(g *graphics.GraphicsContext, offscreen *graphics.Text
geometryMatrix.SetTx(graphics.AffineMatrixElement(game.x)) geometryMatrix.SetTx(graphics.AffineMatrixElement(game.x))
geometryMatrix.SetTy(graphics.AffineMatrixElement(game.x)) geometryMatrix.SetTy(graphics.AffineMatrixElement(game.x))
g.DrawTexture(game.ebitenTexture, g.DrawTexture(game.ebitenTexture,
0, 0, game.ebitenTexture.Width, game.ebitenTexture.Height, 0, 0, game.ebitenTexture.Width(), game.ebitenTexture.Height(),
geometryMatrix, geometryMatrix,
graphics.IdentityColorMatrix()) graphics.IdentityColorMatrix())
} }

29
graphics/graphics.go Normal file
View File

@ -0,0 +1,29 @@
package graphics
import (
"image"
"image/color"
)
type Device interface {
Update()
// TODO: Move somewhere
NewTexture(width, height int) Texture
NewTextureFromImage(img image.Image) Texture
}
type GraphicsContext interface {
Clear()
Fill(color color.Color)
DrawTexture(texture Texture,
srcX, srcY, srcWidth, srcHeight int,
geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix)
SetOffscreen(texture Texture)
}
type Texture interface {
Width() int
Height() int
TextureWidth() int
TextureHeight() int
}

View File

@ -1,4 +1,4 @@
package graphics package opengl
// #cgo LDFLAGS: -framework OpenGL // #cgo LDFLAGS: -framework OpenGL
// //
@ -7,6 +7,7 @@ package graphics
import "C" import "C"
import ( import (
"image" "image"
"github.com/hajimehoshi/go-ebiten/graphics"
) )
type Device struct { type Device struct {
@ -15,12 +16,12 @@ type Device struct {
screenScale int screenScale int
graphicsContext *GraphicsContext graphicsContext *GraphicsContext
offscreenTexture *Texture offscreenTexture *Texture
drawFunc func(*GraphicsContext, *Texture) drawFunc func(graphics.GraphicsContext, graphics.Texture)
funcs []func() funcs []func()
} }
func NewDevice(screenWidth, screenHeight, screenScale int, func NewDevice(screenWidth, screenHeight, screenScale int,
drawFunc func(*GraphicsContext, *Texture)) *Device { drawFunc func(graphics.GraphicsContext, graphics.Texture)) *Device {
device := &Device{ device := &Device{
screenWidth: screenWidth, screenWidth: screenWidth,
screenHeight: screenHeight, screenHeight: screenHeight,
@ -29,7 +30,7 @@ func NewDevice(screenWidth, screenHeight, screenScale int,
drawFunc: drawFunc, drawFunc: drawFunc,
funcs: []func(){}, funcs: []func(){},
} }
device.offscreenTexture = device.NewTexture(screenWidth, screenHeight) device.offscreenTexture = device.NewTexture(screenWidth, screenHeight).(*Texture)
return device return device
} }
@ -52,20 +53,20 @@ func (device *Device) Update() {
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR)
g.resetOffscreen() g.resetOffscreen()
g.Clear() g.Clear()
geometryMatrix := IdentityGeometryMatrix() geometryMatrix := graphics.IdentityGeometryMatrix()
geometryMatrix.SetA(AffineMatrixElement(g.screenScale)) geometryMatrix.SetA(graphics.AffineMatrixElement(g.screenScale))
geometryMatrix.SetD(AffineMatrixElement(g.screenScale)) geometryMatrix.SetD(graphics.AffineMatrixElement(g.screenScale))
g.DrawTexture(device.offscreenTexture, g.DrawTexture(device.offscreenTexture,
0, 0, device.screenWidth, device.screenHeight, 0, 0, device.screenWidth, device.screenHeight,
geometryMatrix, IdentityColorMatrix()) geometryMatrix, graphics.IdentityColorMatrix())
g.flush() g.flush()
} }
func (device *Device) NewTexture(width, height int) *Texture { func (device *Device) NewTexture(width, height int) graphics.Texture {
return createTexture(device, width, height, nil) return createTexture(device, width, height, nil)
} }
func (device *Device) NewTextureFromImage(img image.Image) *Texture { func (device *Device) NewTextureFromImage(img image.Image) graphics.Texture {
var pix []uint8 var pix []uint8
switch img.(type) { switch img.(type) {
case *image.RGBA: case *image.RGBA:

View File

@ -1,4 +1,4 @@
package graphics package opengl
// #cgo LDFLAGS: -framework OpenGL // #cgo LDFLAGS: -framework OpenGL
// //
@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"image/color" "image/color"
"unsafe" "unsafe"
"github.com/hajimehoshi/go-ebiten/graphics"
) )
type GraphicsContext struct { type GraphicsContext struct {
@ -45,8 +46,8 @@ func (context *GraphicsContext) Clear() {
C.glClear(C.GL_COLOR_BUFFER_BIT) C.glClear(C.GL_COLOR_BUFFER_BIT)
} }
func (context *GraphicsContext) Fill(color color.Color) { func (context *GraphicsContext) Fill(clr color.Color) {
r, g, b, a := color.RGBA() r, g, b, a := clr.RGBA()
max := 65535.0 max := 65535.0
C.glClearColor( C.glClearColor(
C.GLclampf(float64(r) / max), C.GLclampf(float64(r) / max),
@ -56,16 +57,18 @@ func (context *GraphicsContext) Fill(color color.Color) {
C.glClear(C.GL_COLOR_BUFFER_BIT) C.glClear(C.GL_COLOR_BUFFER_BIT)
} }
func (context *GraphicsContext) DrawRect(x, y, width, height int, color color.Color) { func (context *GraphicsContext) DrawRect(x, y, width, height int, clr color.Color) {
// TODO: implement! // TODO: implement!
} }
func (context *GraphicsContext) DrawTexture(texture *Texture, func (context *GraphicsContext) DrawTexture(tex graphics.Texture,
srcX, srcY, srcWidth, srcHeight int, srcX, srcY, srcWidth, srcHeight int,
geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix) { geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
geometryMatrix = geometryMatrix.Clone() geometryMatrix = geometryMatrix.Clone()
colorMatrix = colorMatrix.Clone() colorMatrix = colorMatrix.Clone()
texture := tex.(*Texture)
context.setShaderProgram(geometryMatrix, colorMatrix) context.setShaderProgram(geometryMatrix, colorMatrix)
C.glBindTexture(C.GL_TEXTURE_2D, texture.id) C.glBindTexture(C.GL_TEXTURE_2D, texture.id)
@ -80,10 +83,10 @@ func (context *GraphicsContext) DrawTexture(texture *Texture,
x2, y2, x2, y2,
} }
tu1 := float32(srcX) / float32(texture.TextureWidth) tu1 := float32(srcX) / float32(texture.textureWidth)
tu2 := float32(srcX + srcWidth) / float32(texture.TextureWidth) tu2 := float32(srcX + srcWidth) / float32(texture.textureWidth)
tv1 := float32(srcY) / float32(texture.TextureHeight) tv1 := float32(srcY) / float32(texture.textureHeight)
tv2 := float32(srcY + srcHeight) / float32(texture.TextureHeight) tv2 := float32(srcY + srcHeight) / float32(texture.textureHeight)
texCoord := [...]float32{ texCoord := [...]float32{
tu1, tv1, tu1, tv1,
tu2, tv1, tu2, tv1,
@ -116,7 +119,12 @@ func abs(x int) int {
return x return x
} }
func (context *GraphicsContext) SetOffscreen(texture *Texture) { func (context *GraphicsContext) SetOffscreen(tex graphics.Texture) {
var texture *Texture = nil
if tex != nil {
texture = tex.(*Texture)
}
// TODO: glFlush() here?
framebuffer := C.GLuint(0) framebuffer := C.GLuint(0)
if texture != nil { if texture != nil {
framebuffer = context.getFramebuffer(texture) framebuffer = context.getFramebuffer(texture)
@ -135,8 +143,8 @@ func (context *GraphicsContext) SetOffscreen(texture *Texture) {
width, height, tx, ty := 0, 0, 0, 0 width, height, tx, ty := 0, 0, 0, 0
if framebuffer != context.mainFramebuffer { if framebuffer != context.mainFramebuffer {
width = texture.TextureWidth width = texture.textureWidth
height = texture.TextureHeight height = texture.textureHeight
tx = -1 tx = -1
ty = -1 ty = -1
} else { } else {
@ -169,7 +177,7 @@ func (context *GraphicsContext) flush() {
// This method should be called on the UI thread. // This method should be called on the UI thread.
func (context *GraphicsContext) setShaderProgram( func (context *GraphicsContext) setShaderProgram(
geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix) { geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
program := C.GLuint(0) program := C.GLuint(0)
if colorMatrix.IsIdentity() { if colorMatrix.IsIdentity() {
program = regularShaderProgram program = regularShaderProgram

View File

@ -1,4 +1,4 @@
package graphics package opengl
// #cgo LDFLAGS: -framework OpenGL // #cgo LDFLAGS: -framework OpenGL
// //

View File

@ -1,4 +1,4 @@
package graphics package opengl
// #cgo LDFLAGS: -framework OpenGL // #cgo LDFLAGS: -framework OpenGL
// //
@ -21,10 +21,10 @@ func Clp2(x uint64) uint64 {
type Texture struct { type Texture struct {
id C.GLuint id C.GLuint
Width int width int
Height int height int
TextureWidth int textureWidth int
TextureHeight int textureHeight int
} }
func createTexture(device *Device, width, height int, pixels []uint8) *Texture{ func createTexture(device *Device, width, height int, pixels []uint8) *Texture{
@ -40,10 +40,10 @@ func createTexture(device *Device, width, height int, pixels []uint8) *Texture{
} }
texture := &Texture{ texture := &Texture{
id: 0, id: 0,
Width: width, width: width,
Height: height, height: height,
TextureWidth: textureWidth, textureWidth: textureWidth,
TextureHeight: textureHeight, textureHeight: textureHeight,
} }
device.executeWhenDrawing(func() { device.executeWhenDrawing(func() {
@ -74,6 +74,22 @@ func createTexture(device *Device, width, height int, pixels []uint8) *Texture{
return texture return texture
} }
func (texture *Texture) Width() int {
return texture.width
}
func (texture *Texture) Height() int {
return texture.height
}
func (texture *Texture) TextureWidth() int {
return texture.textureWidth
}
func (texture *Texture) TextureHeight() int {
return texture.textureHeight
}
func (texture *Texture) IsAvailable() bool { func (texture *Texture) IsAvailable() bool {
return texture.id != 0 return texture.id != 0
} }

View File

@ -1,4 +1,4 @@
package graphics_test package opengl_test
import ( import (
"testing" "testing"

View File

@ -8,5 +8,5 @@ type UI interface {
ScreenWidth() int ScreenWidth() int
ScreenHeight() int ScreenHeight() int
ScreenScale() int ScreenScale() int
Run(device *graphics.Device) Run(device graphics.Device)
} }