Add image.DrawRects (experimental)

This commit is contained in:
Hajime Hoshi 2015-01-12 20:47:49 +09:00
parent f0519b8604
commit 0328b049d0
6 changed files with 234 additions and 5 deletions

74
example/shapes/main.go Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2015 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 main
import (
"github.com/hajimehoshi/ebiten"
"image"
"image/color"
"log"
"math/rand"
)
const (
screenWidth = 320
screenHeight = 240
)
var rectsToDraw = make([]image.Rectangle, 100)
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a < b {
return b
}
return a
}
func init() {
for i, _ := range rectsToDraw {
x0, x1 := rand.Intn(screenWidth), rand.Intn(screenWidth)
y0, y1 := rand.Intn(screenHeight), rand.Intn(screenHeight)
rectsToDraw[i] = image.Rect(min(x0, x1), min(y0, y1), max(x0, x1), max(y0, y1))
}
}
type rects []image.Rectangle
func (r rects) Len() int {
return len(r)
}
func (r rects) Points(i int) (x0, y0, x1, y1 int) {
rect := &r[i]
return rect.Min.X, rect.Min.Y, rect.Max.X, rect.Max.Y
}
func update(screen *ebiten.Image) error {
screen.DrawRects(color.NRGBA{0x80, 0x80, 0xff, 0x80}, rects(rectsToDraw))
return nil
}
func main() {
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Shapes (Ebiten Demo)"); err != nil {
log.Fatal(err)
}
}

View File

