Add examples/glut/main.go

This commit is contained in:
Hajime Hoshi 2013-06-17 23:10:55 +09:00
parent b8a1a1806c
commit e9fa26142e
4 changed files with 182 additions and 112 deletions

73
examples/glut/main.go Normal file
View File

@ -0,0 +1,73 @@
package main
// #cgo LDFLAGS: -framework GLUT -framework OpenGL
//
// #include <stdlib.h>
// #include <GLUT/glut.h>
//
// void display(void);
//
// static void setDisplayFunc(void) {
// glutDisplayFunc(display);
// }
//
import "C"
import (
"image/color"
"os"
"unsafe"
"github.com/hajimehoshi/go-ebiten/graphics"
)
var device *graphics.Device
type DemoGame struct {
}
func (game *DemoGame) Update() {
}
func (game *DemoGame) Draw(g *graphics.GraphicsContext, offscreen *graphics.Texture) {
g.Fill(&color.RGBA{R: 0, G: 0, B: 255, A: 255})
}
//export display
func display() {
device.Update()
}
func main() {
cargs := []*C.char{}
for _, arg := range os.Args {
cargs = append(cargs, C.CString(arg))
}
defer func() {
for _, carg := range cargs {
C.free(unsafe.Pointer(carg))
}
}()
cargc := C.int(len(cargs))
screenWidth := 256
screenHeight := 256
screenScale := 1
C.glutInit(&cargc, &cargs[0])
C.glutInitDisplayMode(C.GLUT_RGBA);
C.glutInitWindowSize(C.int(screenWidth * screenScale),
C.int(screenHeight * screenScale))
title := C.CString("Ebiten Demo")
defer C.free(unsafe.Pointer(title))
C.glutCreateWindow(title)
C.setDisplayFunc()
game := &DemoGame{}
device = graphics.NewDevice(screenWidth, screenHeight, screenScale,
func(g *graphics.GraphicsContext, offscreen *graphics.Texture) {
game.Draw(g, offscreen)
})
C.glutMainLoop()
}

View File

@ -6,7 +6,7 @@ package graphics
// #include <stdlib.h> // #include <stdlib.h>
import "C" import "C"
type device struct { type Device struct {
screenWidth int screenWidth int
screenHeight int screenHeight int
screenScale int screenScale int
@ -15,9 +15,9 @@ type device struct {
drawFunc func(*GraphicsContext, *Texture) drawFunc func(*GraphicsContext, *Texture)
} }
// This method should be called on the UI thread?? func NewDevice(screenWidth, screenHeight, screenScale int,
func newDevice(screenWidth, screenHeight, screenScale int, drawFunc func(*GraphicsContext, *Texture)) *device { drawFunc func(*GraphicsContext, *Texture)) *Device {
return &device{ device := &Device{
screenWidth: screenWidth, screenWidth: screenWidth,
screenHeight: screenHeight, screenHeight: screenHeight,
screenScale: screenScale, screenScale: screenScale,
@ -25,29 +25,29 @@ func newDevice(screenWidth, screenHeight, screenScale int, drawFunc func(*Graphi
offscreenTexture: NewTexture(screenWidth, screenHeight), offscreenTexture: NewTexture(screenWidth, screenHeight),
drawFunc: drawFunc, drawFunc: drawFunc,
} }
return device
} }
// This method should be called on the UI thread?? func (device *Device) Update() {
func (d *device) Update() { g := device.graphicsContext
g := d.graphicsContext
// g.initialize()
C.glEnable(C.GL_TEXTURE_2D) C.glEnable(C.GL_TEXTURE_2D)
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_NEAREST) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_NEAREST)
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_NEAREST) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_NEAREST)
g.SetOffscreen(d.offscreenTexture) g.SetOffscreen(device.offscreenTexture)
g.Clear() g.Clear()
d.drawFunc(g, d.offscreenTexture) // TODO: lock this!
device.drawFunc(g, device.offscreenTexture)
g.flush() g.flush()
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR)
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 := IdentityGeometryMatrix()
geometryMatrix.SetA(AffineMatrixElement(g.screenScale)) geometryMatrix.SetA(AffineMatrixElement(g.screenScale))
geometryMatrix.SetD(AffineMatrixElement(g.screenScale)) geometryMatrix.SetD(AffineMatrixElement(g.screenScale))
g.DrawTexture(d.offscreenTexture, g.DrawTexture(device.offscreenTexture,
0, 0, d.screenWidth, d.screenHeight, 0, 0, device.screenWidth, device.screenHeight,
geometryMatrix, IdentityColorMatrix()) geometryMatrix, IdentityColorMatrix())
g.flush() g.flush()
} }

