Add image.DrawLine / DrawLines

This commit is contained in:
Hajime Hoshi 2015-01-17 12:45:19 +09:00
parent 22e6996f74
commit 8c15b57d58
12 changed files with 217 additions and 51 deletions

View File

@ -26,8 +26,10 @@ const (
)
func update(screen *ebiten.Image) error {
screen.DrawRect(10, 10, 100, 100, color.NRGBA{0x80, 0x80, 0xff, 0x80})
screen.DrawRect(20, 20, 100, 100, color.NRGBA{0x80, 0x80, 0xff, 0x80})
screen.FillRect(10, 10, 100, 100, color.NRGBA{0x80, 0x80, 0xff, 0x80})
screen.FillRect(20, 20, 100, 100, color.NRGBA{0x80, 0x80, 0xff, 0x80})
screen.DrawLine(130, 10, 140, 150, color.NRGBA{0xff, 0x80, 0x80, 0x80})
screen.DrawLine(140, 10, 150, 150, color.NRGBA{0xff, 0x80, 0x80, 0x80})
return nil
}

View File

@ -27,7 +27,7 @@ const (
FilterLinear
)
func glFilter(c *opengl.Context, filter Filter) opengl.FilterType {
func glFilter(c *opengl.Context, filter Filter) opengl.Filter {
switch filter {
case FilterNearest:
return c.Nearest

View File

@ -95,15 +95,28 @@ func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) {
return
}
// DrawLine draws a line.
func (i *Image) DrawLine(x0, y0, x1, y1 int, clr color.Color) error {
return i.DrawLines(&line{x0, y0, x1, y1, clr})
}
// DrawLines draws lines.
func (i *Image) DrawLines(lines Lines) (err error) {
ui.Use(func(c *opengl.Context) {
err = i.framebuffer.DrawLines(c, lines)
})
return
}
// DrawRect draws a rectangle.
func (i *Image) DrawRect(x, y, width, height int, clr color.Color) error {
return i.DrawRects(&rect{x, y, width, height, clr})
func (i *Image) FillRect(x, y, width, height int, clr color.Color) error {
return i.FillRects(&rect{x, y, width, height, clr})
}
// DrawRects draws rectangles on the image.
func (i *Image) DrawRects(rects Rects) (err error) {
func (i *Image) FillRects(rects Rects) (err error) {
ui.Use(func(c *opengl.Context) {
err = i.framebuffer.DrawRects(c, rects)
err = i.framebuffer.FillRects(c, rects)
})
return
}

View File

@ -114,16 +114,30 @@ func (f *Framebuffer) DrawTexture(c *opengl.Context, t *Texture, quads TextureQu
return shader.DrawTexture(c, t.native, p, quads, geo, clr)
}
type Lines interface {
Len() int
Points(i int) (x0, y0, x1, y1 int)
Color(i int) color.Color
}
func (f *Framebuffer) DrawLines(c *opengl.Context, lines Lines) error {
if err := f.setAsViewport(c); err != nil {
return err
}
p := f.projectionMatrix()
return shader.DrawLines(c, p, lines)
}
type Rects interface {
Len() int
Rect(i int) (x, y, width, height int)
Color(i int) color.Color
}
func (f *Framebuffer) DrawRects(c *opengl.Context, rects Rects) error {
func (f *Framebuffer) FillRects(c *opengl.Context, rects Rects) error {
if err := f.setAsViewport(c); err != nil {
return err
}
p := f.projectionMatrix()
return shader.DrawRects(c, p, rects)
return shader.FillRects(c, p, rects)
}

View File

@ -85,7 +85,51 @@ func DrawTexture(c *opengl.Context, texture opengl.Texture, projectionMatrix *[4
return nil
}
c.BufferSubData(c.ArrayBuffer, vertices)
c.DrawElements(6 * num)
c.DrawElements(c.Triangles, 6*num)
return nil
}
type Lines interface {
Len() int
Points(i int) (x0, y0, x1, y1 int)
Color(i int) color.Color
}
func DrawLines(c *opengl.Context, projectionMatrix *[4][4]float64, lines Lines) error {
if !initialized {
if err := initialize(c); err != nil {
return err
}
initialized = true
}
if lines.Len() == 0 {
return nil
}
f := useProgramLines(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
}
@ -95,7 +139,7 @@ type Rects interface {
Color(i int) color.Color
}
func DrawRects(c *opengl.Context, projectionMatrix *[4][4]float64, rects Rects) error {
func FillRects(c *opengl.Context, projectionMatrix *[4][4]float64, rects Rects) error {
if !initialized {
if err := initialize(c); err != nil {
return err
@ -107,7 +151,7 @@ func DrawRects(c *opengl.Context, projectionMatrix *[4][4]float64, rects Rects)
return nil
}
f := useProgramRect(c, glMatrix(projectionMatrix))
f := useProgramRects(c, glMatrix(projectionMatrix))
defer f.FinishProgram()
vertices := vertices[0:0]
@ -131,7 +175,7 @@ func DrawRects(c *opengl.Context, projectionMatrix *[4][4]float64, rects Rects)
return nil
}
c.BufferSubData(c.ArrayBuffer, vertices)
c.DrawElements(6 * num)
c.DrawElements(c.Triangles, 6*num)
return nil
}

View File

@ -16,13 +16,20 @@ package shader
import (
"github.com/hajimehoshi/ebiten/internal/opengl"
"math"
)
var (
indexBufferLines opengl.Buffer
indexBufferQuads opengl.Buffer
)
var (
programTexture opengl.Program
programRect opengl.Program
programSolid opengl.Program
)
// TODO: Use math.MaxUint16??
const quadsMaxNum = 65536 / 6
// unsafe.SizeOf can't be used because unsafe doesn't work with GopherJS.
@ -47,11 +54,11 @@ func initialize(c *opengl.Context) error {
}
defer c.DeleteShader(shaderFragmentTextureNative)
shaderFragmentRectNative, err := c.NewShader(c.FragmentShader, shader(c, shaderFragmentRect))
shaderFragmentSolidNative, err := c.NewShader(c.FragmentShader, shader(c, shaderFragmentSolid))
if err != nil {
return err
}
defer c.DeleteShader(shaderFragmentRectNative)
defer c.DeleteShader(shaderFragmentSolidNative)
programTexture, err = c.NewProgram([]opengl.Shader{
shaderVertexNative,
@ -61,9 +68,9 @@ func initialize(c *opengl.Context) error {
return err
}
programRect, err = c.NewProgram([]opengl.Shader{
programSolid, err = c.NewProgram([]opengl.Shader{
shaderVertexColorNative,
shaderFragmentRectNative,
shaderFragmentSolidNative,
})
if err != nil {
return err
@ -81,7 +88,14 @@ func initialize(c *opengl.Context) error {
indices[6*i+4] = 4*i + 2
indices[6*i+5] = 4*i + 3
}
c.NewBuffer(c.ElementArrayBuffer, indices, c.StaticDraw)
indexBufferQuads = c.NewBuffer(c.ElementArrayBuffer, indices, c.StaticDraw)
// TODO: Use math.MaxUint16
indices = make([]uint16, 65536)
for i := uint16(0); i < math.MaxUint16; i++ {
indices[i] = i
}
indexBufferLines = c.NewBuffer(c.ElementArrayBuffer, indices, c.StaticDraw)
return nil
}
@ -101,6 +115,8 @@ func useProgramTexture(c *opengl.Context, projectionMatrix []float32, texture op
}
program := programTexture
c.BindElementArrayBuffer(indexBufferQuads)
c.UniformFloats(program, "projection_matrix", projectionMatrix)
ma := float32(geo.Element(0, 0))
@ -153,12 +169,38 @@ func useProgramTexture(c *opengl.Context, projectionMatrix []float32, texture op
}
}
func useProgramRect(c *opengl.Context, projectionMatrix []float32) programFinisher {
if !lastProgram.Equals(programRect) {
c.UseProgram(programRect)
lastProgram = programRect
func useProgramLines(c *opengl.Context, projectionMatrix []float32) programFinisher {
if !lastProgram.Equals(programSolid) {
c.UseProgram(programSolid)
lastProgram = programSolid
}
program := programRect
program := programSolid
c.BindElementArrayBuffer(indexBufferLines)
c.UniformFloats(program, "projection_matrix", projectionMatrix)
c.EnableVertexAttribArray(program, "vertex")
c.EnableVertexAttribArray(program, "color")
// TODO: Change to floats?
c.VertexAttribPointer(program, "vertex", true, false, int16Size*6, 2, uintptr(int16Size*0))
c.VertexAttribPointer(program, "color", false, true, int16Size*6, 4, uintptr(int16Size*2))
return func() {
c.DisableVertexAttribArray(program, "color")
c.DisableVertexAttribArray(program, "vertex")
}
}
func useProgramRects(c *opengl.Context, projectionMatrix []float32) programFinisher {
if !lastProgram.Equals(programSolid) {
c.UseProgram(programSolid)
lastProgram = programSolid
}
program := programSolid
c.BindElementArrayBuffer(indexBufferQuads)
c.UniformFloats(program, "projection_matrix", projectionMatrix)

View File

@ -25,7 +25,7 @@ const (
shaderVertex shaderId = iota
shaderVertexColor
shaderFragmentTexture
shaderFragmentRect
shaderFragmentSolid
)
func shader(c *opengl.Context, id shaderId) string {
@ -83,7 +83,7 @@ void main(void) {
gl_FragColor = color;
}
`,
shaderFragmentRect: `
shaderFragmentSolid: `
varying lowp vec4 vertex_out_color;
void main(void) {

View File

@ -54,7 +54,7 @@ func (t *Texture) Size() (width, height int) {
return t.width, t.height
}
func NewTexture(c *opengl.Context, width, height int, filter opengl.FilterType) (*Texture, error) {
func NewTexture(c *opengl.Context, width, height int, filter opengl.Filter) (*Texture, error) {
w := internal.NextPowerOf2Int(width)
h := internal.NextPowerOf2Int(height)
if w < 4 {
@ -70,7 +70,7 @@ func NewTexture(c *opengl.Context, width, height int, filter opengl.FilterType)
return &Texture{native, width, height}, nil
}
func NewTextureFromImage(c *opengl.Context, img image.Image, filter opengl.FilterType) (*Texture, error) {
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.")

View File

@ -22,10 +22,13 @@ import (
"github.com/go-gl/gl"
)
// TODO: Why int?
type Texture int
type Framebuffer int
type Shader int
type Program int
type Buffer gl.Buffer
// TODO: Remove this after the GopherJS bug was fixed (#159)
func (p Program) Equals(other Program) bool {
@ -53,6 +56,8 @@ func NewContext() *Context {
ElementArrayBuffer: gl.ELEMENT_ARRAY_BUFFER,
DynamicDraw: gl.DYNAMIC_DRAW,
StaticDraw: gl.STATIC_DRAW,
Triangles: gl.TRIANGLES,
Lines: gl.LINES,
}
c.init()
return c
@ -65,7 +70,7 @@ func (c *Context) init() {
gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
}
func (c *Context) NewTexture(width, height int, pixels []uint8, filter FilterType) (Texture, error) {
func (c *Context) NewTexture(width, height int, pixels []uint8, filter Filter) (Texture, error) {
t := gl.GenTexture()
if t < 0 {
return 0, errors.New("glGenTexture failed")
@ -231,8 +236,9 @@ func (c *Context) DisableVertexAttribArray(p Program, location string) {
l.DisableArray()
}
func (c *Context) NewBuffer(bufferType BufferType, v interface{}, bufferUsageType BufferUsageType) {
gl.GenBuffer().Bind(gl.GLenum(bufferType))
func (c *Context) NewBuffer(bufferType BufferType, v interface{}, bufferUsage BufferUsage) Buffer {
b := gl.GenBuffer()
b.Bind(gl.GLenum(bufferType))
size := 0
ptr := v
switch v := v.(type) {
@ -246,7 +252,12 @@ func (c *Context) NewBuffer(bufferType BufferType, v interface{}, bufferUsageTyp
default:
panic("not reach")
}
gl.BufferData(gl.GLenum(bufferType), size, ptr, gl.GLenum(bufferUsageType))
gl.BufferData(gl.GLenum(bufferType), size, ptr, gl.GLenum(bufferUsage))
return Buffer(b)
}
func (c *Context) BindElementArrayBuffer(b Buffer) {
gl.Buffer(b).Bind(gl.ELEMENT_ARRAY_BUFFER)
}
func (c *Context) BufferSubData(bufferType BufferType, data []int16) {
@ -254,8 +265,8 @@ func (c *Context) BufferSubData(bufferType BufferType, data []int16) {
gl.BufferSubData(gl.GLenum(bufferType), 0, int16Size*len(data), data)
}
func (c *Context) DrawElements(len int) {
gl.DrawElements(gl.TRIANGLES, len, gl.UNSIGNED_SHORT, uintptr(0))
func (c *Context) DrawElements(mode Mode, len int) {
gl.DrawElements(gl.GLenum(mode), len, gl.UNSIGNED_SHORT, uintptr(0))
}
func (c *Context) Flush() {

View File

@ -39,6 +39,10 @@ type Program struct {
js.Object
}
type Buffer struct {
js.Object
}
// TODO: Remove this after the GopherJS bug was fixed (#159)
func (p Program) Equals(other Program) bool {
return p.Object == other.Object
@ -62,14 +66,16 @@ type context struct {
func NewContext(gl *webgl.Context) *Context {
c := &Context{
Nearest: FilterType(gl.NEAREST),
Linear: FilterType(gl.LINEAR),
Nearest: Filter(gl.NEAREST),
Linear: Filter(gl.LINEAR),
VertexShader: ShaderType(gl.VERTEX_SHADER),
FragmentShader: ShaderType(gl.FRAGMENT_SHADER),
ArrayBuffer: BufferType(gl.ARRAY_BUFFER),
ElementArrayBuffer: BufferType(gl.ELEMENT_ARRAY_BUFFER),
DynamicDraw: BufferUsageType(gl.DYNAMIC_DRAW),
StaticDraw: BufferUsageType(gl.STATIC_DRAW),
DynamicDraw: BufferUsage(gl.DYNAMIC_DRAW),
StaticDraw: BufferUsage(gl.STATIC_DRAW),
Triangles: Mode(gl.TRIANGLES),
Lines: Mode(gl.LINES),
}
c.gl = gl
c.init()
@ -83,7 +89,7 @@ func (c *Context) init() {
gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
}
func (c *Context) NewTexture(width, height int, pixels []uint8, filter FilterType) (Texture, error) {
func (c *Context) NewTexture(width, height int, pixels []uint8, filter Filter) (Texture, error) {
gl := c.gl
t := gl.CreateTexture()
if t == nil {
@ -284,11 +290,17 @@ func (c *Context) DisableVertexAttribArray(p Program, location string) {
gl.DisableVertexAttribArray(int(l))
}
func (c *Context) NewBuffer(bufferType BufferType, v interface{}, bufferUsageType BufferUsageType) {
func (c *Context) NewBuffer(bufferType BufferType, v interface{}, bufferUsage BufferUsage) Buffer {
gl := c.gl
b := gl.CreateBuffer()
gl.BindBuffer(int(bufferType), b)
gl.BufferData(int(bufferType), v, int(bufferUsageType))
gl.BufferData(int(bufferType), v, int(bufferUsage))
return Buffer{b}
}
func (c *Context) BindElementArrayBuffer(b Buffer) {
gl := c.gl
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, b.Object)
}
func (c *Context) BufferSubData(bufferType BufferType, data []int16) {
@ -296,9 +308,9 @@ func (c *Context) BufferSubData(bufferType BufferType, data []int16) {
gl.BufferSubData(int(bufferType), 0, data)
}
func (c *Context) DrawElements(len int) {
func (c *Context) DrawElements(mode Mode, len int) {
gl := c.gl
gl.DrawElements(gl.TRIANGLES, len, gl.UNSIGNED_SHORT, 0)
gl.DrawElements(int(mode), len, gl.UNSIGNED_SHORT, 0)
}
func (c *Context) Flush() {

View File

@ -14,19 +14,22 @@
package opengl
type FilterType int
type Filter int
type ShaderType int
type BufferType int
type BufferUsageType int
type BufferUsage int
type Mode int
type Context struct {
Nearest FilterType
Linear FilterType
Nearest Filter
Linear Filter
VertexShader ShaderType
FragmentShader ShaderType
ArrayBuffer BufferType
ElementArrayBuffer BufferType
DynamicDraw BufferUsageType
StaticDraw BufferUsageType
DynamicDraw BufferUsage
StaticDraw BufferUsage
Triangles Mode
Lines Mode
context
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 Hajime Hoshi
// 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.
@ -18,10 +18,35 @@ import (
"image/color"
)
// A Lines represents the set of lines.
type Lines interface {
Len() int
Points(i int) (x0, y0, x1, y1 int) // TODO: Change to float64?
Color(i int) color.Color
}
type line struct {
x0, y0 int
x1, y1 int
color color.Color
}
func (l *line) Len() int {
return 1
}
func (l *line) Points(i int) (x0, y0, x1, y1 int) {
return l.x0, l.y0, l.x1, l.y1
}
func (l *line) Color(i int) color.Color {
return l.color
}
// A Rects represents the set of rectangles.
type Rects interface {
Len() int
Rect(i int) (x, y, width, height int)
Rect(i int) (x, y, width, height int) // TODO: Change to float64?
Color(i int) color.Color
}