Remove dependencies on ebiten from shader

This commit is contained in:
Hajime Hoshi 2014-12-13 14:41:38 +09:00
parent 4addf8f9af
commit d264d7a06b
14 changed files with 137 additions and 109 deletions

View File

@ -18,7 +18,7 @@ package ebiten
type affine interface {
dim() int
element(i, j int) float64
Element(i, j int) float64
setElement(i, j int, element float64)
}
@ -26,7 +26,7 @@ func isIdentity(ebiten affine) bool {
dim := ebiten.dim()
for i := 0; i < dim-1; i++ {
for j := 0; j < dim; j++ {
element := ebiten.element(i, j)
element := ebiten.Element(i, j)
if i == j && element != 1 {
return false
} else if i != j && element != 0 {
@ -47,11 +47,11 @@ func mul(lhs, rhs, result affine) {
for j := 0; j < dim; j++ {
element := float64(0)
for k := 0; k < dim-1; k++ {
element += lhs.element(i, k) *
rhs.element(k, j)
element += lhs.Element(i, k) *
rhs.Element(k, j)
}
if j == dim-1 {
element += lhs.element(i, j)
element += lhs.Element(i, j)
}
result.setElement(i, j, element)
}

View File

@ -42,6 +42,10 @@ func (c *ColorMatrix) dim() int {
return ColorMatrixDim
}
func (c *ColorMatrix) Element(i, j int) float64 {
return c.Elements[i][j]
}
func (c *ColorMatrix) Concat(other ColorMatrix) {
result := ColorMatrix{}
mul(&other, c, &result)
@ -52,10 +56,6 @@ func (c *ColorMatrix) IsIdentity() bool {
return isIdentity(c)
}
func (c *ColorMatrix) element(i, j int) float64 {
return c.Elements[i][j]
}
func (c *ColorMatrix) setElement(i, j int, element float64) {
c.Elements[i][j] = element
}

View File

@ -39,6 +39,10 @@ func (g *GeometryMatrix) dim() int {
return GeometryMatrixDim
}
func (g *GeometryMatrix) Element(i, j int) float64 {
return g.Elements[i][j]
}
func (g *GeometryMatrix) Concat(other GeometryMatrix) {
result := GeometryMatrix{}
mul(&other, g, &result)
@ -49,10 +53,6 @@ func (g *GeometryMatrix) IsIdentity() bool {
return isIdentity(g)
}
func (g *GeometryMatrix) element(i, j int) float64 {
return g.Elements[i][j]
}
func (g *GeometryMatrix) setElement(i, j int, element float64) {
g.Elements[i][j] = element
}

View File

@ -50,6 +50,7 @@ type GraphicsContext interface {
Fill(r, g, b uint8)
Texture(id TextureID) Drawer
RenderTarget(id RenderTargetID) Drawer
// TODO: ScreenRenderTarget() Drawer
PushRenderTarget(id RenderTargetID)
PopRenderTarget()
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package glfw
import (
"github.com/go-gl/gl"
glfw "github.com/go-gl/glfw3"
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/internal/opengl"
@ -55,7 +56,16 @@ func (c *canvas) NewTextureID(img image.Image, filter ebiten.Filter) (ebiten.Tex
var id ebiten.TextureID
var err error
c.use(func() {
id, err = opengl.NewTextureID(img, filter)
glFilter := 0
switch filter {
case ebiten.FilterNearest:
glFilter = gl.NEAREST
case ebiten.FilterLinear:
glFilter = gl.LINEAR
default:
panic("not reached")
}
id, err = opengl.NewTextureID(img, glFilter)
})
return id, err
}
@ -64,7 +74,16 @@ func (c *canvas) NewRenderTargetID(width, height int, filter ebiten.Filter) (ebi
var id ebiten.RenderTargetID
var err error
c.use(func() {
id, err = opengl.NewRenderTargetID(width, height, filter)
glFilter := 0
switch filter {
case ebiten.FilterNearest:
glFilter = gl.NEAREST
case ebiten.FilterLinear:
glFilter = gl.LINEAR
default:
panic("not reached")
}
id, err = opengl.NewRenderTargetID(width, height, glFilter)
})
return id, err
}

View File

@ -40,7 +40,7 @@ func Initialize(screenWidth, screenHeight, screenScale int) (*GraphicsContext, e
})
var err error
c.screenID, err = idsInstance.createRenderTarget(screenWidth, screenHeight, ebiten.FilterNearest)
c.screenID, err = idsInstance.createRenderTarget(screenWidth, screenHeight, gl.NEAREST)
if err != nil {
return nil, err
}

View File

@ -41,11 +41,11 @@ var idsInstance = &ids{
currentRenderTargetId: -1,
}
func NewRenderTargetID(width, height int, filter ebiten.Filter) (ebiten.RenderTargetID, error) {
func NewRenderTargetID(width, height int, filter int) (ebiten.RenderTargetID, error) {
return idsInstance.createRenderTarget(width, height, filter)
}
func NewTextureID(img image.Image, filter ebiten.Filter) (ebiten.TextureID, error) {
func NewTextureID(img image.Image, filter int) (ebiten.TextureID, error) {
return idsInstance.createTexture(img, filter)
}
@ -67,7 +67,7 @@ func (i *ids) toTexture(id ebiten.RenderTargetID) ebiten.TextureID {
return i.renderTargetToTexture[id]
}
func (i *ids) createTexture(img image.Image, filter ebiten.Filter) (ebiten.TextureID, error) {
func (i *ids) createTexture(img image.Image, filter int) (ebiten.TextureID, error) {
texture, err := createTextureFromImage(img, filter)
if err != nil {
return 0, err
@ -81,7 +81,7 @@ func (i *ids) createTexture(img image.Image, filter ebiten.Filter) (ebiten.Textu
return textureId, nil
}
func (i *ids) createRenderTarget(width, height int, filter ebiten.Filter) (ebiten.RenderTargetID, error) {
func (i *ids) createRenderTarget(width, height int, filter int) (ebiten.RenderTargetID, error) {
texture, err := createTexture(width, height, filter)
if err != nil {
return 0, err
@ -148,7 +148,8 @@ func (i *ids) drawTexture(target ebiten.RenderTargetID, id ebiten.TextureID, par
i.setViewportIfNeeded(target)
r := i.renderTargetAt(target)
projectionMatrix := r.projectionMatrix()
shader.DrawTexture(texture.native, texture.width, texture.height, projectionMatrix, parts, geo, color)
quads := textureQuads(parts, texture.width, texture.height)
shader.DrawTexture(texture.native, projectionMatrix, quads, &geo, &color)
}
func (i *ids) setViewportIfNeeded(id ebiten.RenderTargetID) {

View File

@ -18,15 +18,14 @@ package shader
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten"
"sync"
)
func glMatrix(ebiten [4][4]float64) [16]float32 {
func glMatrix(m [4][4]float64) [16]float32 {
result := [16]float32{}
for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ {
result[i+j*4] = float32(ebiten[i][j])
result[i+j*4] = float32(m[i][j])
}
}
return result
@ -34,16 +33,19 @@ func glMatrix(ebiten [4][4]float64) [16]float32 {
var once sync.Once
type Matrix interface {
Element(i, j int) float64
}
// TODO: Use VBO
func DrawTexture(native gl.Texture, width, height int, projectionMatrix [4][4]float64, parts []ebiten.TexturePart, geo ebiten.GeometryMatrix, color ebiten.ColorMatrix) {
func DrawTexture(native gl.Texture, projectionMatrix [4][4]float64, quads []TextureQuad, geo Matrix, color Matrix) {
once.Do(func() {
initialize()
})
if len(parts) == 0 {
if len(quads) == 0 {
return
}
quads := textureQuads(parts, width, height)
// TODO: Check performance
shaderProgram := use(glMatrix(projectionMatrix), geo, color)
@ -67,7 +69,7 @@ func DrawTexture(native gl.Texture, width, height int, projectionMatrix [4][4]fl
vertices := []float32{}
texCoords := []float32{}
indicies := []uint32{}
// TODO: Check len(parts) and gl.MAX_ELEMENTS_INDICES?
// TODO: Check len(quads) and gl.MAX_ELEMENTS_INDICES?
for i, quad := range quads {
x1 := quad.VertexX1
x2 := quad.VertexX2

View File

@ -18,7 +18,6 @@ package shader
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten"
)
type program struct {
@ -81,18 +80,18 @@ func getUniformLocation(program gl.Program, name string) gl.UniformLocation {
return location
}
func use(projectionMatrix [16]float32, geo ebiten.GeometryMatrix, color ebiten.ColorMatrix) gl.Program {
func use(projectionMatrix [16]float32, geo Matrix, color Matrix) gl.Program {
// TODO: Check the performance.
program := programColorMatrix
getUniformLocation(program.native, "projection_matrix").UniformMatrix4fv(false, projectionMatrix)
a := float32(geo.Elements[0][0])
b := float32(geo.Elements[0][1])
c := float32(geo.Elements[1][0])
d := float32(geo.Elements[1][1])
tx := float32(geo.Elements[0][2])
ty := float32(geo.Elements[1][2])
a := float32(geo.Element(0, 0))
b := float32(geo.Element(0, 1))
c := float32(geo.Element(1, 0))
d := float32(geo.Element(1, 1))
tx := float32(geo.Element(0, 2))
ty := float32(geo.Element(1, 2))
glModelviewMatrix := [...]float32{
a, c, 0, 0,
b, d, 0, 0,
@ -106,7 +105,7 @@ func use(projectionMatrix [16]float32, geo ebiten.GeometryMatrix, color ebiten.C
e := [4][5]float32{}
for i := 0; i < 4; i++ {
for j := 0; j < 5; j++ {
e[i][j] = float32(color.Elements[i][j])
e[i][j] = float32(color.Element(i, j))
}
}

View File

@ -16,11 +16,7 @@ limitations under the License.
package shader
import (
"github.com/hajimehoshi/ebiten"
)
type textureQuad struct {
type TextureQuad struct {
VertexX1 float32
VertexX2 float32
VertexY1 float32
@ -30,43 +26,3 @@ type textureQuad struct {
TextureCoordV1 float32
TextureCoordV2 float32
}
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
}
func AdjustSizeForTexture(size int) int {
return int(NextPowerOf2(uint64(size)))
}
func u(x int, width int) float32 {
return float32(x) / float32(AdjustSizeForTexture(width))
}
func v(y int, height int) float32 {
return float32(y) / float32(AdjustSizeForTexture(height))
}
func textureQuads(parts []ebiten.TexturePart, width, height int) []textureQuad {
quads := []textureQuad{}
for _, part := range parts {
x1 := float32(part.LocationX)
x2 := float32(part.LocationX + part.Source.Width)
y1 := float32(part.LocationY)
y2 := float32(part.LocationY + part.Source.Height)
u1 := u(part.Source.X, width)
u2 := u(part.Source.X+part.Source.Width, width)
v1 := v(part.Source.Y, height)
v2 := v(part.Source.Y+part.Source.Height, height)
quad := textureQuad{x1, x2, y1, y2, u1, u2, v1, v2}
quads = append(quads, quad)
}
return quads
}

View File

@ -19,7 +19,6 @@ package opengl
import (
"fmt"
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten/internal/opengl/internal/shader"
)
func orthoProjectionMatrix(left, right, bottom, top int) [4][4]float64 {
@ -70,18 +69,18 @@ func (r *renderTarget) setAsViewport() {
gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)
width := shader.AdjustSizeForTexture(r.width)
height := shader.AdjustSizeForTexture(r.height)
width := adjustSizeForTexture(r.width)
height := adjustSizeForTexture(r.height)
gl.Viewport(0, 0, width, height)
}
func (r *renderTarget) projectionMatrix() [4][4]float64 {
width := shader.AdjustSizeForTexture(r.width)
height := shader.AdjustSizeForTexture(r.height)
width := adjustSizeForTexture(r.width)
height := adjustSizeForTexture(r.height)
ebiten := orthoProjectionMatrix(0, width, 0, height)
if r.flipY {
ebiten[1][1] *= -1
ebiten[1][3] += float64(r.height) / float64(shader.AdjustSizeForTexture(r.height)) * 2
ebiten[1][3] += float64(r.height) / float64(adjustSizeForTexture(r.height)) * 2
}
return ebiten
}

View File

@ -18,8 +18,6 @@ package opengl
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/internal/opengl/internal/shader"
"image"
"image/draw"
)
@ -29,8 +27,8 @@ func adjustImageForTexture(img image.Image) *image.NRGBA {
adjustedImageBounds := image.Rectangle{
image.ZP,
image.Point{
shader.AdjustSizeForTexture(width),
shader.AdjustSizeForTexture(height),
adjustSizeForTexture(width),
adjustSizeForTexture(height),
},
}
if nrgba, ok := img.(*image.NRGBA); ok && img.Bounds() == adjustedImageBounds {
@ -52,7 +50,7 @@ type texture struct {
height int
}
func createNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter ebiten.Filter) gl.Texture {
func createNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter int) gl.Texture {
nativeTexture := gl.GenTexture()
if nativeTexture < 0 {
panic("glGenTexture failed")
@ -61,31 +59,22 @@ func createNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter
nativeTexture.Bind(gl.TEXTURE_2D)
defer gl.Texture(0).Bind(gl.TEXTURE_2D)
glFilter := 0
switch filter {
case ebiten.FilterLinear:
glFilter = gl.LINEAR
case ebiten.FilterNearest:
glFilter = gl.NEAREST
default:
panic("not reached")
}
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, glFilter)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, glFilter)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter)
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, textureWidth, textureHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
return nativeTexture
}
func createTexture(width, height int, filter ebiten.Filter) (*texture, error) {
w := shader.AdjustSizeForTexture(width)
h := shader.AdjustSizeForTexture(height)
func createTexture(width, height int, filter int) (*texture, error) {
w := adjustSizeForTexture(width)
h := adjustSizeForTexture(height)
native := createNativeTexture(w, h, nil, filter)
return &texture{native, width, height}, nil
}
func createTextureFromImage(img image.Image, filter ebiten.Filter) (*texture, error) {
func createTextureFromImage(img image.Image, filter int) (*texture, error) {
adjustedImage := adjustImageForTexture(img)
size := adjustedImage.Bounds().Size()
native := createNativeTexture(size.X, size.Y, adjustedImage.Pix, filter)

View File

@ -0,0 +1,62 @@
/*
Copyright 2014 Hajime Hoshi
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package opengl
import (
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/internal/opengl/internal/shader"
)
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
}
func adjustSizeForTexture(size int) int {
return int(NextPowerOf2(uint64(size)))
}
func u(x int, width int) float32 {
return float32(x) / float32(adjustSizeForTexture(width))
}
func v(y int, height int) float32 {
return float32(y) / float32(adjustSizeForTexture(height))
}
func textureQuads(parts []ebiten.TexturePart, width, height int) []shader.TextureQuad {
quads := make([]shader.TextureQuad, 0, len(parts))
for _, part := range parts {
x1 := float32(part.LocationX)
x2 := float32(part.LocationX + part.Source.Width)
y1 := float32(part.LocationY)
y2 := float32(part.LocationY + part.Source.Height)
u1 := u(part.Source.X, width)
u2 := u(part.Source.X+part.Source.Width, width)
v1 := v(part.Source.Y, height)
v2 := v(part.Source.Y+part.Source.Height, height)
quad := shader.TextureQuad{x1, x2, y1, y2, u1, u2, v1, v2}
quads = append(quads, quad)
}
return quads
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package shader_test
package opengl_test
import (
. "."