Refactoring

This commit is contained in:
Hajime Hoshi 2013-12-13 00:31:00 +09:00
parent 63fc25d24c
commit d087333e48
5 changed files with 118 additions and 87 deletions

View File

@ -10,50 +10,60 @@ import (
"unsafe" "unsafe"
) )
func createProgram(shaders ...*shader) C.GLuint { type program struct {
program := C.glCreateProgram() native C.GLuint
for _, shader := range shaders { shaderIds []shaderId
C.glAttachShader(program, shader.id) }
type programId int
const (
programRegular programId = iota
programColorMatrix
)
var programs = map[programId]*program{
programRegular: &program{
shaderIds: []shaderId{shaderVertex, shaderFragment},
},
programColorMatrix: &program{
shaderIds: []shaderId{shaderVertex, shaderColorMatrix},
},
}
func (p *program) create() {
p.native = C.glCreateProgram()
if p.native == 0 {
panic("glCreateProgram failed")
} }
C.glLinkProgram(program)
for _, shaderId := range p.shaderIds {
C.glAttachShader(p.native, shaders[shaderId].native)
}
C.glLinkProgram(p.native)
linked := C.GLint(C.GL_FALSE) linked := C.GLint(C.GL_FALSE)
C.glGetProgramiv(program, C.GL_LINK_STATUS, &linked) C.glGetProgramiv(p.native, C.GL_LINK_STATUS, &linked)
if linked == C.GL_FALSE { if linked == C.GL_FALSE {
panic("program error") panic("program error")
} }
return program
} }
var ( var initialized = false
initialized = false
)
func initialize() { func initialize() {
// TODO: when should this function be called? for _, shader := range shaders {
vertexShader.id = C.glCreateShader(C.GL_VERTEX_SHADER) shader.compile()
if vertexShader.id == 0 {
panic("creating shader failed")
} }
fragmentShader.id = C.glCreateShader(C.GL_FRAGMENT_SHADER) defer func() {
if fragmentShader.id == 0 { for _, shader := range shaders {
panic("creating shader failed") shader.delete()
} }
colorMatrixShader.id = C.glCreateShader(C.GL_FRAGMENT_SHADER) }()
if colorMatrixShader.id == 0 {
panic("creating shader failed") for _, program := range programs {
program.create()
} }
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 initialized = true
} }
@ -105,13 +115,14 @@ func getUniformLocation(program C.GLuint, name string) C.GLint {
func use(projectionMatrix [16]float32, func use(projectionMatrix [16]float32,
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) C.GLuint { geometryMatrix matrix.Geometry, colorMatrix matrix.Color) C.GLuint {
program := programRegular programId := programRegular
if !colorMatrix.IsIdentity() { if !colorMatrix.IsIdentity() {
program = programColorMatrix programId = programColorMatrix
} }
C.glUseProgram(program) program := programs[programId]
C.glUseProgram(program.native)
C.glUniformMatrix4fv(C.GLint(getUniformLocation(program, "projection_matrix")), C.glUniformMatrix4fv(C.GLint(getUniformLocation(program.native, "projection_matrix")),
1, C.GL_FALSE, (*C.GLfloat)(&projectionMatrix[0])) 1, C.GL_FALSE, (*C.GLfloat)(&projectionMatrix[0]))
a := float32(geometryMatrix.Elements[0][0]) a := float32(geometryMatrix.Elements[0][0])
@ -126,14 +137,14 @@ func use(projectionMatrix [16]float32,
0, 0, 1, 0, 0, 0, 1, 0,
tx, ty, 0, 1, tx, ty, 0, 1,
} }
C.glUniformMatrix4fv(getUniformLocation(program, "modelview_matrix"), C.glUniformMatrix4fv(getUniformLocation(program.native, "modelview_matrix"),
1, C.GL_FALSE, 1, C.GL_FALSE,
(*C.GLfloat)(&glModelviewMatrix[0])) (*C.GLfloat)(&glModelviewMatrix[0]))
C.glUniform1i(getUniformLocation(program, "texture"), 0) C.glUniform1i(getUniformLocation(program.native, "texture"), 0)
if program != programColorMatrix { if programId != programColorMatrix {
return program return program.native
} }
e := [4][5]float32{} e := [4][5]float32{}
@ -149,14 +160,14 @@ func use(projectionMatrix [16]float32,
e[0][2], e[1][2], e[2][2], e[3][2], e[0][2], e[1][2], e[2][2], e[3][2],
e[0][3], e[1][3], e[2][3], e[3][3], e[0][3], e[1][3], e[2][3], e[3][3],
} }
C.glUniformMatrix4fv(getUniformLocation(program, "color_matrix"), C.glUniformMatrix4fv(getUniformLocation(program.native, "color_matrix"),
1, C.GL_FALSE, (*C.GLfloat)(&glColorMatrix[0])) 1, C.GL_FALSE, (*C.GLfloat)(&glColorMatrix[0]))
glColorMatrixTranslation := [...]float32{ glColorMatrixTranslation := [...]float32{
e[0][4], e[1][4], e[2][4], e[3][4], e[0][4], e[1][4], e[2][4], e[3][4],
} }
C.glUniform4fv(getUniformLocation(program, "color_matrix_translation"), C.glUniform4fv(getUniformLocation(program.native, "color_matrix_translation"),
1, (*C.GLfloat)(&glColorMatrixTranslation[0])) 1, (*C.GLfloat)(&glColorMatrixTranslation[0]))
return program return program.native
} }