View File

@ -2,14 +2,13 @@ package graphics
// #cgo LDFLAGS: -framework OpenGL // #cgo LDFLAGS: -framework OpenGL
// //
// #include <OpenGL/gl.h>
// #include <stdlib.h> // #include <stdlib.h>
// #include <OpenGL/gl.h>
import "C" import "C"
import ( import (
"image/color" "image/color"
"math" "math"
"unsafe" "unsafe"
"../ui"
) )
type GraphicsContext struct { type GraphicsContext struct {
@ -35,30 +34,30 @@ func newGraphicsContext(screenWidth, screenHeight, screenScale int) *GraphicsCon
mainFramebuffer := C.GLint(0) mainFramebuffer := C.GLint(0)
C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer) C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer)
context.mainFramebuffer = C.GLuint(mainFramebuffer) context.mainFramebuffer = C.GLuint(mainFramebuffer)
initializeShaders()
return context return context
} }
func (context *GraphicsContext) Clear() { func (context *GraphicsContext) Clear() {
ui.ExecuteOnUIThread(func() { C.glClearColor(0, 0, 0, 1)
C.glClearColor(0, 0, 0, 1) 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(color color.Color) {
r, g, b, a := color.RGBA() r, g, b, a := color.RGBA()
ui.ExecuteOnUIThread(func() { max := 65535.0
max := 65535.0 C.glClearColor(
C.glClearColor( C.GLclampf(float64(r) / max),
C.GLclampf(float64(r) / max), C.GLclampf(float64(g) / max),
C.GLclampf(float64(g) / max), C.GLclampf(float64(b) / max),
C.GLclampf(float64(b) / max), C.GLclampf(float64(a) / max))
C.GLclampf(float64(a) / max)) 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, color color.Color) {
// TODO: implement!
} }
func (context *GraphicsContext) DrawTexture(texture *Texture, func (context *GraphicsContext) DrawTexture(texture *Texture,
@ -67,90 +66,88 @@ func (context *GraphicsContext) DrawTexture(texture *Texture,
geometryMatrix = geometryMatrix.Clone() geometryMatrix = geometryMatrix.Clone()
colorMatrix = colorMatrix.Clone() colorMatrix = colorMatrix.Clone()
ui.ExecuteOnUIThread(func() { context.setShaderProgram(geometryMatrix, colorMatrix)
context.setShaderProgram(geometryMatrix, colorMatrix) C.glBindTexture(C.GL_TEXTURE_2D, texture.id)
C.glBindTexture(C.GL_TEXTURE_2D, texture.id)
x1 := float32(0) x1 := float32(0)
x2 := float32(srcWidth) x2 := float32(srcWidth)
y1 := float32(0) y1 := float32(0)
y2 := float32(srcHeight) y2 := float32(srcHeight)
vertex := [...]float32{ vertex := [...]float32{
x1, y1, x1, y1,
x2, y1, x2, y1,
x1, y2, x1, y2,
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,
tu1, tv2, tu1, tv2,
tu2, tv2, tu2, tv2,
} }
vertexAttrLocation := getAttributeLocation(context.currentShaderProgram, "vertex") vertexAttrLocation := getAttributeLocation(context.currentShaderProgram, "vertex")
textureAttrLocation := getAttributeLocation(context.currentShaderProgram, "texture") textureAttrLocation := getAttributeLocation(context.currentShaderProgram, "texture")
C.glEnableClientState(C.GL_VERTEX_ARRAY) C.glEnableClientState(C.GL_VERTEX_ARRAY)
C.glEnableClientState(C.GL_TEXTURE_COORD_ARRAY) C.glEnableClientState(C.GL_TEXTURE_COORD_ARRAY)
C.glEnableVertexAttribArray(C.GLuint(vertexAttrLocation)) C.glEnableVertexAttribArray(C.GLuint(vertexAttrLocation))
C.glEnableVertexAttribArray(C.GLuint(textureAttrLocation)) C.glEnableVertexAttribArray(C.GLuint(textureAttrLocation))
C.glVertexAttribPointer(C.GLuint(vertexAttrLocation), 2, C.GL_FLOAT, C.GL_FALSE, C.glVertexAttribPointer(C.GLuint(vertexAttrLocation), 2, C.GL_FLOAT, C.GL_FALSE,
0, unsafe.Pointer(&vertex[0])) 0, unsafe.Pointer(&vertex[0]))
C.glVertexAttribPointer(C.GLuint(textureAttrLocation), 2, C.GL_FLOAT, C.GL_FALSE, C.glVertexAttribPointer(C.GLuint(textureAttrLocation), 2, C.GL_FLOAT, C.GL_FALSE,
0, unsafe.Pointer(&texCoord[0])) 0, unsafe.Pointer(&texCoord[0]))
C.glDrawArrays(C.GL_TRIANGLE_STRIP, 0, 4) C.glDrawArrays(C.GL_TRIANGLE_STRIP, 0, 4)
C.glDisableVertexAttribArray(C.GLuint(textureAttrLocation)) C.glDisableVertexAttribArray(C.GLuint(textureAttrLocation))
C.glDisableVertexAttribArray(C.GLuint(vertexAttrLocation)) C.glDisableVertexAttribArray(C.GLuint(vertexAttrLocation))
C.glDisableClientState(C.GL_TEXTURE_COORD_ARRAY) C.glDisableClientState(C.GL_TEXTURE_COORD_ARRAY)
C.glDisableClientState(C.GL_VERTEX_ARRAY) C.glDisableClientState(C.GL_VERTEX_ARRAY)
})
} }
func (context *GraphicsContext) SetOffscreen(texture *Texture) { func (context *GraphicsContext) SetOffscreen(texture *Texture) {
ui.ExecuteOnUIThread(func() { framebuffer := C.GLuint(0)
framebuffer := C.GLuint(0) if texture != nil {
if texture != nil { framebuffer = context.getFramebuffer(texture)
framebuffer = context.getFramebuffer(texture) } else {
} else { framebuffer = context.mainFramebuffer
framebuffer = context.mainFramebuffer }
} C.glBindFramebuffer(C.GL_FRAMEBUFFER, framebuffer)
C.glBindFramebuffer(C.GL_FRAMEBUFFER, framebuffer) if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) != C.GL_FRAMEBUFFER_COMPLETE {
// TODO: assert glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE panic("glBindFramebuffer failed")
C.glEnable(C.GL_BLEND) }
C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA) C.glEnable(C.GL_BLEND)
C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA)
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 {
width = context.screenWidth * context.screenScale width = context.screenWidth * context.screenScale
height = -1 * context.screenHeight * context.screenScale height = -1 * context.screenHeight * context.screenScale
tx = -1 tx = -1
ty = 1 ty = 1
} }
C.glViewport(0, 0, C.glViewport(0, 0,
C.GLsizei(math.Abs(float64(width))), C.GLsizei(math.Abs(float64(width))),
C.GLsizei(math.Abs(float64(height)))) C.GLsizei(math.Abs(float64(height))))
e11 := float32(2.0 / width) e11 := float32(2.0) / float32(width)
e22 := float32(2.0 / height) e22 := float32(2.0) / float32(height)
e41 := float32(tx) e41 := float32(tx)
e42 := float32(ty) e42 := float32(ty)
context.projectionMatrix = [...]float32{ context.projectionMatrix = [...]float32{
e11, 0, 0, 0, e11, 0, 0, 0,
0, e22, 0, 0, 0, e22, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
e41, e42, 0, 1, e41, e42, 0, 1,
} }
})
} }
func (context *GraphicsContext) resetOffscreen() { func (context *GraphicsContext) resetOffscreen() {

View File

@ -7,7 +7,7 @@ import "C"
import ( import (
"image" "image"
"unsafe" "unsafe"
"../ui" "github.com/hajimehoshi/go-ebiten/ui"
) )
func Clp2(x uint64) uint64 { func Clp2(x uint64) uint64 {
@ -47,14 +47,18 @@ func createTexture(width, height int, pixels []uint8) *Texture{
} }
ch := make(chan C.GLuint) ch := make(chan C.GLuint)
// TODO: should wait?
go func() {
texture.id = <-ch
}()
ui.ExecuteOnUIThread(func() { ui.ExecuteOnUIThread(func() {
textureID := C.GLuint(0) textureID := C.GLuint(0)
C.glGenTextures(1, (*C.GLuint)(&textureID)) C.glGenTextures(1, (*C.GLuint)(&textureID))
if textureID == 0 {
panic("glGenTexture failed")
}
C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 4) C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 4)
C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(textureID)) C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(textureID))
if textureID != 0 {
panic("glBindTexture failed")
}
ptr := unsafe.Pointer(nil) ptr := unsafe.Pointer(nil)
if pixels != nil { if pixels != nil {
@ -71,10 +75,6 @@ func createTexture(width, height int, pixels []uint8) *Texture{
ch<- textureID ch<- textureID
close(ch) close(ch)
}) })
// TODO: should wait?
go func() {
texture.id = <-ch
}()
return texture return texture
} }