mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
Apply 'Tell, don't ask'
This commit is contained in:
parent
9aded38cc2
commit
b15febed51
@ -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},
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
99
graphics/texture/texture.go
Normal file
99
graphics/texture/texture.go
Normal 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())
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// This package is experimental.
|
||||
package glut
|
||||
|
||||
// #cgo CFLAGS: -Wno-deprecated-declarations
|
||||
// #cgo LDFLAGS: -framework GLUT -framework OpenGL
|
||||
//
|
||||
// #include <stdlib.h>
|
||||
|
Loading…
Reference in New Issue
Block a user