Use go-gl/gl

This commit is contained in:
Hajime Hoshi 2014-12-06 15:47:48 +09:00
parent 1591e8299b
commit ca56d05dfa
8 changed files with 114 additions and 205 deletions

View File

@ -1,23 +1,17 @@
package opengl
// #cgo LDFLAGS: -framework OpenGL
//
// #include <stdlib.h>
// #include <OpenGL/gl.h>
import "C"
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten/graphics"
"github.com/hajimehoshi/ebiten/graphics/matrix"
"sync"
)
func enableAlphaBlending() {
C.glEnable(C.GL_TEXTURE_2D)
C.glEnable(C.GL_BLEND)
func flush() {
gl.Flush()
}
func flush() {
C.glFlush()
}
var onceInit sync.Once
type Context struct {
screenId graphics.RenderTargetId
@ -29,11 +23,18 @@ type Context struct {
}
func NewContext(screenWidth, screenHeight, screenScale int) *Context {
onceInit.Do(func() {
gl.Init()
gl.Enable(gl.TEXTURE_2D)
gl.Enable(gl.BLEND)
})
context := &Context{
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
}
defaultRenderTarget := &RenderTarget{
width: screenWidth * screenScale,
height: screenHeight * screenScale,
@ -49,8 +50,6 @@ func NewContext(screenWidth, screenHeight, screenScale int) *Context {
context.ResetOffscreen()
context.Clear()
enableAlphaBlending()
return context
}

View File

@ -1,10 +1,7 @@
package opengl
// #cgo LDFLAGS: -framework OpenGL
//
// #include <OpenGL/gl.h>
import "C"
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten/graphics"
"github.com/hajimehoshi/ebiten/graphics/matrix"
"github.com/hajimehoshi/ebiten/graphics/opengl/internal/shader"
@ -69,8 +66,7 @@ func (i *ids) toTexture(id graphics.RenderTargetId) graphics.TextureId {
return i.renderTargetToTexture[id]
}
func (i *ids) createTexture(img image.Image, filter graphics.Filter) (
graphics.TextureId, error) {
func (i *ids) createTexture(img image.Image, filter graphics.Filter) (graphics.TextureId, error) {
texture, err := createTextureFromImage(img, filter)
if err != nil {
return 0, err
@ -84,14 +80,12 @@ func (i *ids) createTexture(img image.Image, filter graphics.Filter) (
return textureId, nil
}
func (i *ids) createRenderTarget(width, height int, filter graphics.Filter) (
graphics.RenderTargetId, error) {
func (i *ids) createRenderTarget(width, height int, filter graphics.Filter) (graphics.RenderTargetId, error) {
texture, err := createTexture(width, height, filter)
if err != nil {
return 0, err
}
framebuffer := createFramebuffer(texture.native)
framebuffer := createFramebuffer(gl.Texture(texture.native))
// The current binded framebuffer can be changed.
i.currentRenderTargetId = -1
renderTarget := &RenderTarget{
@ -144,12 +138,8 @@ func (i *ids) deleteRenderTarget(id graphics.RenderTargetId) {
func (i *ids) fillRenderTarget(id graphics.RenderTargetId, r, g, b uint8) {
i.setViewportIfNeeded(id)
const max = float64(math.MaxUint8)
C.glClearColor(
C.GLclampf(float64(r)/max),
C.GLclampf(float64(g)/max),
C.GLclampf(float64(b)/max),
1)
C.glClear(C.GL_COLOR_BUFFER_BIT)
gl.ClearColor(gl.GLclampf(float64(r)/max), gl.GLclampf(float64(g)/max), gl.GLclampf(float64(b)/max), 1)
gl.Clear(gl.COLOR_BUFFER_BIT)
}
func (i *ids) drawTexture(
@ -163,12 +153,7 @@ func (i *ids) drawTexture(
r := i.renderTargetAt(target)
projectionMatrix := r.projectionMatrix()
quads := graphics.TextureQuads(parts, texture.width, texture.height)
shader.DrawTexture(
shader.NativeTexture(texture.native),
glMatrix(projectionMatrix),
quads,
geo,
color)
shader.DrawTexture(texture.native, glMatrix(projectionMatrix), quads, geo, color)
}
func (i *ids) setViewportIfNeeded(id graphics.RenderTargetId) {

View File

@ -1,23 +1,15 @@
package shader
// #cgo LDFLAGS: -framework OpenGL
//
// #include <OpenGL/gl.h>
// #include <stdlib.h>
import "C"
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten/graphics"
"github.com/hajimehoshi/ebiten/graphics/matrix"
"sync"
"unsafe"
)
type NativeTexture C.GLuint
var once sync.Once
func DrawTexture(native NativeTexture, projectionMatrix [16]float32,
quads []graphics.TextureQuad, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
func DrawTexture(native gl.Texture, projectionMatrix [16]float32, quads []graphics.TextureQuad, geo matrix.Geometry, color matrix.Color) {
once.Do(func() {
initialize()
})
@ -26,23 +18,23 @@ func DrawTexture(native NativeTexture, projectionMatrix [16]float32,
return
}
// TODO: Check performance
shaderProgram := use(projectionMatrix, geometryMatrix, colorMatrix)
shaderProgram := use(projectionMatrix, geo, color)
C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(native))
defer C.glBindTexture(C.GL_TEXTURE_2D, 0)
native.Bind(gl.TEXTURE_2D)
defer gl.Texture(0).Bind(gl.TEXTURE_2D)
vertexAttrLocation := getAttributeLocation(shaderProgram, "vertex")
texCoordAttrLocation := getAttributeLocation(shaderProgram, "tex_coord")
C.glEnableClientState(C.GL_VERTEX_ARRAY)
C.glEnableClientState(C.GL_TEXTURE_COORD_ARRAY)
C.glEnableVertexAttribArray(C.GLuint(vertexAttrLocation))
C.glEnableVertexAttribArray(C.GLuint(texCoordAttrLocation))
gl.EnableClientState(gl.VERTEX_ARRAY)
gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
vertexAttrLocation.EnableArray()
texCoordAttrLocation.EnableArray()
defer func() {
C.glDisableVertexAttribArray(C.GLuint(texCoordAttrLocation))
C.glDisableVertexAttribArray(C.GLuint(vertexAttrLocation))
C.glDisableClientState(C.GL_TEXTURE_COORD_ARRAY)
C.glDisableClientState(C.GL_VERTEX_ARRAY)
texCoordAttrLocation.DisableArray()
vertexAttrLocation.DisableArray()
gl.DisableClientState(gl.TEXTURE_COORD_ARRAY)
gl.DisableClientState(gl.VERTEX_ARRAY)
}()
vertices := []float32{}
@ -76,12 +68,7 @@ func DrawTexture(native NativeTexture, projectionMatrix [16]float32,
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(texCoordAttrLocation), 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]))
vertexAttrLocation.AttribPointer(2, gl.FLOAT, false, 0, vertices)
texCoordAttrLocation.AttribPointer(2, gl.FLOAT, false, 0, texCoords)
gl.DrawElements(gl.TRIANGLES, len(indicies), gl.UNSIGNED_INT, indicies)
}

View File

@ -1,17 +1,12 @@
package shader
// #cgo LDFLAGS: -framework OpenGL
//
// #include <OpenGL/gl.h>
// #include <stdlib.h>
import "C"
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten/graphics/matrix"
"unsafe"
)
type program struct {
native C.GLuint
native gl.Program
shaderIds []shaderId
}
@ -33,18 +28,16 @@ var programs = map[programId]*program{
}
func (p *program) create() {
p.native = C.glCreateProgram()
p.native = gl.CreateProgram()
if p.native == 0 {
panic("glCreateProgram failed")
}
for _, shaderId := range p.shaderIds {
C.glAttachShader(p.native, shaders[shaderId].native)
p.native.AttachShader(shaders[shaderId].native)
}
C.glLinkProgram(p.native)
linked := C.GLint(C.GL_FALSE)
C.glGetProgramiv(p.native, C.GL_LINK_STATUS, &linked)
if linked == C.GL_FALSE {
p.native.Link()
if p.native.Get(gl.LINK_STATUS) == gl.FALSE {
panic("program error")
}
}
@ -72,57 +65,49 @@ const (
)
var (
shaderLocationCache = map[qualifierVariableType]map[string]C.GLint{
qualifierVariableTypeAttribute: map[string]C.GLint{},
qualifierVariableTypeUniform: map[string]C.GLint{},
shaderLocationCache = map[qualifierVariableType]map[string]gl.AttribLocation{
qualifierVariableTypeAttribute: map[string]gl.AttribLocation{},
qualifierVariableTypeUniform: map[string]gl.AttribLocation{},
}
)
func getLocation(program C.GLuint, name string, qvType qualifierVariableType) C.GLint {
func getLocation(program gl.Program, name string, qvType qualifierVariableType) gl.AttribLocation {
if location, ok := shaderLocationCache[qvType][name]; ok {
return location
}
locationName := C.CString(name)
defer C.free(unsafe.Pointer(locationName))
const invalidLocation = -1
location := C.GLint(invalidLocation)
location := gl.AttribLocation(-1)
switch qvType {
case qualifierVariableTypeAttribute:
location = C.glGetAttribLocation(program, (*C.GLchar)(locationName))
location = program.GetAttribLocation(name)
case qualifierVariableTypeUniform:
location = C.glGetUniformLocation(program, (*C.GLchar)(locationName))
location = gl.AttribLocation(program.GetUniformLocation(name))
default:
panic("no reach")
}
if location == invalidLocation {
panic("glGetUniformLocation failed")
if location == -1 {
panic("GetAttribLocation failed")
}
shaderLocationCache[qvType][name] = location
return location
}
func getAttributeLocation(program C.GLuint, name string) C.GLint {
func getAttributeLocation(program gl.Program, name string) gl.AttribLocation {
return getLocation(program, name, qualifierVariableTypeAttribute)
}
func getUniformLocation(program C.GLuint, name string) C.GLint {
return getLocation(program, name, qualifierVariableTypeUniform)
func getUniformLocation(program gl.Program, name string) gl.UniformLocation {
return gl.UniformLocation(getLocation(program, name, qualifierVariableTypeUniform))
}
func use(projectionMatrix [16]float32,
geometryMatrix matrix.Geometry,
colorMatrix matrix.Color) C.GLuint {
func use(projectionMatrix [16]float32, geometryMatrix matrix.Geometry, colorMatrix matrix.Color) gl.Program {
programId := programColorMatrix
program := programs[programId]
// TODO: Check the performance.
C.glUseProgram(program.native)
program.native.Use()
C.glUniformMatrix4fv(C.GLint(getUniformLocation(program.native, "projection_matrix")),
1, C.GL_FALSE, (*C.GLfloat)(&projectionMatrix[0]))
getUniformLocation(program.native, "projection_matrix").UniformMatrix4fv(false, projectionMatrix)
a := float32(geometryMatrix.Elements[0][0])
b := float32(geometryMatrix.Elements[0][1])
@ -136,11 +121,9 @@ func use(projectionMatrix [16]float32,
0, 0, 1, 0,
tx, ty, 0, 1,
}
C.glUniformMatrix4fv(getUniformLocation(program.native, "modelview_matrix"),
1, C.GL_FALSE,
(*C.GLfloat)(&glModelviewMatrix[0]))
getUniformLocation(program.native, "modelview_matrix").UniformMatrix4fv(false, glModelviewMatrix)
C.glUniform1i(getUniformLocation(program.native, "texture"), 0)
getUniformLocation(program.native, "texture").Uniform1i(0)
e := [4][5]float32{}
for i := 0; i < 4; i++ {
@ -155,14 +138,11 @@ func use(projectionMatrix [16]float32,
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.native, "color_matrix"),
1, C.GL_FALSE, (*C.GLfloat)(&glColorMatrix[0]))
getUniformLocation(program.native, "color_matrix").UniformMatrix4fv(false, glColorMatrix)
glColorMatrixTranslation := [...]float32{
e[0][4], e[1][4], e[2][4], e[3][4],
}
C.glUniform4fv(getUniformLocation(program.native, "color_matrix_translation"),
1, (*C.GLfloat)(&glColorMatrixTranslation[0]))
getUniformLocation(program.native, "color_matrix_translation").Uniform4fv(1, glColorMatrixTranslation[:])
return program.native
}

View File

@ -1,18 +1,13 @@
package shader
// #cgo LDFLAGS: -framework OpenGL
//
// #include <OpenGL/gl.h>
// #include <stdlib.h>
import "C"
import (
"fmt"
"unsafe"
"github.com/go-gl/gl"
"log"
)
type shader struct {
native C.GLuint
shaderType C.GLenum
native gl.Shader
shaderType gl.GLenum
source string
}
@ -27,7 +22,7 @@ const (
var shaders = map[shaderId]*shader{
shaderVertex: &shader{
shaderType: C.GL_VERTEX_SHADER,
shaderType: gl.VERTEX_SHADER,
source: `
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
@ -42,7 +37,7 @@ void main(void) {
`,
},
shaderFragment: &shader{
shaderType: C.GL_FRAGMENT_SHADER,
shaderType: gl.FRAGMENT_SHADER,
source: `
uniform sampler2D texture;
varying vec2 vertex_out_tex_coord;
@ -53,7 +48,7 @@ void main(void) {
`,
},
shaderColorMatrix: &shader{
shaderType: C.GL_FRAGMENT_SHADER,
shaderType: gl.FRAGMENT_SHADER,
source: `
uniform sampler2D texture;
uniform mat4 color_matrix;
@ -67,7 +62,7 @@ void main(void) {
`,
},
shaderSolidColor: &shader{
shaderType: C.GL_FRAGMENT_SHADER,
shaderType: gl.FRAGMENT_SHADER,
source: `
uniform vec4 color;
@ -79,40 +74,27 @@ void main(void) {
}
func (s *shader) compile() {
s.native = C.glCreateShader(s.shaderType)
s.native = gl.CreateShader(s.shaderType)
if s.native == 0 {
panic("glCreateShader failed")
}
csource := (*C.GLchar)(C.CString(s.source))
// TODO: defer?
// defer C.free(unsafe.Pointer(csource))
s.native.Source(s.source)
s.native.Compile()
C.glShaderSource(s.native, 1, &csource, nil)
C.glCompileShader(s.native)
compiled := C.GLint(C.GL_FALSE)
C.glGetShaderiv(s.native, C.GL_COMPILE_STATUS, &compiled)
if compiled == C.GL_FALSE {
if s.native.Get(gl.COMPILE_STATUS) == gl.FALSE {
s.showShaderLog()
panic("shader compile failed")
}
}
func (s *shader) showShaderLog() {
logSize := C.GLint(0)
C.glGetShaderiv(s.native, C.GL_INFO_LOG_LENGTH, &logSize)
if logSize == 0 {
if s.native.Get(gl.INFO_LOG_LENGTH) == 0 {
return
}
length := C.GLsizei(0)
buffer := make([]C.GLchar, logSize)
C.glGetShaderInfoLog(s.native, C.GLsizei(logSize), &length, &buffer[0])
message := string(C.GoBytes(unsafe.Pointer(&buffer[0]), C.int(length)))
fmt.Printf("shader error: %s\n", message)
log.Fatalf("shader error: %s\n", s.native.GetInfoLog())
}
func (s *shader) delete() {
C.glDeleteShader(s.native)
s.native.Delete()
}

View File

@ -1,57 +1,49 @@
package opengl
// #cgo LDFLAGS: -framework OpenGL
//
// #include <OpenGL/gl.h>
import "C"
import (
"fmt"
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten/graphics"
)
type RenderTarget struct {
framebuffer C.GLuint
framebuffer gl.Framebuffer
width int
height int
flipY bool
}
func createFramebuffer(nativeTexture C.GLuint) C.GLuint {
framebuffer := C.GLuint(0)
C.glGenFramebuffers(1, &framebuffer)
func createFramebuffer(nativeTexture gl.Texture) gl.Framebuffer {
framebuffer := gl.GenFramebuffer()
framebuffer.Bind()
C.glBindFramebuffer(C.GL_FRAMEBUFFER, framebuffer)
C.glFramebufferTexture2D(C.GL_FRAMEBUFFER, C.GL_COLOR_ATTACHMENT0,
C.GL_TEXTURE_2D, nativeTexture, 0)
if C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER) !=
C.GL_FRAMEBUFFER_COMPLETE {
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, nativeTexture, 0)
if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE {
panic("creating framebuffer failed")
}
// Set this framebuffer opaque because alpha values on a target might be
// confusing.
C.glClearColor(0, 0, 0, 1)
C.glClear(C.GL_COLOR_BUFFER_BIT)
gl.ClearColor(0, 0, 0, 1)
gl.Clear(gl.COLOR_BUFFER_BIT)
return framebuffer
}
func (r *RenderTarget) setAsViewport() {
C.glFlush()
C.glBindFramebuffer(C.GL_FRAMEBUFFER, C.GLuint(r.framebuffer))
err := C.glCheckFramebufferStatus(C.GL_FRAMEBUFFER)
if err != C.GL_FRAMEBUFFER_COMPLETE {
gl.Flush()
r.framebuffer.Bind()
err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER)
if err != gl.FRAMEBUFFER_COMPLETE {
panic(fmt.Sprintf("glBindFramebuffer failed: %d", err))
}
C.glBlendFuncSeparate(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA,
C.GL_ZERO, C.GL_ONE)
gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)
width := graphics.AdjustSizeForTexture(r.width)
height := graphics.AdjustSizeForTexture(r.height)
C.glViewport(0, 0, C.GLsizei(width), C.GLsizei(height))
gl.Viewport(0, 0, width, height)
}
func (r *RenderTarget) projectionMatrix() [4][4]float64 {
@ -67,5 +59,5 @@ func (r *RenderTarget) projectionMatrix() [4][4]float64 {
}
func (r *RenderTarget) dispose() {
C.glDeleteFramebuffers(1, &r.framebuffer)
r.framebuffer.Delete()
}

View File

@ -1,72 +1,55 @@
package opengl
// #cgo LDFLAGS: -framework OpenGL
//
// #include <OpenGL/gl.h>
import "C"
import (
"github.com/go-gl/gl"
"github.com/hajimehoshi/ebiten/graphics"
"image"
"unsafe"
)
type Texture struct {
native C.GLuint
native gl.Texture
width int
height int
}
func createNativeTexture(
textureWidth, textureHeight int,
pixels []uint8,
filter graphics.Filter) C.GLuint {
nativeTexture := C.GLuint(0)
C.glGenTextures(1, &nativeTexture)
func createNativeTexture(textureWidth, textureHeight int, pixels []uint8, filter graphics.Filter) gl.Texture {
nativeTexture := gl.GenTexture()
if nativeTexture < 0 {
panic("glGenTexture failed")
}
C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 4)
C.glBindTexture(C.GL_TEXTURE_2D, C.GLuint(nativeTexture))
defer C.glBindTexture(C.GL_TEXTURE_2D, 0)
gl.PixelStorei(gl.UNPACK_ALIGNMENT, 4)
nativeTexture.Bind(gl.TEXTURE_2D)
defer gl.Texture(0).Bind(gl.TEXTURE_2D)
glFilter := C.GLint(0)
glFilter := 0
switch filter {
case graphics.FilterLinear:
glFilter = C.GL_LINEAR
glFilter = gl.LINEAR
case graphics.FilterNearest:
glFilter = C.GL_NEAREST
glFilter = gl.NEAREST
default:
panic("not reached")
}
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, glFilter)
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, glFilter)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, glFilter)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, glFilter)
ptr := unsafe.Pointer(nil)
ptr := interface{}(nil)
if pixels != nil {
ptr = unsafe.Pointer(&pixels[0])
ptr = pixels
}
C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RGBA,
C.GLsizei(textureWidth), C.GLsizei(textureHeight),
0, C.GL_RGBA, C.GL_UNSIGNED_BYTE, ptr)
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, textureWidth, textureHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, ptr)
return nativeTexture
}
func createTexture(
width, height int,
filter graphics.Filter) (*Texture, error) {
native := createNativeTexture(
graphics.AdjustSizeForTexture(width),
graphics.AdjustSizeForTexture(height),
nil,
filter)
func createTexture(width, height int, filter graphics.Filter) (*Texture, error) {
w := graphics.AdjustSizeForTexture(width)
h := graphics.AdjustSizeForTexture(height)
native := createNativeTexture(w, h, nil, filter)
return &Texture{native, width, height}, nil
}
func createTextureFromImage(
img image.Image,
filter graphics.Filter) (*Texture, error) {
func createTextureFromImage(img image.Image, filter graphics.Filter) (*Texture, error) {
adjustedImage := graphics.AdjustImageForTexture(img)
size := adjustedImage.Bounds().Size()
native := createNativeTexture(size.X, size.Y, adjustedImage.Pix, filter)
@ -74,5 +57,5 @@ func createTextureFromImage(
}
func (t *Texture) dispose() {
C.glDeleteTextures(1, &t.native)
t.native.Delete()
}

View File

@ -43,6 +43,7 @@ func (i *InputState) PressedKeys() ui.Keys {
}
func (i *InputState) MouseX() int {
// TODO: Update
return i.mouseX
}