mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
Remove dependencies on ebiten from shader
This commit is contained in:
parent
4addf8f9af
commit
d264d7a06b
10
affine.go
10
affine.go
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
62
internal/opengl/texturequad.go
Normal file
62
internal/opengl/texturequad.go
Normal 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
|
||||
}
|
@ -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 (
|
||||
. "."
|
Loading…
Reference in New Issue
Block a user