func (f *Framebuffer) Dispose(c *opengl.Context) { // Don't delete the default framebuffer. if f.native == opengl.ZeroFramebuffer { return } c.DeleteFramebuffer(f.native) }
func (i *Image) Pixels(context *opengl.Context) ([]uint8, error) { // Flush the enqueued commands so that pixels are certainly read. if err := theCommandQueue.Flush(context); err != nil { return nil, err } f := i.framebuffer return context.FramebufferPixels(f.native, f.width, f.height) }
func shader(c *opengl.Context, id shaderId) string { str := shaders[id] if !c.GlslHighpSupported() { str = strings.Replace(str, "highp ", "", -1) str = strings.Replace(str, "lowp ", "", -1) } return str }
func newFramebufferFromTexture(context *opengl.Context, texture *texture) (*framebuffer, error) { native, err := context.NewFramebuffer(opengl.Texture(texture.native)) if err != nil { return nil, err } return &framebuffer{ native: native, width: texture.width, height: texture.height, }, nil }
func NewFramebufferFromTexture(c *opengl.Context, texture *Texture) (*Framebuffer, error) { f, err := c.NewFramebuffer(opengl.Texture(texture.native)) if err != nil { return nil, err } w, h := texture.Size() return &Framebuffer{ native: f, width: w, height: h, }, nil }
func (f *Framebuffer) Fill(c *opengl.Context, clr color.Color) error { if err := f.setAsViewport(c); err != nil { return err } cr, cg, cb, ca := clr.RGBA() const max = math.MaxUint16 r := float64(cr) / max g := float64(cg) / max b := float64(cb) / max a := float64(ca) / max return c.FillFramebuffer(r, g, b, a) }
func NewTexture(c *opengl.Context, width, height int, filter opengl.Filter) (*Texture, error) { w := NextPowerOf2Int(width) h := NextPowerOf2Int(height) if w < 4 { return nil, errors.New("width must be equal or more than 4.") } if h < 4 { return nil, errors.New("height must be equal or more than 4.") } native, err := c.NewTexture(w, h, nil, filter) if err != nil { return nil, err } return &Texture{native, width, height}, nil }
func NewTextureFromImage(c *opengl.Context, img image.Image, filter opengl.Filter) (*Texture, error) { origSize := img.Bounds().Size() if origSize.X < 4 { return nil, errors.New("width must be equal or more than 4.") } if origSize.Y < 4 { return nil, errors.New("height must be equal or more than 4.") } adjustedImage := adjustImageForTexture(img) size := adjustedImage.Bounds().Size() native, err := c.NewTexture(size.X, size.Y, adjustedImage.Pix, filter) if err != nil { return nil, err } return &Texture{native, origSize.X, origSize.Y}, nil }
func drawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4][4]float64, quads TextureQuads, geo Matrix, color Matrix) error { // NOTE: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far. // Let's use them to compare to len(quads) in the future. if !shadersInitialized { if err := initialize(c); err != nil { return err } shadersInitialized = true } if quads.Len() == 0 { return nil } if quadsMaxNum < quads.Len() { return errors.New(fmt.Sprintf("len(quads) must be equal to or less than %d", quadsMaxNum)) } f := useProgramForTexture(c, glMatrix(projectionMatrix), texture, geo, color) defer f.FinishProgram() vertices := vertices[0:0] num := 0 for i := 0; i < quads.Len(); i++ { x0, y0, x1, y1 := quads.Vertex(i) u0, v0, u1, v1 := quads.Texture(i) if x0 == x1 || y0 == y1 || u0 == u1 || v0 == v1 { continue } vertices = append(vertices, int16(x0), int16(y0), int16(u0), int16(v0), int16(x1), int16(y0), int16(u1), int16(v0), int16(x0), int16(y1), int16(u0), int16(v1), int16(x1), int16(y1), int16(u1), int16(v1), ) num++ } if len(vertices) == 0 { return nil } c.BufferSubData(c.ArrayBuffer, vertices) c.DrawElements(c.Triangles, 6*num) return nil }
func drawFilledRects(c *opengl.Context, projectionMatrix *[4][4]float64, rects Rects) error { if !shadersInitialized { if err := initialize(c); err != nil { return err } shadersInitialized = true } if rects.Len() == 0 { return nil } f := useProgramForRects(c, glMatrix(projectionMatrix)) defer f.FinishProgram() vertices := vertices[0:0] num := 0 for i := 0; i < rects.Len(); i++ { x, y, w, h := rects.Rect(i) if w == 0 || h == 0 { continue } x0, y0, x1, y1 := x, y, x+w, y+h r, g, b, a := rects.Color(i).RGBA() vertices = append(vertices, int16(x0), int16(y0), int16(r), int16(g), int16(b), int16(a), int16(x1), int16(y0), int16(r), int16(g), int16(b), int16(a), int16(x0), int16(y1), int16(r), int16(g), int16(b), int16(a), int16(x1), int16(y1), int16(r), int16(g), int16(b), int16(a), ) num++ } if len(vertices) == 0 { return nil } c.BufferSubData(c.ArrayBuffer, vertices) c.DrawElements(c.Triangles, 6*num) return nil }
func drawLines(c *opengl.Context, projectionMatrix *[4][4]float64, lines Lines) error { if !shadersInitialized { if err := initialize(c); err != nil { return err } shadersInitialized = true } if lines.Len() == 0 { return nil } f := useProgramForLines(c, glMatrix(projectionMatrix)) defer f.FinishProgram() vertices := vertices[0:0] num := 0 for i := 0; i < lines.Len(); i++ { x0, y0, x1, y1 := lines.Points(i) if x0 == x1 && y0 == y1 { continue } r, g, b, a := lines.Color(i).RGBA() vertices = append(vertices, int16(x0), int16(y0), int16(r), int16(g), int16(b), int16(a), int16(x1), int16(y1), int16(r), int16(g), int16(b), int16(a), ) num++ } if len(vertices) == 0 { return nil } c.BufferSubData(c.ArrayBuffer, vertices) c.DrawElements(c.Lines, 2*num) return nil }
func initialize(c *opengl.Context) error { shaderVertexModelviewNative, err := c.NewShader(c.VertexShader, shader(c, shaderVertexModelview)) if err != nil { return err } defer c.DeleteShader(shaderVertexModelviewNative) shaderVertexColorNative, err := c.NewShader(c.VertexShader, shader(c, shaderVertexColor)) if err != nil { return err } defer c.DeleteShader(shaderVertexColorNative) shaderVertexColorLineNative, err := c.NewShader(c.VertexShader, shader(c, shaderVertexColorLine)) if err != nil { return err } defer c.DeleteShader(shaderVertexColorLineNative) shaderFragmentTextureNative, err := c.NewShader(c.FragmentShader, shader(c, shaderFragmentTexture)) if err != nil { return err } defer c.DeleteShader(shaderFragmentTextureNative) shaderFragmentSolidNative, err := c.NewShader(c.FragmentShader, shader(c, shaderFragmentSolid)) if err != nil { return err } defer c.DeleteShader(shaderFragmentSolidNative) programTexture, err = c.NewProgram([]opengl.Shader{ shaderVertexModelviewNative, shaderFragmentTextureNative, }) if err != nil { return err } programSolidRect, err = c.NewProgram([]opengl.Shader{ shaderVertexColorNative, shaderFragmentSolidNative, }) if err != nil { return err } programSolidLine, err = c.NewProgram([]opengl.Shader{ shaderVertexColorLineNative, shaderFragmentSolidNative, }) if err != nil { return err } // 16 [bytse] is an arbitrary number which seems enough to draw anything. Fix this if necessary. const stride = 16 c.NewBuffer(c.ArrayBuffer, 4*stride*quadsMaxNum, c.DynamicDraw) indices := make([]uint16, 6*quadsMaxNum) for i := uint16(0); i < quadsMaxNum; i++ { indices[6*i+0] = 4*i + 0 indices[6*i+1] = 4*i + 1 indices[6*i+2] = 4*i + 2 indices[6*i+3] = 4*i + 1 indices[6*i+4] = 4*i + 2 indices[6*i+5] = 4*i + 3 } indexBufferQuads = c.NewBuffer(c.ElementArrayBuffer, indices, c.StaticDraw) indices = make([]uint16, indicesNum) for i := 0; i < len(indices); i++ { indices[i] = uint16(i) } indexBufferLines = c.NewBuffer(c.ElementArrayBuffer, indices, c.StaticDraw) return nil }
func useProgramForTexture(c *opengl.Context, projectionMatrix []float32, texture opengl.Texture, geo Matrix, color Matrix) programFinisher { if !lastProgram.Equals(programTexture) { c.UseProgram(programTexture) lastProgram = programTexture lastProjectionMatrix = nil lastModelviewMatrix = nil lastColorMatrix = nil } program := programTexture c.BindElementArrayBuffer(indexBufferQuads) if !areSameFloat32Array(lastProjectionMatrix, projectionMatrix) { c.UniformFloats(program, "projection_matrix", projectionMatrix) if lastProjectionMatrix == nil { lastProjectionMatrix = make([]float32, 16) } copy(lastProjectionMatrix, projectionMatrix) } ma := float32(geo.Element(0, 0)) mb := float32(geo.Element(0, 1)) mc := float32(geo.Element(1, 0)) md := float32(geo.Element(1, 1)) tx := float32(geo.Element(0, 2)) ty := float32(geo.Element(1, 2)) modelviewMatrix := []float32{ ma, mc, 0, 0, mb, md, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1, } if !areSameFloat32Array(lastModelviewMatrix, modelviewMatrix) { c.UniformFloats(program, "modelview_matrix", modelviewMatrix) if lastModelviewMatrix == nil { lastModelviewMatrix = make([]float32, 16) } copy(lastModelviewMatrix, modelviewMatrix) } c.UniformInt(program, "texture", 0) e := [4][5]float32{} for i := 0; i < 4; i++ { for j := 0; j < 5; j++ { e[i][j] = float32(color.Element(i, j)) } } colorMatrix := []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], } if !areSameFloat32Array(lastColorMatrix, colorMatrix) { c.UniformFloats(program, "color_matrix", colorMatrix) if lastColorMatrix == nil { lastColorMatrix = make([]float32, 16) } copy(lastColorMatrix, colorMatrix) } colorMatrixTranslation := []float32{ e[0][4], e[1][4], e[2][4], e[3][4], } c.UniformFloats(program, "color_matrix_translation", colorMatrixTranslation) // We don't have to call gl.ActiveTexture here: GL_TEXTURE0 is the default active texture // See also: https://www.opengl.org/sdk/docs/man2/xhtml/glActiveTexture.xml c.BindTexture(texture) c.EnableVertexAttribArray(program, "vertex") c.EnableVertexAttribArray(program, "tex_coord") c.VertexAttribPointer(program, "vertex", true, false, int16Size*4, 2, int16Size*0) c.VertexAttribPointer(program, "tex_coord", true, true, int16Size*4, 2, int16Size*2) return func() { c.DisableVertexAttribArray(program, "tex_coord") c.DisableVertexAttribArray(program, "vertex") } }
func (f *framebuffer) setAsViewport(context *opengl.Context) error { width := viewportSize height := viewportSize return context.SetViewport(f.native, width, height) }
func (f *Framebuffer) Pixels(c *opengl.Context) ([]uint8, error) { w, h := f.Size() w, h = NextPowerOf2Int(w), NextPowerOf2Int(h) return c.FramebufferPixels(f.native, w, h) }
func (f *Framebuffer) setAsViewport(c *opengl.Context) error { width := NextPowerOf2Int(f.width) height := NextPowerOf2Int(f.height) return c.SetViewport(f.native, width, height) }
func (t *Texture) ReplacePixels(c *opengl.Context, p []uint8) error { c.BindTexture(t.native) c.TexSubImage2D(p, t.width, t.height) return nil }
func (t *Texture) Dispose(c *opengl.Context) { c.DeleteTexture(t.native) }
func (i *Image) IsInvalidated(context *opengl.Context) bool { return !context.IsTexture(i.texture.native) }
func useProgramForRects(c *opengl.Context, projectionMatrix []float32) programFinisher { if !lastProgram.Equals(programSolidRect) { c.UseProgram(programSolidRect) lastProgram = programSolidRect } program := programSolidRect c.BindElementArrayBuffer(indexBufferQuads) c.UniformFloats(program, "projection_matrix", projectionMatrix) c.EnableVertexAttribArray(program, "vertex") c.EnableVertexAttribArray(program, "color") c.VertexAttribPointer(program, "vertex", true, false, int16Size*6, 2, int16Size*0) c.VertexAttribPointer(program, "color", false, true, int16Size*6, 4, int16Size*2) return func() { c.DisableVertexAttribArray(program, "color") c.DisableVertexAttribArray(program, "vertex") } }