@ -94,6 +94,36 @@ func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) {
return return
} }
// A Rects represents the set of rectangles.
type Rects interface {
Len() int
Points(i int) (x0, y0, x1, y1 int)
}
type rectVertexQuads struct {
Rects
}
func (l rectVertexQuads) Len() int {
return l.Rects.Len()
}
func (l rectVertexQuads) Vertex(i int) (x0, y0, x1, y1 float32) {
ix0, iy0, ix1, iy1 := l.Rects.Points(i)
return float32(ix0), float32(iy0), float32(ix1), float32(iy1)
}
// DrawRects draws rectangles on the image.
//
// NOTE: This method is experimental.
func (i *Image) DrawRects(clr color.Color, rects Rects) (err error) {
r, g, b, a := internal.RGBA(clr)
ui.Use(func(c *opengl.Context) {
err = i.framebuffer.DrawRects(c, r, g, b, a, &rectVertexQuads{rects})
})
return
}
// Bounds returns the bounds of the image. // Bounds returns the bounds of the image.
func (i *Image) Bounds() image.Rectangle { func (i *Image) Bounds() image.Rectangle {
w, h := i.Size() w, h := i.Size()

View File

@ -109,6 +109,19 @@ func (f *Framebuffer) DrawTexture(c *opengl.Context, t *Texture, quads TextureQu
if err := f.setAsViewport(c); err != nil { if err := f.setAsViewport(c); err != nil {
return err return err
} }
projectionMatrix := f.projectionMatrix() p := f.projectionMatrix()
return shader.DrawTexture(c, t.native, projectionMatrix, quads, geo, clr) return shader.DrawTexture(c, t.native, p, quads, geo, clr)
}
type VertexQuads interface {
Len() int
Vertex(i int) (x0, y0, x1, y1 float32)
}
func (f *Framebuffer) DrawRects(c *opengl.Context, r, g, b, a float64, quads VertexQuads) error {
if err := f.setAsViewport(c); err != nil {
return err
}
p := f.projectionMatrix()
return shader.DrawRects(c, p, r, g, b, a, quads)
} }

View File

@ -43,6 +43,7 @@ func DrawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4
// TODO: WebGL doesn't seem to have Check gl.MAX_ELEMENTS_VERTICES or gl.MAX_ELEMENTS_INDICES so far. // TODO: 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. // Let's use them to compare to len(quads) in the future.
// TODO: Unify stride or other consts
const stride = 4 * 4 const stride = 4 * 4
if !initialized { if !initialized {
@ -80,3 +81,54 @@ func DrawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4
c.DrawElements(6 * len(vertices) / 16) c.DrawElements(6 * len(vertices) / 16)
return nil return nil
} }
type VertexQuads interface {
Len() int
Vertex(i int) (x0, y0, x1, y1 float32)
}
func max(a, b float32) float32 {
if a < b {
return b
}
return a
}
func DrawRects(c *opengl.Context, projectionMatrix *[4][4]float64, r, g, b, a float64, quads VertexQuads) error {
const stride = 4 * 4
if !initialized {
if err := initialize(c); err != nil {
return err
}
initialized = true
}
if quads.Len() == 0 {
return nil
}
f := useProgramRect(c, glMatrix(projectionMatrix), r, g, b, a)
defer f.FinishProgram()
vertices := make([]float32, 0, stride*quads.Len())
for i := 0; i < quads.Len(); i++ {
x0, y0, x1, y1 := quads.Vertex(i)
if x0 == x1 || y0 == y1 {
continue
}
vertices = append(vertices,
x0, y0, 0, 0,
x1, y0, 1, 0,
x0, y1, 0, 1,
x1, y1, 1, 1,
)
}
if len(vertices) == 0 {
return nil
}
c.BufferSubData(c.ArrayBuffer, vertices)
c.DrawElements(6 * len(vertices) / 16)
return nil
}

View File

@ -18,7 +18,10 @@ import (
"github.com/hajimehoshi/ebiten/internal/opengl" "github.com/hajimehoshi/ebiten/internal/opengl"
) )
var programTexture opengl.Program var (
programTexture opengl.Program
programRect opengl.Program
)
func initialize(c *opengl.Context) error { func initialize(c *opengl.Context) error {
const size = 10000 const size = 10000
@ -36,11 +39,24 @@ func initialize(c *opengl.Context) error {
} }
defer c.DeleteShader(shaderFragmentTextureNative) defer c.DeleteShader(shaderFragmentTextureNative)
shaders := []opengl.Shader{ shaderFragmentRectNative, err := c.NewShader(c.FragmentShader, shader(c, shaderFragmentRect))
if err != nil {
return err
}
defer c.DeleteShader(shaderFragmentRectNative)
programTexture, err = c.NewProgram([]opengl.Shader{
shaderVertexNative, shaderVertexNative,
shaderFragmentTextureNative, shaderFragmentTextureNative,
})
if err != nil {
return err
} }
programTexture, err = c.NewProgram(shaders)
programRect, err = c.NewProgram([]opengl.Shader{
shaderVertexNative,
shaderFragmentRectNative,
})
if err != nil { if err != nil {
return err return err
} }
@ -132,3 +148,38 @@ func useProgramTexture(c *opengl.Context, projectionMatrix []float32, texture op
c.DisableVertexAttribArray(program, "vertex") c.DisableVertexAttribArray(program, "vertex")
} }
} }
func useProgramRect(c *opengl.Context, projectionMatrix []float32, r, g, b, a float64) programFinisher {
const float32Size = 4
const stride = 4 * 4
if lastProgram != programRect {
c.UseProgram(programRect)
lastProgram = programRect
}
program := programRect
c.UniformFloats(program, "projection_matrix", projectionMatrix)
glModelviewMatrix := []float32{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
}
c.UniformFloats(program, "modelview_matrix", glModelviewMatrix)
clr := []float32{float32(r), float32(g), float32(b), float32(a)}
c.UniformFloats(program, "color", clr)
c.EnableVertexAttribArray(program, "vertex")
c.EnableVertexAttribArray(program, "tex_coord")
c.VertexAttribPointer(program, "vertex", stride, uintptr(float32Size*0))
c.VertexAttribPointer(program, "tex_coord", stride, uintptr(float32Size*2))
return func() {
c.DisableVertexAttribArray(program, "tex_coord")
c.DisableVertexAttribArray(program, "vertex")
}
}

View File

@ -24,6 +24,7 @@ type shaderId int
const ( const (
shaderVertex shaderId = iota shaderVertex shaderId = iota
shaderFragmentTexture shaderFragmentTexture
shaderFragmentRect
) )
func shader(c *opengl.Context, id shaderId) string { func shader(c *opengl.Context, id shaderId) string {
@ -69,5 +70,13 @@ void main(void) {
gl_FragColor = color; gl_FragColor = color;
} }
`,
shaderFragmentRect: `
uniform lowp vec4 color;
varying highp vec2 vertex_out_tex_coord;
void main(void) {
gl_FragColor = color;
}
`, `,
} }