Apply 'Tell, don't ask'

This commit is contained in:
Hajime Hoshi 2013-10-25 09:30:39 +09:00
parent 9aded38cc2
commit b15febed51
5 changed files with 154 additions and 105 deletions

View File

@ -44,3 +44,17 @@ type TextureId int
// A render target is essentially same as a texture, but it is assumed that the // A render target is essentially same as a texture, but it is assumed that the
// all alpha of a render target is maximum. // all alpha of a render target is maximum.
type RenderTargetId int 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)
e14 := -1 * float64(right+left) / float64(right-left)
e24 := -1 * float64(top+bottom) / float64(top-bottom)
return [4][4]float64{
{e11, 0, 0, e14},
{0, e22, 0, e24},
{0, 0, 1, 0},
{0, 0, 0, 1},
}
}

View File

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"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"
"github.com/hajimehoshi/go-ebiten/graphics/texture"
"image" "image"
"math" "math"
"unsafe" "unsafe"
@ -19,7 +20,7 @@ type Context struct {
screenWidth int screenWidth int
screenHeight int screenHeight int
screenScale int screenScale int
textures map[graphics.TextureId]*Texture textures map[graphics.TextureId]*texture.Texture
renderTargets map[graphics.RenderTargetId]*RenderTarget renderTargets map[graphics.RenderTargetId]*RenderTarget
renderTargetToTexture map[graphics.RenderTargetId]graphics.TextureId renderTargetToTexture map[graphics.RenderTargetId]graphics.TextureId
currentOffscreen *RenderTarget currentOffscreen *RenderTarget
@ -32,7 +33,7 @@ func newContext(screenWidth, screenHeight, screenScale int) *Context {
screenWidth: screenWidth, screenWidth: screenWidth,
screenHeight: screenHeight, screenHeight: screenHeight,
screenScale: screenScale, screenScale: screenScale,
textures: map[graphics.TextureId]*Texture{}, textures: map[graphics.TextureId]*texture.Texture{},
renderTargets: map[graphics.RenderTargetId]*RenderTarget{}, renderTargets: map[graphics.RenderTargetId]*RenderTarget{},
renderTargetToTexture: map[graphics.RenderTargetId]graphics.TextureId{}, renderTargetToTexture: map[graphics.RenderTargetId]graphics.TextureId{},
} }
@ -45,14 +46,17 @@ func (context *Context) Init() {
mainFramebuffer := C.GLint(0) mainFramebuffer := C.GLint(0)
C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer) C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer)
context.mainFramebufferTexture = newRenderTargetWithFramebuffer( var err error
context.mainFramebufferTexture, err = newRenderTargetWithFramebuffer(
context.screenWidth*context.screenScale, context.screenWidth*context.screenScale,
context.screenHeight*context.screenScale, context.screenHeight*context.screenScale,
C.GLuint(mainFramebuffer)) C.GLuint(mainFramebuffer))
if err != nil {
panic("creating main framebuffer failed: " + err.Error())
}
initializeShaders() initializeShaders()
var err error
context.screenId, err = context.NewRenderTarget( context.screenId, err = context.NewRenderTarget(
context.screenWidth, context.screenHeight) context.screenWidth, context.screenHeight)
if err != nil { if err != nil {
@ -85,7 +89,8 @@ func (context *Context) DrawTexture(
if !ok { if !ok {
panic("invalid texture ID") panic("invalid texture ID")
} }
source := graphics.Rect{0, 0, texture.width, texture.height} // TODO: fix this
source := graphics.Rect{0, 0, texture.Width(), texture.Height()}
locations := []graphics.TexturePart{{0, 0, source}} locations := []graphics.TexturePart{{0, 0, source}}
context.DrawTextureParts(textureId, locations, context.DrawTextureParts(textureId, locations,
geometryMatrix, colorMatrix) geometryMatrix, colorMatrix)
@ -175,26 +180,12 @@ func (context *Context) setOffscreen(renderTarget *RenderTarget) {
context.currentOffscreen.SetAsViewport(context) context.currentOffscreen.SetAsViewport(context)
} }
func orthoProjectionMatrix(left, right, bottom, top int) [4][4]float64 {
e11 := float64(2) / float64(right-left)
e22 := float64(2) / float64(top-bottom)
e14 := -1 * float64(right+left) / float64(right-left)
e24 := -1 * float64(top+bottom) / float64(top-bottom)
return [4][4]float64{
{e11, 0, 0, e14},
{0, e22, 0, e24},
{0, 0, 1, 0},
{0, 0, 0, 1},
}
}
func (context *Context) SetViewport(x, y, width, height int) { func (context *Context) SetViewport(x, y, width, height int) {
C.glViewport(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height)) C.glViewport(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height))
matrix := orthoProjectionMatrix(x, width, y, height) matrix := graphics.OrthoProjectionMatrix(x, width, y, height)
if context.currentOffscreen == context.mainFramebufferTexture { if context.currentOffscreen == context.mainFramebufferTexture {
// Flip Y and translate // Flip Y and move to fit with the top of the window.
matrix[1][1] *= -1 matrix[1][1] *= -1
actualHeight := context.screenHeight * context.screenScale actualHeight := context.screenHeight * context.screenScale
matrix[1][3] += float64(actualHeight) / float64(height) * 2 matrix[1][3] += float64(actualHeight) / float64(height) * 2
@ -300,7 +291,7 @@ func (context *Context) NewRenderTarget(width, height int) (
func (context *Context) NewTextureFromImage(img image.Image) ( func (context *Context) NewTextureFromImage(img image.Image) (
graphics.TextureId, error) { graphics.TextureId, error) {
texture, err := newTextureFromImage(img) texture, err := texture.NewFromImage(img, &NativeTextureCreator{})
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -5,62 +5,23 @@ package opengl
// #include <OpenGL/gl.h> // #include <OpenGL/gl.h>
import "C" import "C"
import ( import (
"github.com/hajimehoshi/go-ebiten/graphics/texture"
"image" "image"
"image/draw"
"unsafe" "unsafe"
) )
func nextPowerOf2(x uint64) uint64 {
x -= 1
x |= (x >> 1)
x |= (x >> 2)
x |= (x >> 4)
x |= (x >> 8)
x |= (x >> 16)
x |= (x >> 32)
return x + 1
}
type Texture struct {
native interface{}
width int
height int
}
func (texture *Texture) Native() interface{} {
return texture.native
}
func (texture *Texture) textureWidth() int {
return int(nextPowerOf2(uint64(texture.width)))
}
func (texture *Texture) textureHeight() int {
return int(nextPowerOf2(uint64(texture.height)))
}
func (texture *Texture) U(x int) float64 {
return float64(x) / float64(texture.textureWidth())
}
func (texture *Texture) V(y int) float64 {
return float64(y) / float64(texture.textureHeight())
}
type RenderTarget struct { type RenderTarget struct {
texture *Texture texture *texture.Texture
framebuffer C.GLuint framebuffer C.GLuint
} }
func (renderTarget *RenderTarget) SetAsViewport(setter interface{ func (renderTarget *RenderTarget) SetAsViewport(setter interface{
SetViewport(x, y, width, height int) SetViewport(x, y, width, height int)
}) { }) {
texture := renderTarget.texture renderTarget.texture.SetAsViewport(0, 0, setter)
x, y, width, height := 0, 0, texture.textureWidth(), texture.textureHeight()
setter.SetViewport(x, y, width, height)
} }
func createNativeTexture(textureWidth, textureHeight int, pixels unsafe.Pointer) C.GLuint { func createNativeTexture(textureWidth, textureHeight int, pixels []uint8) C.GLuint {
nativeTexture := C.GLuint(0) nativeTexture := C.GLuint(0)
C.glGenTextures(1, (*C.GLuint)(&nativeTexture)) C.glGenTextures(1, (*C.GLuint)(&nativeTexture))
@ -70,9 +31,13 @@ func createNativeTexture(textureWidth, textureHeight int, pixels unsafe.Pointer)
C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 4) C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 4)
C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(nativeTexture)) C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(nativeTexture))
ptr := unsafe.Pointer(nil)
if pixels != nil {
ptr = unsafe.Pointer(&pixels[0])
}
C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RGBA, C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RGBA,
C.GLsizei(textureWidth), C.GLsizei(textureHeight), C.GLsizei(textureWidth), C.GLsizei(textureHeight),
0, C.GL_RGBA, C.GL_UNSIGNED_BYTE, pixels) 0, C.GL_RGBA, C.GL_UNSIGNED_BYTE, ptr)
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)
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)
@ -81,17 +46,22 @@ func createNativeTexture(textureWidth, textureHeight int, pixels unsafe.Pointer)
return nativeTexture return nativeTexture
} }
func createTexture(width, height int) *Texture { type NativeTextureCreator struct{}
texture := &Texture{
width: width, func (creator *NativeTextureCreator) Create(textureWidth, textureHeight int) (interface{}, error) {
height: height, return createNativeTexture(textureWidth, textureHeight, nil), nil
} }
texture.native = createNativeTexture(texture.textureWidth(), texture.textureHeight(), nil)
return texture func (creator *NativeTextureCreator) CreateFromImage(img *image.NRGBA) (interface{}, error) {
size := img.Bounds().Size()
return createNativeTexture(size.X, size.Y, img.Pix), nil
} }
func newRenderTarget(width, height int) (*RenderTarget, error) { func newRenderTarget(width, height int) (*RenderTarget, error) {
texture := createTexture(width, height) texture, err := texture.New(width, height, &NativeTextureCreator{})
if err != nil {
return nil, err
}
framebuffer := createFramebuffer(texture.Native().(C.GLuint)) framebuffer := createFramebuffer(texture.Native().(C.GLuint))
return &RenderTarget{ return &RenderTarget{
texture: texture, texture: texture,
@ -99,41 +69,15 @@ func newRenderTarget(width, height int) (*RenderTarget, error) {
}, nil }, nil
} }
func newTextureFromImage(img image.Image) (*Texture, error) { func newRenderTargetWithFramebuffer(width, height int, framebuffer C.GLuint) (*RenderTarget, error) {
size := img.Bounds().Size() texture, err := texture.New(width, height, &NativeTextureCreator{})
width, height := size.X, size.Y if err != nil {
return nil, err
texture := &Texture{
width: width,
height: height,
}
adjustedImageBound := image.Rectangle{
image.ZP,
image.Point{texture.textureWidth(), texture.textureHeight()},
}
adjustedImage := image.NewNRGBA(adjustedImageBound)
dstBound := image.Rectangle{
image.ZP,
img.Bounds().Size(),
}
draw.Draw(adjustedImage, dstBound, img, image.ZP, draw.Src)
pixelsPtr := unsafe.Pointer(&adjustedImage.Pix[0])
texture.native = createNativeTexture(
texture.textureWidth(), texture.textureHeight(), pixelsPtr)
return texture, nil
}
func newRenderTargetWithFramebuffer(width, height int,
framebuffer C.GLuint) *RenderTarget {
texture := &Texture{
width: width,
height: height,
} }
return &RenderTarget{ return &RenderTarget{
texture: texture, texture: texture,
framebuffer: framebuffer, framebuffer: framebuffer,
} }, nil
} }
func createFramebuffer(nativeTexture C.GLuint) C.GLuint { func createFramebuffer(nativeTexture C.GLuint) C.GLuint {

View File

@ -0,0 +1,99 @@
package texture
import (
"image"
"image/draw"
)
func nextPowerOf2(x uint64) uint64 {
x -= 1
x |= (x >> 1)
x |= (x >> 2)
x |= (x >> 4)
x |= (x >> 8)
x |= (x >> 16)
x |= (x >> 32)
return x + 1
}
type Texture struct {
native interface{}
width int
height int
}
func New(width, height int, creator interface {
Create(textureWidth, textureHeight int) (interface{}, error)
}) (*Texture, error) {
texture := &Texture{
width: width,
height: height,
}
var err error
texture.native, err = creator.Create(texture.textureWidth(), texture.textureHeight())
if err != nil {
return nil, err
}
return texture, nil
}
func NewFromImage(img image.Image, creator interface {
CreateFromImage(img *image.NRGBA) (interface{}, error)
}) (*Texture, error) {
size := img.Bounds().Size()
width, height := size.X, size.Y
texture := &Texture{
width: width,
height: height,
}
adjustedImageBound := image.Rectangle{
image.ZP,
image.Point{texture.textureWidth(), texture.textureHeight()},
}
adjustedImage := image.NewNRGBA(adjustedImageBound)
dstBound := image.Rectangle{
image.ZP,
img.Bounds().Size(),
}
draw.Draw(adjustedImage, dstBound, img, image.ZP, draw.Src)
var err error
texture.native, err = creator.CreateFromImage(adjustedImage)
if err != nil {
return nil, err
}
return texture, nil
}
func (texture *Texture) Width() int {
return texture.width
}
func (texture *Texture) Height() int {
return texture.height
}
func (texture *Texture) textureWidth() int {
return int(nextPowerOf2(uint64(texture.width)))
}
func (texture *Texture) textureHeight() int {
return int(nextPowerOf2(uint64(texture.height)))
}
func (texture *Texture) Native() interface{} {
return texture.native
}
func (texture *Texture) U(x int) float64 {
return float64(x) / float64(texture.textureWidth())
}
func (texture *Texture) V(y int) float64 {
return float64(y) / float64(texture.textureHeight())
}
func (texture *Texture) SetAsViewport(x, y int, setter interface{
SetViewport(x, y, width, height int)
}) {
setter.SetViewport(x, y, texture.textureWidth(), texture.textureHeight())
}

View File

@ -1,6 +1,7 @@
// This package is experimental. // This package is experimental.
package glut package glut
// #cgo CFLAGS: -Wno-deprecated-declarations
// #cgo LDFLAGS: -framework GLUT -framework OpenGL // #cgo LDFLAGS: -framework GLUT -framework OpenGL
// //
// #include <stdlib.h> // #include <stdlib.h>