mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-12 12:08:58 +01:00
Add program.go
This commit is contained in:
parent
790a840389
commit
0baad5a6c3
@ -24,7 +24,6 @@ type Context struct {
|
||||
textures map[graphics.TextureId]*texture.Texture
|
||||
renderTargets map[graphics.RenderTargetId]*rendertarget.RenderTarget
|
||||
renderTargetToTexture map[graphics.RenderTargetId]graphics.TextureId
|
||||
currentOffscreen *rendertarget.RenderTarget
|
||||
mainFramebufferTexture *rendertarget.RenderTarget
|
||||
projectionMatrix [16]float32
|
||||
}
|
||||
@ -89,7 +88,8 @@ func (context *Context) DrawTexture(
|
||||
panic("invalid texture ID")
|
||||
}
|
||||
tex.Draw(func(native interface{}, quads []texture.Quad) {
|
||||
shader.DrawTexture(uint(native.(C.GLuint)), context.projectionMatrix, quads,
|
||||
shader.DrawTexture(shader.Texture(native.(C.GLuint)),
|
||||
context.projectionMatrix, quads,
|
||||
geometryMatrix, colorMatrix)
|
||||
})
|
||||
}
|
||||
@ -102,7 +102,8 @@ func (context *Context) DrawTextureParts(
|
||||
panic("invalid texture ID")
|
||||
}
|
||||
tex.DrawParts(parts, func(native interface{}, quads []texture.Quad) {
|
||||
shader.DrawTexture(uint(native.(C.GLuint)), context.projectionMatrix, quads,
|
||||
shader.DrawTexture(shader.Texture(native.(C.GLuint)),
|
||||
context.projectionMatrix, quads,
|
||||
geometryMatrix, colorMatrix)
|
||||
})
|
||||
}
|
||||
@ -117,8 +118,6 @@ func (context *Context) SetOffscreen(renderTargetId graphics.RenderTargetId) {
|
||||
}
|
||||
|
||||
func (context *Context) setOffscreen(renderTarget *rendertarget.RenderTarget) {
|
||||
context.currentOffscreen = renderTarget
|
||||
|
||||
C.glFlush()
|
||||
|
||||
framebuffer := renderTarget.Framebuffer().(C.GLuint)
|
||||
@ -132,13 +131,13 @@ func (context *Context) setOffscreen(renderTarget *rendertarget.RenderTarget) {
|
||||
C.glBlendFuncSeparate(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA,
|
||||
C.GL_ZERO, C.GL_ONE)
|
||||
|
||||
isUsingMainFramebuffer := context.currentOffscreen == context.mainFramebufferTexture
|
||||
isUsingMainFramebuffer := renderTarget == context.mainFramebufferTexture
|
||||
setter := &viewportSetter{
|
||||
isUsingMainFramebuffer,
|
||||
context.screenHeight * context.screenScale,
|
||||
context,
|
||||
}
|
||||
context.currentOffscreen.SetAsViewport(setter.Set)
|
||||
renderTarget.SetAsViewport(setter.Set)
|
||||
}
|
||||
|
||||
type viewportSetter struct {
|
||||
|
233
graphics/opengl/shader/program.go
Normal file
233
graphics/opengl/shader/program.go
Normal file
@ -0,0 +1,233 @@
|
||||
package shader
|
||||
|
||||
// #cgo LDFLAGS: -framework OpenGL
|
||||
//
|
||||
// #include <OpenGL/gl.h>
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
import (
|
||||
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
|
||||
"github.com/hajimehoshi/go-ebiten/graphics/texture"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func createProgram(shaders ...*shader) C.GLuint {
|
||||
program := C.glCreateProgram()
|
||||
for _, shader := range shaders {
|
||||
C.glAttachShader(program, shader.id)
|
||||
}
|
||||
C.glLinkProgram(program)
|
||||
linked := C.GLint(C.GL_FALSE)
|
||||
C.glGetProgramiv(program, C.GL_LINK_STATUS, &linked)
|
||||
if linked == C.GL_FALSE {
|
||||
panic("program error")
|
||||
}
|
||||
return program
|
||||
}
|
||||
|
||||
var (
|
||||
initialized = false
|
||||
)
|
||||
|
||||
func initialize() {
|
||||
// TODO: when should this function be called?
|
||||
vertexShader.id = C.glCreateShader(C.GL_VERTEX_SHADER)
|
||||
if vertexShader.id == 0 {
|
||||
panic("creating shader failed")
|
||||
}
|
||||
fragmentShader.id = C.glCreateShader(C.GL_FRAGMENT_SHADER)
|
||||
if fragmentShader.id == 0 {
|
||||
panic("creating shader failed")
|
||||
}
|
||||
colorMatrixShader.id = C.glCreateShader(C.GL_FRAGMENT_SHADER)
|
||||
if colorMatrixShader.id == 0 {
|
||||
panic("creating shader failed")
|
||||
}
|
||||
|
||||
vertexShader.compile()
|
||||
fragmentShader.compile()
|
||||
colorMatrixShader.compile()
|
||||
|
||||
programRegular = createProgram(vertexShader, fragmentShader)
|
||||
programColorMatrix = createProgram(vertexShader, colorMatrixShader)
|
||||
|
||||
C.glDeleteShader(vertexShader.id)
|
||||
C.glDeleteShader(fragmentShader.id)
|
||||
C.glDeleteShader(colorMatrixShader.id)
|
||||
|
||||
initialized = true
|
||||
}
|
||||
|
||||
const (
|
||||
qualifierVariableTypeAttribute = iota
|
||||
qualifierVariableTypeUniform
|
||||
)
|
||||
|
||||
var (
|
||||
shaderLocationCache = map[int]map[string]C.GLint{
|
||||
qualifierVariableTypeAttribute: map[string]C.GLint{},
|
||||
qualifierVariableTypeUniform: map[string]C.GLint{},
|
||||
}
|
||||
)
|
||||
|
||||
func getLocation(program C.GLuint, name string, qualifierVariableType int) C.GLint {
|
||||
if location, ok := shaderLocationCache[qualifierVariableType][name]; ok {
|
||||
return location
|
||||
}
|
||||
|
||||
locationName := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(locationName))
|
||||
|
||||
location := C.GLint(-1)
|
||||
|
||||
switch qualifierVariableType {
|
||||
case qualifierVariableTypeAttribute:
|
||||
location = C.glGetAttribLocation(program, (*C.GLchar)(locationName))
|
||||
case qualifierVariableTypeUniform:
|
||||
location = C.glGetUniformLocation(program, (*C.GLchar)(locationName))
|
||||
default:
|
||||
panic("no reach")
|
||||
}
|
||||
if location == -1 {
|
||||
panic("glGetUniformLocation failed")
|
||||
}
|
||||
shaderLocationCache[qualifierVariableType][name] = location
|
||||
|
||||
return location
|
||||
}
|
||||
|
||||
func getAttributeLocation(program C.GLuint, name string) C.GLint {
|
||||
return getLocation(program, name, qualifierVariableTypeAttribute)
|
||||
}
|
||||
|
||||
func getUniformLocation(program C.GLuint, name string) C.GLint {
|
||||
return getLocation(program, name, qualifierVariableTypeUniform)
|
||||
}
|
||||
|
||||
func use(projectionMatrix [16]float32, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) C.GLuint {
|
||||
program := programRegular
|
||||
if !colorMatrix.IsIdentity() {
|
||||
program = programColorMatrix
|
||||
}
|
||||
C.glUseProgram(program)
|
||||
|
||||
C.glUniformMatrix4fv(C.GLint(getUniformLocation(program, "projection_matrix")),
|
||||
1, C.GL_FALSE, (*C.GLfloat)(&projectionMatrix[0]))
|
||||
|
||||
a := float32(geometryMatrix.Elements[0][0])
|
||||
b := float32(geometryMatrix.Elements[0][1])
|
||||
c := float32(geometryMatrix.Elements[1][0])
|
||||
d := float32(geometryMatrix.Elements[1][1])
|
||||
tx := float32(geometryMatrix.Elements[0][2])
|
||||
ty := float32(geometryMatrix.Elements[1][2])
|
||||
glModelviewMatrix := [...]float32{
|
||||
a, c, 0, 0,
|
||||
b, d, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
tx, ty, 0, 1,
|
||||
}
|
||||
C.glUniformMatrix4fv(getUniformLocation(program, "modelview_matrix"),
|
||||
1, C.GL_FALSE,
|
||||
(*C.GLfloat)(&glModelviewMatrix[0]))
|
||||
|
||||
C.glUniform1i(getUniformLocation(program, "texture"), 0)
|
||||
|
||||
if program != programColorMatrix {
|
||||
return program
|
||||
}
|
||||
|
||||
e := [4][5]float32{}
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
e[i][j] = float32(colorMatrix.Elements[i][j])
|
||||
}
|
||||
}
|
||||
|
||||
glColorMatrix := [...]float32{
|
||||
e[0][0], e[1][0], e[2][0], e[3][0],
|
||||
e[0][1], e[1][1], e[2][1], e[3][1],
|
||||
e[0][2], e[1][2], e[2][2], e[3][2],
|
||||
e[0][3], e[1][3], e[2][3], e[3][3],
|
||||
}
|
||||
C.glUniformMatrix4fv(getUniformLocation(program, "color_matrix"),
|
||||
1, C.GL_FALSE, (*C.GLfloat)(&glColorMatrix[0]))
|
||||
|
||||
glColorMatrixTranslation := [...]float32{
|
||||
e[0][4], e[1][4], e[2][4], e[3][4],
|
||||
}
|
||||
C.glUniform4fv(getUniformLocation(program, "color_matrix_translation"),
|
||||
1, (*C.GLfloat)(&glColorMatrixTranslation[0]))
|
||||
|
||||
return program
|
||||
}
|
||||
|
||||
type Texture C.GLuint
|
||||
|
||||
func DrawTexture(native Texture, projectionMatrix [16]float32, quads []texture.Quad,
|
||||
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
|
||||
if !initialized {
|
||||
initialize()
|
||||
}
|
||||
|
||||
if len(quads) == 0 {
|
||||
return
|
||||
}
|
||||
shaderProgram := use(projectionMatrix, geometryMatrix, colorMatrix)
|
||||
// This state affects the other functions, so can't disable here...
|
||||
C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(native))
|
||||
//defer C.glBindTexture(C.GL_TEXTURE_2D, 0)
|
||||
|
||||
vertexAttrLocation := getAttributeLocation(shaderProgram, "vertex")
|
||||
textureAttrLocation := getAttributeLocation(shaderProgram, "texture")
|
||||
|
||||
C.glEnableClientState(C.GL_VERTEX_ARRAY)
|
||||
C.glEnableClientState(C.GL_TEXTURE_COORD_ARRAY)
|
||||
C.glEnableVertexAttribArray(C.GLuint(vertexAttrLocation))
|
||||
C.glEnableVertexAttribArray(C.GLuint(textureAttrLocation))
|
||||
defer func() {
|
||||
C.glDisableVertexAttribArray(C.GLuint(textureAttrLocation))
|
||||
C.glDisableVertexAttribArray(C.GLuint(vertexAttrLocation))
|
||||
C.glDisableClientState(C.GL_TEXTURE_COORD_ARRAY)
|
||||
C.glDisableClientState(C.GL_VERTEX_ARRAY)
|
||||
}()
|
||||
|
||||
vertices := []float32{}
|
||||
texCoords := []float32{}
|
||||
indicies := []uint32{}
|
||||
// TODO: Check len(parts) and GL_MAX_ELEMENTS_INDICES
|
||||
for i, quad := range quads {
|
||||
x1 := quad.VertexX1
|
||||
x2 := quad.VertexX2
|
||||
y1 := quad.VertexY1
|
||||
y2 := quad.VertexY2
|
||||
vertices = append(vertices,
|
||||
x1, y1,
|
||||
x2, y1,
|
||||
x1, y2,
|
||||
x2, y2,
|
||||
)
|
||||
u1 := quad.TextureCoordU1
|
||||
u2 := quad.TextureCoordU2
|
||||
v1 := quad.TextureCoordV1
|
||||
v2 := quad.TextureCoordV2
|
||||
texCoords = append(texCoords,
|
||||
u1, v1,
|
||||
u2, v1,
|
||||
u1, v2,
|
||||
u2, v2,
|
||||
)
|
||||
base := uint32(i * 4)
|
||||
indicies = append(indicies,
|
||||
base, base+1, base+2,
|
||||
base+1, base+2, base+3,
|
||||
)
|
||||
}
|
||||
C.glVertexAttribPointer(C.GLuint(vertexAttrLocation), 2,
|
||||
C.GL_FLOAT, C.GL_FALSE,
|
||||
0, unsafe.Pointer(&vertices[0]))
|
||||
C.glVertexAttribPointer(C.GLuint(textureAttrLocation), 2,
|
||||
C.GL_FLOAT, C.GL_FALSE,
|
||||
0, unsafe.Pointer(&texCoords[0]))
|
||||
C.glDrawElements(C.GL_TRIANGLES, C.GLsizei(len(indicies)),
|
||||
C.GL_UNSIGNED_INT, unsafe.Pointer(&indicies[0]))
|
||||
}
|
@ -6,13 +6,9 @@ package shader
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
import (
|
||||
"github.com/hajimehoshi/go-ebiten/graphics/matrix"
|
||||
"github.com/hajimehoshi/go-ebiten/graphics/texture"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Location int
|
||||
|
||||
type shader struct {
|
||||
id C.GLuint
|
||||
name string
|
||||
@ -99,217 +95,3 @@ func (s *shader) showShaderLog() {
|
||||
message := string(C.GoBytes(unsafe.Pointer(&buffer[0]), C.int(length)))
|
||||
print("shader error (", s.name, "):\n", message)
|
||||
}
|
||||
|
||||
func createProgram(shaders ...*shader) C.GLuint {
|
||||
program := C.glCreateProgram()
|
||||
for _, shader := range shaders {
|
||||
C.glAttachShader(program, shader.id)
|
||||
}
|
||||
C.glLinkProgram(program)
|
||||
linked := C.GLint(C.GL_FALSE)
|
||||
C.glGetProgramiv(program, C.GL_LINK_STATUS, &linked)
|
||||
if linked == C.GL_FALSE {
|
||||
panic("program error")
|
||||
}
|
||||
return program
|
||||
}
|
||||
|
||||
var (
|
||||
initialized = false
|
||||
)
|
||||
|
||||
func initialize() {
|
||||
// TODO: when should this function be called?
|
||||
vertexShader.id = C.glCreateShader(C.GL_VERTEX_SHADER)
|
||||
if vertexShader.id == 0 {
|
||||
panic("creating shader failed")
|
||||
}
|
||||
fragmentShader.id = C.glCreateShader(C.GL_FRAGMENT_SHADER)
|
||||
if fragmentShader.id == 0 {
|
||||
panic("creating shader failed")
|
||||
}
|
||||
colorMatrixShader.id = C.glCreateShader(C.GL_FRAGMENT_SHADER)
|
||||
if colorMatrixShader.id == 0 {
|
||||
panic("creating shader failed")
|
||||
}
|
||||
|
||||
vertexShader.compile()
|
||||
fragmentShader.compile()
|
||||
colorMatrixShader.compile()
|
||||
|
||||
programRegular = createProgram(vertexShader, fragmentShader)
|
||||
programColorMatrix = createProgram(vertexShader, colorMatrixShader)
|
||||
|
||||
C.glDeleteShader(vertexShader.id)
|
||||
C.glDeleteShader(fragmentShader.id)
|
||||
C.glDeleteShader(colorMatrixShader.id)
|
||||
|
||||
initialized = true
|
||||
}
|
||||
|
||||
const (
|
||||
qualifierVariableTypeAttribute = iota
|
||||
qualifierVariableTypeUniform
|
||||
)
|
||||
|
||||
var (
|
||||
shaderLocationCache = map[int]map[string]C.GLint{
|
||||
qualifierVariableTypeAttribute: map[string]C.GLint{},
|
||||
qualifierVariableTypeUniform: map[string]C.GLint{},
|
||||
}
|
||||
)
|
||||
|
||||
func getLocation(program C.GLuint, name string, qualifierVariableType int) C.GLint {
|
||||
if location, ok := shaderLocationCache[qualifierVariableType][name]; ok {
|
||||
return location
|
||||
}
|
||||
|
||||
locationName := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(locationName))
|
||||
|
||||
location := C.GLint(-1)
|
||||
|
||||
switch qualifierVariableType {
|
||||
case qualifierVariableTypeAttribute:
|
||||
location = C.glGetAttribLocation(program, (*C.GLchar)(locationName))
|
||||
case qualifierVariableTypeUniform:
|
||||
location = C.glGetUniformLocation(program, (*C.GLchar)(locationName))
|
||||
default:
|
||||
panic("no reach")
|
||||
}
|
||||
if location == -1 {
|
||||
panic("glGetUniformLocation failed")
|
||||
}
|
||||
shaderLocationCache[qualifierVariableType][name] = location
|
||||
|
||||
return location
|
||||
}
|
||||
|
||||
func getAttributeLocation(program C.GLuint, name string) C.GLint {
|
||||
return getLocation(program, name, qualifierVariableTypeAttribute)
|
||||
}
|
||||
|
||||
func getUniformLocation(program C.GLuint, name string) C.GLint {
|
||||
return getLocation(program, name, qualifierVariableTypeUniform)
|
||||
}
|
||||
|
||||
func use(projectionMatrix [16]float32, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) C.GLuint {
|
||||
program := programRegular
|
||||
if !colorMatrix.IsIdentity() {
|
||||
program = programColorMatrix
|
||||
}
|
||||
C.glUseProgram(program)
|
||||
|
||||
C.glUniformMatrix4fv(C.GLint(getUniformLocation(program, "projection_matrix")),
|
||||
1, C.GL_FALSE, (*C.GLfloat)(&projectionMatrix[0]))
|
||||
|
||||
a := float32(geometryMatrix.Elements[0][0])
|
||||
b := float32(geometryMatrix.Elements[0][1])
|
||||
c := float32(geometryMatrix.Elements[1][0])
|
||||
d := float32(geometryMatrix.Elements[1][1])
|
||||
tx := float32(geometryMatrix.Elements[0][2])
|
||||
ty := float32(geometryMatrix.Elements[1][2])
|
||||
glModelviewMatrix := [...]float32{
|
||||
a, c, 0, 0,
|
||||
b, d, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
tx, ty, 0, 1,
|
||||
}
|
||||
C.glUniformMatrix4fv(getUniformLocation(program, "modelview_matrix"),
|
||||
1, C.GL_FALSE,
|
||||
(*C.GLfloat)(&glModelviewMatrix[0]))
|
||||
|
||||
C.glUniform1i(getUniformLocation(program, "texture"), 0)
|
||||
|
||||
if program != programColorMatrix {
|
||||
return program
|
||||
}
|
||||
|
||||
e := [4][5]float32{}
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
e[i][j] = float32(colorMatrix.Elements[i][j])
|
||||
}
|
||||
}
|
||||
|
||||
glColorMatrix := [...]float32{
|
||||
e[0][0], e[1][0], e[2][0], e[3][0],
|
||||
e[0][1], e[1][1], e[2][1], e[3][1],
|
||||
e[0][2], e[1][2], e[2][2], e[3][2],
|
||||
e[0][3], e[1][3], e[2][3], e[3][3],
|
||||
}
|
||||
C.glUniformMatrix4fv(getUniformLocation(program, "color_matrix"),
|
||||
1, C.GL_FALSE, (*C.GLfloat)(&glColorMatrix[0]))
|
||||
|
||||
glColorMatrixTranslation := [...]float32{
|
||||
e[0][4], e[1][4], e[2][4], e[3][4],
|
||||
}
|
||||
C.glUniform4fv(getUniformLocation(program, "color_matrix_translation"),
|
||||
1, (*C.GLfloat)(&glColorMatrixTranslation[0]))
|
||||
|
||||
return program
|
||||
}
|
||||
|
||||
func DrawTexture(native uint, projectionMatrix [16]float32, quads []texture.Quad,
|
||||
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
|
||||
if !initialized {
|
||||
initialize()
|
||||
}
|
||||
|
||||
if len(quads) == 0 {
|
||||
return
|
||||
}
|
||||
shaderProgram := use(projectionMatrix, geometryMatrix, colorMatrix)
|
||||
C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(native))
|
||||
|
||||
vertexAttrLocation := getAttributeLocation(shaderProgram, "vertex")
|
||||
textureAttrLocation := getAttributeLocation(shaderProgram, "texture")
|
||||
|
||||
C.glEnableClientState(C.GL_VERTEX_ARRAY)
|
||||
C.glEnableClientState(C.GL_TEXTURE_COORD_ARRAY)
|
||||
C.glEnableVertexAttribArray(C.GLuint(vertexAttrLocation))
|
||||
C.glEnableVertexAttribArray(C.GLuint(textureAttrLocation))
|
||||
vertices := []float32{}
|
||||
texCoords := []float32{}
|
||||
indicies := []uint32{}
|
||||
// TODO: Check len(parts) and GL_MAX_ELEMENTS_INDICES
|
||||
for i, quad := range quads {
|
||||
x1 := quad.VertexX1
|
||||
x2 := quad.VertexX2
|
||||
y1 := quad.VertexY1
|
||||
y2 := quad.VertexY2
|
||||
vertices = append(vertices,
|
||||
x1, y1,
|
||||
x2, y1,
|
||||
x1, y2,
|
||||
x2, y2,
|
||||
)
|
||||
u1 := quad.TextureCoordU1
|
||||
u2 := quad.TextureCoordU2
|
||||
v1 := quad.TextureCoordV1
|
||||
v2 := quad.TextureCoordV2
|
||||
texCoords = append(texCoords,
|
||||
u1, v1,
|
||||
u2, v1,
|
||||
u1, v2,
|
||||
u2, v2,
|
||||
)
|
||||
base := uint32(i * 4)
|
||||
indicies = append(indicies,
|
||||
base, base+1, base+2,
|
||||
base+1, base+2, base+3,
|
||||
)
|
||||
}
|
||||
C.glVertexAttribPointer(C.GLuint(vertexAttrLocation), 2,
|
||||
C.GL_FLOAT, C.GL_FALSE,
|
||||
0, unsafe.Pointer(&vertices[0]))
|
||||
C.glVertexAttribPointer(C.GLuint(textureAttrLocation), 2,
|
||||
C.GL_FLOAT, C.GL_FALSE,
|
||||
0, unsafe.Pointer(&texCoords[0]))
|
||||
C.glDrawElements(C.GL_TRIANGLES, C.GLsizei(len(indicies)),
|
||||
C.GL_UNSIGNED_INT, unsafe.Pointer(&indicies[0]))
|
||||
C.glDisableVertexAttribArray(C.GLuint(textureAttrLocation))
|
||||
C.glDisableVertexAttribArray(C.GLuint(vertexAttrLocation))
|
||||
C.glDisableClientState(C.GL_TEXTURE_COORD_ARRAY)
|
||||
C.glDisableClientState(C.GL_VERTEX_ARRAY)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user