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
// all alpha of a render target is maximum.
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"
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
"github.com/hajimehoshi/go-ebiten/graphics/texture"
"image"
"math"
"unsafe"
@ -19,7 +20,7 @@ type Context struct {
screenWidth int
screenHeight int
screenScale int
textures map[graphics.TextureId]*Texture
textures map[graphics.TextureId]*texture.Texture
renderTargets map[graphics.RenderTargetId]*RenderTarget
renderTargetToTexture map[graphics.RenderTargetId]graphics.TextureId
currentOffscreen *RenderTarget
@ -32,7 +33,7 @@ func newContext(screenWidth, screenHeight, screenScale int) *Context {
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
textures: map[graphics.TextureId]*Texture{},
textures: map[graphics.TextureId]*texture.Texture{},
renderTargets: map[graphics.RenderTargetId]*RenderTarget{},
renderTargetToTexture: map[graphics.RenderTargetId]graphics.TextureId{},
}
@ -45,14 +46,17 @@ func (context *Context) Init() {
mainFramebuffer := C.GLint(0)
C.glGetIntegerv(C.GL_FRAMEBUFFER_BINDING, &mainFramebuffer)
context.mainFramebufferTexture = newRenderTargetWithFramebuffer(
var err error
context.mainFramebufferTexture, err = newRenderTargetWithFramebuffer(
context.screenWidth*context.screenScale,
context.screenHeight*context.screenScale,
C.GLuint(mainFramebuffer))
if err != nil {
panic("creating main framebuffer failed: " + err.Error())
}
initializeShaders()
var err error
context.screenId, err = context.NewRenderTarget(
context.screenWidth, context.screenHeight)
if err != nil {
@ -85,7 +89,8 @@ func (context *Context) DrawTexture(
if !ok {
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}}
context.DrawTextureParts(textureId, locations,
geometryMatrix, colorMatrix)
@ -175,26 +180,12 @@ func (context *Context) setOffscreen(renderTarget *RenderTarget) {
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) {
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 {
// Flip Y and translate
// Flip Y and move to fit with the top of the window.
matrix[1][1] *= -1
actualHeight := context.screenHeight * context.screenScale
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) (
graphics.TextureId, error) {
texture, err := newTextureFromImage(img)
texture, err := texture.NewFromImage(img, &NativeTextureCreator{})
if err != nil {
return 0, err
}

View File

@ -5,62 +5,23 @@ package opengl
// #include <OpenGL/gl.h>
import "C"
import (
"github.com/hajimehoshi/go-ebiten/graphics/texture"
"image"
"image/draw"
"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 {
texture *Texture
texture *texture.Texture
framebuffer C.GLuint
}
func (renderTarget *RenderTarget) SetAsViewport(setter interface{
SetViewport(x, y, width, height int)
}) {
texture := renderTarget.texture
x, y, width, height := 0, 0, texture.textureWidth(), texture.textureHeight()
setter.SetViewport(x, y, width, height)
renderTarget.texture.SetAsViewport(0, 0, setter)
}
func createNativeTexture(textureWidth, textureHeight int, pixels unsafe.Pointer) C.GLuint {
func createNativeTexture(textureWidth, textureHeight int, pixels []uint8) C.GLuint {
nativeTexture := C.GLuint(0)
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.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.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_MIN_FILTER, C.GL_LINEAR)
@ -81,17 +46,22 @@ func createNativeTexture(textureWidth, textureHeight int, pixels unsafe.Pointer)
return nativeTexture
}
func createTexture(width, height int) *Texture {
texture := &Texture{
width: width,
height: height,
}
texture.native = createNativeTexture(texture.textureWidth(), texture.textureHeight(), nil)
return texture
type NativeTextureCreator struct{}
func (creator *NativeTextureCreator) Create(textureWidth, textureHeight int) (interface{}, error) {
return createNativeTexture(textureWidth, textureHeight, nil), nil
}
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) {
texture := createTexture(width, height)
texture, err := texture.New(width, height, &NativeTextureCreator{})
if err != nil {
return nil, err
}
framebuffer := createFramebuffer(texture.Native().(C.GLuint))
return &RenderTarget{
texture: texture,
@ -99,41 +69,15 @@ func newRenderTarget(width, height int) (*RenderTarget, error) {
}, nil
}
func newTextureFromImage(img image.Image) (*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)
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,
func newRenderTargetWithFramebuffer(width, height int, framebuffer C.GLuint) (*RenderTarget, error) {
texture, err := texture.New(width, height, &NativeTextureCreator{})
if err != nil {
return nil, err
}
return &RenderTarget{
texture: texture,
framebuffer: framebuffer,
}
}, nil
}
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.
package glut
// #cgo CFLAGS: -Wno-deprecated-declarations
// #cgo LDFLAGS: -framework GLUT -framework OpenGL
//
// #include <stdlib.h>