View File

@ -6,92 +6,113 @@ package shader
// #include <stdlib.h> // #include <stdlib.h>
import "C" import "C"
import ( import (
"fmt"
"unsafe" "unsafe"
) )
type shader struct { type shader struct {
id C.GLuint native C.GLuint
name string shaderType C.GLenum
source string source string
} }
var ( type shaderId int
vertexShader = &shader{
id: 0, const (
name: "vertex_shader", shaderVertex shaderId = iota
shaderFragment
shaderColorMatrix
shaderSolidColor
)
var shaders = map[shaderId]*shader{
shaderVertex: &shader{
shaderType: C.GL_VERTEX_SHADER,
source: ` source: `
attribute /*highp*/ vec2 vertex; attribute vec2 vertex;
attribute /*highp*/ vec2 texture; attribute vec2 texture;
uniform /*highp*/ mat4 projection_matrix; uniform mat4 projection_matrix;
uniform /*highp*/ mat4 modelview_matrix; uniform mat4 modelview_matrix;
varying /*highp*/ vec2 tex_coord; varying vec2 tex_coord;
void main(void) { void main(void) {
tex_coord = texture; tex_coord = texture;
gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 0, 1); gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 0, 1);
} }
`, `,
} },
fragmentShader = &shader{ shaderFragment: &shader{
id: 0, shaderType: C.GL_FRAGMENT_SHADER,
name: "fragment_shader",
source: ` source: `
uniform /*lowp*/ sampler2D texture; uniform sampler2D texture;
varying /*highp*/ vec2 tex_coord; varying vec2 tex_coord;
void main(void) { void main(void) {
gl_FragColor = texture2D(texture, tex_coord); gl_FragColor = texture2D(texture, tex_coord);
} }
`, `,
} },
colorMatrixShader = &shader{ shaderColorMatrix: &shader{
id: 0, shaderType: C.GL_FRAGMENT_SHADER,
name: "color_matrix_shader",
source: ` source: `
uniform /*highp*/ sampler2D texture; uniform sampler2D texture;
uniform /*lowp*/ mat4 color_matrix; uniform mat4 color_matrix;
uniform /*lowp*/ vec4 color_matrix_translation; uniform vec4 color_matrix_translation;
varying /*highp*/ vec2 tex_coord; varying vec2 tex_coord;
void main(void) { void main(void) {
/*lowp*/ vec4 color = texture2D(texture, tex_coord); vec4 color = texture2D(texture, tex_coord);
gl_FragColor = (color_matrix * color) + color_matrix_translation; gl_FragColor = (color_matrix * color) + color_matrix_translation;
} }
`, `,
} },
) shaderSolidColor: &shader{
shaderType: C.GL_FRAGMENT_SHADER,
source: `
uniform vec4 color;
var ( void main(void) {
programRegular = C.GLuint(0) gl_FragColor = color;
programColorMatrix = C.GLuint(0) }
) `,
},
}
func (s *shader) compile() { func (s *shader) compile() {
s.native = C.glCreateShader(s.shaderType)
if s.native == 0 {
panic("glCreateShader failed")
}
csource := (*C.GLchar)(C.CString(s.source)) csource := (*C.GLchar)(C.CString(s.source))
// TODO: defer? // TODO: defer?
// defer C.free(unsafe.Pointer(csource)) // defer C.free(unsafe.Pointer(csource))
C.glShaderSource(s.id, 1, &csource, nil) C.glShaderSource(s.native, 1, &csource, nil)
C.glCompileShader(s.id) C.glCompileShader(s.native)
compiled := C.GLint(C.GL_FALSE) compiled := C.GLint(C.GL_FALSE)
C.glGetShaderiv(s.id, C.GL_COMPILE_STATUS, &compiled) C.glGetShaderiv(s.native, C.GL_COMPILE_STATUS, &compiled)
if compiled == C.GL_FALSE { if compiled == C.GL_FALSE {
s.showShaderLog() s.showShaderLog()
panic("shader compile failed: " + s.name) panic("shader compile failed")
} }
} }
func (s *shader) showShaderLog() { func (s *shader) showShaderLog() {
logSize := C.GLint(0) logSize := C.GLint(0)
C.glGetShaderiv(s.id, C.GL_INFO_LOG_LENGTH, &logSize) C.glGetShaderiv(s.native, C.GL_INFO_LOG_LENGTH, &logSize)
if logSize == 0 { if logSize == 0 {
return return
} }
length := C.GLsizei(0) length := C.GLsizei(0)
buffer := make([]C.GLchar, logSize) buffer := make([]C.GLchar, logSize)
C.glGetShaderInfoLog(s.id, C.GLsizei(logSize), &length, &buffer[0]) C.glGetShaderInfoLog(s.native, C.GLsizei(logSize), &length, &buffer[0])
message := string(C.GoBytes(unsafe.Pointer(&buffer[0]), C.int(length))) message := string(C.GoBytes(unsafe.Pointer(&buffer[0]), C.int(length)))
print("shader error (", s.name, "):\n", message) fmt.Printf("shader error: %s\n", message)
}
func (s *shader) delete() {
C.glDeleteShader(s.native)
} }

View File

@ -60,4 +60,3 @@ func (w *windowEvents) notifyWindowClosed(e ui.WindowClosedEvent) {
w.windowClosed <- e w.windowClosed <- e
}() }()
} }