first things about OpenGL

This commit is contained in:
Laurent Le Goff 2011-04-21 14:30:46 +02:00
parent 8ba663637e
commit 2081261511
7 changed files with 345 additions and 278 deletions

View file

@ -7,19 +7,20 @@ install:
cd draw2d && make install cd draw2d && make install
cd draw2dgl && make install cd draw2dgl && make install
cd postscript && make install cd postscript && make install
#cd wingui && make install cd wingui && make install
clean: clean:
cd draw2d && make clean cd draw2d && make clean
cd draw2dgl && make clean cd draw2dgl && make clean
cd postscript && make clean cd postscript && make clean
cd cmd && make clean cd cmd && make clean
#cd wingui && make clean cd wingui && make clean
nuke: nuke:
cd draw2d && make nuke cd draw2d && make nuke
cd draw2dgl && make nuke cd draw2dgl && make nuke
cd postscript && make nuke cd postscript && make nuke
cd wingui && make nuke
command: command:
cd cmd && make cd cmd && make

View file

@ -18,45 +18,105 @@
package main package main
import ( import (
"os"
"math"
"io/ioutil"
"strings"
"gl" "gl"
"glut" "glut"
"image"
"draw2d.googlecode.com/hg/draw2d"
"draw2d.googlecode.com/hg/draw2dgl"
"draw2d.googlecode.com/hg/postscript"
"log"
"time"
) )
type GLPainter struct { var postscriptContent string
func TestDrawCubicCurve(gc draw2d.GraphicContext) {
// draw a cubic curve
x, y := 25.6, 128.0
x1, y1 := 102.4, 230.4
x2, y2 := 153.6, 25.6
x3, y3 := 230.4, 128.0
gc.SetStrokeColor(image.NRGBAColor{0, 0, 0, 0xff})
gc.SetLineWidth(10)
gc.MoveTo(x, y)
gc.CubicCurveTo(x1, y1, x2, y2, x3, y3)
gc.Stroke()
gc.SetStrokeColor(image.NRGBAColor{0xFF, 0x33, 0x33, 0x99})
gc.SetLineWidth(6)
// draw segment of curve
gc.MoveTo(x, y)
gc.LineTo(x1, y1)
gc.MoveTo(x2, y2)
gc.LineTo(x3, y3)
gc.Stroke()
} }
var (
width, height int
rotate int
)
func reshape(w, h int) { func reshape(w, h int) {
/* Because Gil specified "screen coordinates" (presumably with an /* Because Gil specified "screen coordinates" (presumably with an
upper-left origin), this short bit of code sets up the coordinate upper-left origin), this short bit of code sets up the coordinate
system to correspond to actual window coodrinates. This code system to correspond to actual window coodrinates. This code
wouldn't be required if you chose a (more typical in 3D) abstract wouldn't be required if you chose a (more typical in 3D) abstract
coordinate system. */ coordinate system. */
gl.ClearColor(1, 1, 1, 1)
//fmt.Println(gl.GetString(gl.EXTENSIONS))
gl.Viewport(0, 0, w, h) /* Establish viewing area to cover entire window. */ gl.Viewport(0, 0, w, h) /* Establish viewing area to cover entire window. */
gl.MatrixMode(gl.PROJECTION) /* Start modifying the projection matrix. */ gl.MatrixMode(gl.PROJECTION) /* Start modifying the projection matrix. */
gl.LoadIdentity() /* Reset project matrix. */ gl.LoadIdentity() /* Reset project matrix. */
gl.Ortho(0, float64(w), 0, float64(h), -1, 1) /* Map abstract coords directly to window coords. */ gl.Ortho(0, float64(w), 0, float64(h), -1, 1) /* Map abstract coords directly to window coords. */
gl.Scalef(1, -1, 1) /* Invert Y axis so increasing Y goes down. */ gl.Scalef(1, -1, 1) /* Invert Y axis so increasing Y goes down. */
gl.Translatef(0, float32(-h), 0) /* Shift origin up to upper-left corner. */ gl.Translatef(0, float32(-h), 0) /* Shift origin up to upper-left corner. */
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
width, height = w, h
} }
func display() { func display() {
gl.Clear(gl.COLOR_BUFFER_BIT)
gl.Begin(gl.TRIANGLES) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.Color3f(0.0, 0.0, 1.0) /* blue */ gl.LineWidth(1)
gl.Vertex2i(0, 0) gc := draw2dgl.NewGraphicContext(width, height)
gl.Color3f(0.0, 1.0, 0.0) /* green */
gl.Vertex2i(200, 200) gc.Translate(380, 400)
gl.Color3f(1.0, 0.0, 0.0) /* red */ gc.Scale(1, -1)
gl.Vertex2i(20, 200) rotate = (rotate + 10) % 360
gl.End() gc.Rotate(float64(rotate) * math.Pi / 180)
gc.Translate(-380, -400)
interpreter := postscript.NewInterpreter(gc)
reader := strings.NewReader(postscriptContent)
lastTime := time.Nanoseconds()
interpreter.Execute(reader)
dt := time.Nanoseconds() - lastTime
log.Printf("Redraw in : %f ms\n", float64(dt)*1e-6)
gl.Flush() /* Single buffered, so needs a flush. */ gl.Flush() /* Single buffered, so needs a flush. */
glut.PostRedisplay()
} }
func main() { func main() {
src, err := os.OpenFile("../resource/postscript/tiger.ps", 0, 0)
if err != nil {
log.Println("can't find postscript file.")
return
}
defer src.Close()
bytes, err := ioutil.ReadAll(src)
postscriptContent = string(bytes)
glut.Init() glut.Init()
glut.InitWindowSize(800, 800)
glut.CreateWindow("single triangle") glut.CreateWindow("single triangle")
glut.DisplayFunc(display) glut.DisplayFunc(display)
glut.ReshapeFunc(reshape) glut.ReshapeFunc(reshape)
glut.MainLoop() glut.MainLoop()

View file

@ -1,147 +0,0 @@
// Ported from GLUT's samples. Original copyright below applies.
/* Copyright (c) Mark J. Kilgard, 1996. */
/* This program is freely distributable without licensing fees
and is provided without guarantee or warrantee expressed or
implied. This program is -not- in the public domain. */
/* This program is a response to a question posed by Gil Colgate
<gcolgate@sirius.com> about how lengthy a program is required using
OpenGL compared to using Direct3D immediate mode to "draw a
triangle at screen coordinates 0,0, to 200,200 to 20,200, and I
want it to be blue at the top vertex, red at the left vertex, and
green at the right vertex". I'm not sure how long the Direct3D
program is; Gil has used Direct3D and his guess is "about 3000
lines of code". */
package main
import (
"gl"
"glut"
"exp/draw"
"image"
"freetype-go.googlecode.com/hg/freetype/raster"
"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d"
"postscript-go.googlecode.com/svn/trunk/postscript-go/src/pkg/postscript"
"fmt"
)
type GLPainter struct {
// The Porter-Duff composition operator.
Op draw.Op
// The 16-bit color to paint the spans.
cr, cg, cb uint8
ca uint32
}
const M16 uint32 = 1<<16 - 1
const M32 uint32 = 1<<32 - 1
// Paint satisfies the Painter interface by painting ss onto an image.RGBA.
func (p *GLPainter) Paint(ss []raster.Span, done bool) {
gl.Begin(gl.LINES)
for _, s := range ss {
ma := s.A >> 16
a := ma * p.ca / M16
gl.Color4ub(p.cr, p.cg, p.cb, uint8(a>>8))
gl.Vertex2i(s.X0, s.Y)
gl.Vertex2i(s.X1, s.Y)
}
gl.End()
}
// SetColor sets the color to paint the spans.
func (p *GLPainter) SetColor(c image.Color) {
r, g, b, a := c.RGBA()
if a == 0 {
p.cr = 0
p.cg = 0
p.cb = 0
p.ca = a
} else {
p.cr = uint8((r * M16 / a) >> 8)
p.cg = uint8((g * M16 / a) >> 8)
p.cb = uint8((b * M16 / a) >> 8)
p.ca = a
}
}
// NewRGBAPainter creates a new RGBAPainter for the given image.
func NewGLPainter() *GLPainter {
return &GLPainter{}
}
func TestDrawCubicCurve(gc draw2d.GraphicContext) {
// draw a cubic curve
x, y := 25.6, 128.0
x1, y1 := 102.4, 230.4
x2, y2 := 153.6, 25.6
x3, y3 := 230.4, 128.0
gc.SetStrokeColor(image.NRGBAColor{0, 0, 0, 0xff})
gc.SetLineWidth(10)
gc.MoveTo(x, y)
gc.CubicCurveTo(x1, y1, x2, y2, x3, y3)
gc.Stroke()
gc.SetStrokeColor(image.NRGBAColor{0xFF, 0x33, 0x33, 0x99})
gc.SetLineWidth(6)
// draw segment of curve
gc.MoveTo(x, y)
gc.LineTo(x1, y1)
gc.MoveTo(x2, y2)
gc.LineTo(x3, y3)
gc.Stroke()
}
var (
width, height int
)
func reshape(w, h int) {
/* Because Gil specified "screen coordinates" (presumably with an
upper-left origin), this short bit of code sets up the coordinate
system to correspond to actual window coodrinates. This code
wouldn't be required if you chose a (more typical in 3D) abstract
coordinate system. */
gl.ClearColor(1, 1, 1, 1)
//fmt.Println(gl.GetString(gl.EXTENSIONS))
gl.Viewport(0, 0, w, h) /* Establish viewing area to cover entire window. */
gl.MatrixMode(gl.PROJECTION) /* Start modifying the projection matrix. */
gl.LoadIdentity() /* Reset project matrix. */
gl.Ortho(0, float64(w), 0, float64(h), -1, 1) /* Map abstract coords directly to window coords. */
gl.Scalef(1, -1, 1) /* Invert Y axis so increasing Y goes down. */
gl.Translatef(0, float32(-h), 0) /* Shift origin up to upper-left corner. */
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
width, height = w, h
}
func display() {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.LineWidth(1)
p := NewGLPainter()
fmt.Println("draw")
gc := draw2d.NewImageGraphicContextFromPainter(p, image.Rect(0, 0, width, height))
gc.Translate(0, 380)
gc.Scale(1, -1)
gc.Translate(0, -380)
interpreter := postscript.NewInterpreter(gc)
interpreter.ExecuteFile("../../tiger.ps")
gl.Flush() /* Single buffered, so needs a flush. */
}
func main() {
glut.Init()
glut.InitWindowSize(800, 800)
glut.CreateWindow("single triangle")
glut.DisplayFunc(display)
glut.ReshapeFunc(reshape)
glut.MainLoop()
}

View file

@ -128,7 +128,7 @@ func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr {
gc.Restore() gc.Restore()
// back buf in // back buf in
wingui.BitBlt(hdc, 0, 0, 100/*int(wndBuffer.Width)*/, 100/*int(wndBuffer.Height)*/, hdcWndBuffer, 0, 0, wingui.SRCCOPY) wingui.BitBlt(hdc, 0, 0, int(wndBuffer.Width), int(wndBuffer.Height), hdcWndBuffer, 0, 0, wingui.SRCCOPY)
wingui.EndPaint(hwnd, &ps) wingui.EndPaint(hwnd, &ps)
rc = wingui.DefWindowProc(hwnd, msg, wparam, lparam) rc = wingui.DefWindowProc(hwnd, msg, wparam, lparam)
fmt.Printf("Redraw in : %f ms\n", float64(dt)*1e-6) fmt.Printf("Redraw in : %f ms\n", float64(dt)*1e-6)

View file

@ -6,7 +6,6 @@ import (
"exp/draw" "exp/draw"
"image" "image"
"log" "log"
"time"
"freetype-go.googlecode.com/hg/freetype" "freetype-go.googlecode.com/hg/freetype"
"freetype-go.googlecode.com/hg/freetype/raster" "freetype-go.googlecode.com/hg/freetype/raster"
) )
@ -77,22 +76,22 @@ func (gc *ImageGraphicContext) Clear() {
} }
func (gc *ImageGraphicContext) ClearRect(x1, y1, x2, y2 int) { func (gc *ImageGraphicContext) ClearRect(x1, y1, x2, y2 int) {
imageColor := image.NewColorImage(gc.current.FillColor) imageColor := image.NewColorImage(gc.Current.FillColor)
draw.Draw(gc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP) draw.Draw(gc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP)
} }
func (gc *ImageGraphicContext) DrawImage(img image.Image) { func (gc *ImageGraphicContext) DrawImage(img image.Image) {
DrawImage(img, gc.img, gc.current.Tr, draw.Over, BilinearFilter) DrawImage(img, gc.img, gc.Current.Tr, draw.Over, BilinearFilter)
} }
func (gc *ImageGraphicContext) FillString(text string) (cursor float64) { func (gc *ImageGraphicContext) FillString(text string) (cursor float64) {
gc.freetype.SetSrc(image.NewColorImage(gc.current.StrokeColor)) gc.freetype.SetSrc(image.NewColorImage(gc.Current.StrokeColor))
// Draw the text. // Draw the text.
x, y := gc.current.Path.LastPoint() x, y := gc.Current.Path.LastPoint()
gc.current.Tr.Transform(&x, &y) gc.Current.Tr.Transform(&x, &y)
x0, fontSize := 0.0, gc.current.FontSize x0, fontSize := 0.0, gc.Current.FontSize
gc.current.Tr.VectorTransform(&x0, &fontSize) gc.Current.Tr.VectorTransform(&x0, &fontSize)
font := GetFont(gc.current.FontData) font := GetFont(gc.Current.FontData)
if font == nil { if font == nil {
font = GetFont(defaultFontData) font = GetFont(defaultFontData)
} }
@ -106,9 +105,9 @@ func (gc *ImageGraphicContext) FillString(text string) (cursor float64) {
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
x1, _ := gc.current.Path.LastPoint() x1, _ := gc.Current.Path.LastPoint()
x2, y2 := float64(p.X)/256, float64(p.Y)/256 x2, y2 := float64(p.X)/256, float64(p.Y)/256
gc.current.Tr.InverseTransform(&x2, &y2) gc.Current.Tr.InverseTransform(&x2, &y2)
width := x2 - x1 width := x2 - x1
return width return width
} }
@ -118,124 +117,121 @@ func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color image.
gc.painter.SetColor(color) gc.painter.SetColor(color)
rasterizer.Rasterize(gc.painter) rasterizer.Rasterize(gc.painter)
rasterizer.Clear() rasterizer.Clear()
gc.current.Path = new(PathStorage) gc.Current.Path = new(PathStorage)
} }
/**** First method ****/ /**** First method ****/
func (gc *ImageGraphicContext) Stroke2(paths ...*PathStorage) { func (gc *ImageGraphicContext) Stroke2(paths ...*PathStorage) {
paths = append(paths, gc.current.Path) paths = append(paths, gc.Current.Path)
gc.strokeRasterizer.UseNonZeroWinding = true gc.strokeRasterizer.UseNonZeroWinding = true
rasterPath := new(raster.Path) rasterPath := new(raster.Path)
var pathConverter *PathConverter var pathConverter *PathConverter
if gc.current.Dash != nil && len(gc.current.Dash) > 0 { if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
dasher := NewDashConverter(gc.current.Dash, gc.current.DashOffset, NewVertexAdder(rasterPath)) dasher := NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, NewVertexAdder(rasterPath))
pathConverter = NewPathConverter(dasher) pathConverter = NewPathConverter(dasher)
} else { } else {
pathConverter = NewPathConverter(NewVertexAdder(rasterPath)) pathConverter = NewPathConverter(NewVertexAdder(rasterPath))
} }
pathConverter.ApproximationScale = gc.current.Tr.GetMaxAbsScaling() pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...) pathConverter.Convert(paths...)
mta := NewMatrixTransformAdder(gc.current.Tr, gc.strokeRasterizer) mta := NewMatrixTransformAdder(gc.Current.Tr, gc.strokeRasterizer)
raster.Stroke(mta, *rasterPath, raster.Fix32(gc.current.LineWidth*256), gc.current.Cap.capper(), gc.current.Join.joiner()) raster.Stroke(mta, *rasterPath, raster.Fix32(gc.Current.LineWidth*256), gc.Current.Cap.capper(), gc.Current.Join.joiner())
gc.paint(gc.strokeRasterizer, gc.current.StrokeColor) gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
} }
/**** second method ****/ /**** second method ****/
func (gc *ImageGraphicContext) Stroke(paths ...*PathStorage) { func (gc *ImageGraphicContext) Stroke(paths ...*PathStorage) {
paths = append(paths, gc.current.Path) paths = append(paths, gc.Current.Path)
gc.strokeRasterizer.UseNonZeroWinding = true gc.strokeRasterizer.UseNonZeroWinding = true
stroker := NewLineStroker(gc.current.Cap, gc.current.Join, NewVertexMatrixTransform(gc.current.Tr, NewVertexAdder(gc.strokeRasterizer))) stroker := NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.strokeRasterizer)))
stroker.HalfLineWidth = gc.current.LineWidth / 2 stroker.HalfLineWidth = gc.Current.LineWidth / 2
var pathConverter *PathConverter var pathConverter *PathConverter
if gc.current.Dash != nil && len(gc.current.Dash) > 0 { if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
dasher := NewDashConverter(gc.current.Dash, gc.current.DashOffset, stroker) dasher := NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
pathConverter = NewPathConverter(dasher) pathConverter = NewPathConverter(dasher)
} else { } else {
pathConverter = NewPathConverter(stroker) pathConverter = NewPathConverter(stroker)
} }
pathConverter.ApproximationScale = gc.current.Tr.GetMaxAbsScaling() pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...) pathConverter.Convert(paths...)
gc.paint(gc.strokeRasterizer, gc.current.StrokeColor) gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
} }
/**** first method ****/ /**** first method ****/
func (gc *ImageGraphicContext) Fill2(paths ...*PathStorage) { func (gc *ImageGraphicContext) Fill2(paths ...*PathStorage) {
paths = append(paths, gc.current.Path) paths = append(paths, gc.Current.Path)
gc.fillRasterizer.UseNonZeroWinding = gc.current.FillRule.fillRule() gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
pathConverter := NewPathConverter(NewVertexAdder(NewMatrixTransformAdder(gc.current.Tr, gc.fillRasterizer))) pathConverter := NewPathConverter(NewVertexAdder(NewMatrixTransformAdder(gc.Current.Tr, gc.fillRasterizer)))
pathConverter.ApproximationScale = gc.current.Tr.GetMaxAbsScaling() pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...) pathConverter.Convert(paths...)
gc.paint(gc.fillRasterizer, gc.current.FillColor) gc.paint(gc.fillRasterizer, gc.Current.FillColor)
} }
/**** second method ****/ /**** second method ****/
func (gc *ImageGraphicContext) Fill(paths ...*PathStorage) { func (gc *ImageGraphicContext) Fill(paths ...*PathStorage) {
paths = append(paths, gc.current.Path) paths = append(paths, gc.Current.Path)
gc.fillRasterizer.UseNonZeroWinding = gc.current.FillRule.fillRule() gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
/**** first method ****/ /**** first method ****/
pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.current.Tr, NewVertexAdder(gc.fillRasterizer))) pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.fillRasterizer)))
pathConverter.ApproximationScale = gc.current.Tr.GetMaxAbsScaling() pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...) pathConverter.Convert(paths...)
t := time.Nanoseconds() gc.paint(gc.fillRasterizer, gc.Current.FillColor)
gc.paint(gc.fillRasterizer, gc.current.FillColor)
dt := time.Nanoseconds() - t
log.Printf("Paint during %f\n", float64(dt)*1e-6)
} }
func (gc *ImageGraphicContext) FillStroke2(paths ...*PathStorage) { func (gc *ImageGraphicContext) FillStroke2(paths ...*PathStorage) {
paths = append(paths, gc.current.Path) paths = append(paths, gc.Current.Path)
gc.fillRasterizer.UseNonZeroWinding = gc.current.FillRule.fillRule() gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
gc.strokeRasterizer.UseNonZeroWinding = true gc.strokeRasterizer.UseNonZeroWinding = true
filler := NewVertexMatrixTransform(gc.current.Tr, NewVertexAdder(gc.fillRasterizer)) filler := NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.fillRasterizer))
rasterPath := new(raster.Path) rasterPath := new(raster.Path)
stroker := NewVertexAdder(rasterPath) stroker := NewVertexAdder(rasterPath)
demux := NewDemuxConverter(filler, stroker) demux := NewDemuxConverter(filler, stroker)
pathConverter := NewPathConverter(demux) pathConverter := NewPathConverter(demux)
pathConverter.ApproximationScale = gc.current.Tr.GetMaxAbsScaling() pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...) pathConverter.Convert(paths...)
mta := NewMatrixTransformAdder(gc.current.Tr, gc.strokeRasterizer) mta := NewMatrixTransformAdder(gc.Current.Tr, gc.strokeRasterizer)
raster.Stroke(mta, *rasterPath, raster.Fix32(gc.current.LineWidth*256), gc.current.Cap.capper(), gc.current.Join.joiner()) raster.Stroke(mta, *rasterPath, raster.Fix32(gc.Current.LineWidth*256), gc.Current.Cap.capper(), gc.Current.Join.joiner())
gc.paint(gc.fillRasterizer, gc.current.FillColor) gc.paint(gc.fillRasterizer, gc.Current.FillColor)
gc.paint(gc.strokeRasterizer, gc.current.StrokeColor) gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
} }
/* second method */ /* second method */
func (gc *ImageGraphicContext) FillStroke(paths ...*PathStorage) { func (gc *ImageGraphicContext) FillStroke(paths ...*PathStorage) {
gc.fillRasterizer.UseNonZeroWinding = gc.current.FillRule.fillRule() gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
gc.strokeRasterizer.UseNonZeroWinding = true gc.strokeRasterizer.UseNonZeroWinding = true
filler := NewVertexMatrixTransform(gc.current.Tr, NewVertexAdder(gc.fillRasterizer)) filler := NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.fillRasterizer))
stroker := NewLineStroker(gc.current.Cap, gc.current.Join, NewVertexMatrixTransform(gc.current.Tr, NewVertexAdder(gc.strokeRasterizer))) stroker := NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.strokeRasterizer)))
stroker.HalfLineWidth = gc.current.LineWidth / 2 stroker.HalfLineWidth = gc.Current.LineWidth / 2
demux := NewDemuxConverter(filler, stroker) demux := NewDemuxConverter(filler, stroker)
paths = append(paths, gc.current.Path) paths = append(paths, gc.Current.Path)
pathConverter := NewPathConverter(demux) pathConverter := NewPathConverter(demux)
pathConverter.ApproximationScale = gc.current.Tr.GetMaxAbsScaling() pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...) pathConverter.Convert(paths...)
gc.paint(gc.fillRasterizer, gc.current.FillColor) gc.paint(gc.fillRasterizer, gc.Current.FillColor)
gc.paint(gc.strokeRasterizer, gc.current.StrokeColor) gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
} }
func (f FillRule) fillRule() bool { func (f FillRule) UseNonZeroWinding() bool {
switch f { switch f {
case FillRuleEvenOdd: case FillRuleEvenOdd:
return false return false

View file

@ -7,7 +7,7 @@ import (
) )
type StackGraphicContext struct { type StackGraphicContext struct {
current *ContextStack Current *ContextStack
} }
type ContextStack struct { type ContextStack struct {
@ -32,168 +32,168 @@ type ContextStack struct {
*/ */
func NewStackGraphicContext() *StackGraphicContext { func NewStackGraphicContext() *StackGraphicContext {
gc := &StackGraphicContext{} gc := &StackGraphicContext{}
gc.current = new(ContextStack) gc.Current = new(ContextStack)
gc.current.Tr = NewIdentityMatrix() gc.Current.Tr = NewIdentityMatrix()
gc.current.Path = new(PathStorage) gc.Current.Path = new(PathStorage)
gc.current.LineWidth = 1.0 gc.Current.LineWidth = 1.0
gc.current.StrokeColor = image.Black gc.Current.StrokeColor = image.Black
gc.current.FillColor = image.White gc.Current.FillColor = image.White
gc.current.Cap = RoundCap gc.Current.Cap = RoundCap
gc.current.FillRule = FillRuleEvenOdd gc.Current.FillRule = FillRuleEvenOdd
gc.current.Join = RoundJoin gc.Current.Join = RoundJoin
gc.current.FontSize = 10 gc.Current.FontSize = 10
gc.current.FontData = defaultFontData gc.Current.FontData = defaultFontData
return gc return gc
} }
func (gc *StackGraphicContext) GetMatrixTransform() MatrixTransform { func (gc *StackGraphicContext) GetMatrixTransform() MatrixTransform {
return gc.current.Tr return gc.Current.Tr
} }
func (gc *StackGraphicContext) SetMatrixTransform(Tr MatrixTransform) { func (gc *StackGraphicContext) SetMatrixTransform(Tr MatrixTransform) {
gc.current.Tr = Tr gc.Current.Tr = Tr
} }
func (gc *StackGraphicContext) ComposeMatrixTransform(Tr MatrixTransform) { func (gc *StackGraphicContext) ComposeMatrixTransform(Tr MatrixTransform) {
gc.current.Tr = Tr.Multiply(gc.current.Tr) gc.Current.Tr = Tr.Multiply(gc.Current.Tr)
} }
func (gc *StackGraphicContext) Rotate(angle float64) { func (gc *StackGraphicContext) Rotate(angle float64) {
gc.current.Tr = NewRotationMatrix(angle).Multiply(gc.current.Tr) gc.Current.Tr = NewRotationMatrix(angle).Multiply(gc.Current.Tr)
} }
func (gc *StackGraphicContext) Translate(tx, ty float64) { func (gc *StackGraphicContext) Translate(tx, ty float64) {
gc.current.Tr = NewTranslationMatrix(tx, ty).Multiply(gc.current.Tr) gc.Current.Tr = NewTranslationMatrix(tx, ty).Multiply(gc.Current.Tr)
} }
func (gc *StackGraphicContext) Scale(sx, sy float64) { func (gc *StackGraphicContext) Scale(sx, sy float64) {
gc.current.Tr = NewScaleMatrix(sx, sy).Multiply(gc.current.Tr) gc.Current.Tr = NewScaleMatrix(sx, sy).Multiply(gc.Current.Tr)
} }
func (gc *StackGraphicContext) SetStrokeColor(c image.Color) { func (gc *StackGraphicContext) SetStrokeColor(c image.Color) {
gc.current.StrokeColor = c gc.Current.StrokeColor = c
} }
func (gc *StackGraphicContext) SetFillColor(c image.Color) { func (gc *StackGraphicContext) SetFillColor(c image.Color) {
gc.current.FillColor = c gc.Current.FillColor = c
} }
func (gc *StackGraphicContext) SetFillRule(f FillRule) { func (gc *StackGraphicContext) SetFillRule(f FillRule) {
gc.current.FillRule = f gc.Current.FillRule = f
} }
func (gc *StackGraphicContext) SetLineWidth(LineWidth float64) { func (gc *StackGraphicContext) SetLineWidth(LineWidth float64) {
gc.current.LineWidth = LineWidth gc.Current.LineWidth = LineWidth
} }
func (gc *StackGraphicContext) SetLineCap(Cap Cap) { func (gc *StackGraphicContext) SetLineCap(Cap Cap) {
gc.current.Cap = Cap gc.Current.Cap = Cap
} }
func (gc *StackGraphicContext) SetLineJoin(Join Join) { func (gc *StackGraphicContext) SetLineJoin(Join Join) {
gc.current.Join = Join gc.Current.Join = Join
} }
func (gc *StackGraphicContext) SetLineDash(Dash []float64, DashOffset float64) { func (gc *StackGraphicContext) SetLineDash(Dash []float64, DashOffset float64) {
gc.current.Dash = Dash gc.Current.Dash = Dash
gc.current.DashOffset = DashOffset gc.Current.DashOffset = DashOffset
} }
func (gc *StackGraphicContext) SetFontSize(FontSize float64) { func (gc *StackGraphicContext) SetFontSize(FontSize float64) {
gc.current.FontSize = FontSize gc.Current.FontSize = FontSize
} }
func (gc *StackGraphicContext) GetFontSize() float64 { func (gc *StackGraphicContext) GetFontSize() float64 {
return gc.current.FontSize return gc.Current.FontSize
} }
func (gc *StackGraphicContext) SetFontData(FontData FontData) { func (gc *StackGraphicContext) SetFontData(FontData FontData) {
gc.current.FontData = FontData gc.Current.FontData = FontData
} }
func (gc *StackGraphicContext) GetFontData() FontData { func (gc *StackGraphicContext) GetFontData() FontData {
return gc.current.FontData return gc.Current.FontData
} }
func (gc *StackGraphicContext) BeginPath() { func (gc *StackGraphicContext) BeginPath() {
gc.current.Path = new(PathStorage) gc.Current.Path = new(PathStorage)
} }
func (gc *StackGraphicContext) IsEmpty() bool { func (gc *StackGraphicContext) IsEmpty() bool {
return gc.current.Path.IsEmpty() return gc.Current.Path.IsEmpty()
} }
func (gc *StackGraphicContext) LastPoint() (float64, float64) { func (gc *StackGraphicContext) LastPoint() (float64, float64) {
return gc.current.Path.LastPoint() return gc.Current.Path.LastPoint()
} }
func (gc *StackGraphicContext) MoveTo(x, y float64) { func (gc *StackGraphicContext) MoveTo(x, y float64) {
gc.current.Path.MoveTo(x, y) gc.Current.Path.MoveTo(x, y)
} }
func (gc *StackGraphicContext) RMoveTo(dx, dy float64) { func (gc *StackGraphicContext) RMoveTo(dx, dy float64) {
gc.current.Path.RMoveTo(dx, dy) gc.Current.Path.RMoveTo(dx, dy)
} }
func (gc *StackGraphicContext) LineTo(x, y float64) { func (gc *StackGraphicContext) LineTo(x, y float64) {
gc.current.Path.LineTo(x, y) gc.Current.Path.LineTo(x, y)
} }
func (gc *StackGraphicContext) RLineTo(dx, dy float64) { func (gc *StackGraphicContext) RLineTo(dx, dy float64) {
gc.current.Path.RLineTo(dx, dy) gc.Current.Path.RLineTo(dx, dy)
} }
func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) { func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) {
gc.current.Path.QuadCurveTo(cx, cy, x, y) gc.Current.Path.QuadCurveTo(cx, cy, x, y)
} }
func (gc *StackGraphicContext) RQuadCurveTo(dcx, dcy, dx, dy float64) { func (gc *StackGraphicContext) RQuadCurveTo(dcx, dcy, dx, dy float64) {
gc.current.Path.RQuadCurveTo(dcx, dcy, dx, dy) gc.Current.Path.RQuadCurveTo(dcx, dcy, dx, dy)
} }
func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) { func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) {
gc.current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y) gc.Current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y)
} }
func (gc *StackGraphicContext) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) { func (gc *StackGraphicContext) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) {
gc.current.Path.RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy) gc.Current.Path.RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy)
} }
func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float64) { func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float64) {
gc.current.Path.ArcTo(cx, cy, rx, ry, startAngle, angle) gc.Current.Path.ArcTo(cx, cy, rx, ry, startAngle, angle)
} }
func (gc *StackGraphicContext) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) { func (gc *StackGraphicContext) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) {
gc.current.Path.RArcTo(dcx, dcy, rx, ry, startAngle, angle) gc.Current.Path.RArcTo(dcx, dcy, rx, ry, startAngle, angle)
} }
func (gc *StackGraphicContext) Close() { func (gc *StackGraphicContext) Close() {
gc.current.Path.Close() gc.Current.Path.Close()
} }
func (gc *StackGraphicContext) Save() { func (gc *StackGraphicContext) Save() {
context := new(ContextStack) context := new(ContextStack)
context.FontSize = gc.current.FontSize context.FontSize = gc.Current.FontSize
context.FontData = gc.current.FontData context.FontData = gc.Current.FontData
context.LineWidth = gc.current.LineWidth context.LineWidth = gc.Current.LineWidth
context.StrokeColor = gc.current.StrokeColor context.StrokeColor = gc.Current.StrokeColor
context.FillColor = gc.current.FillColor context.FillColor = gc.Current.FillColor
context.FillRule = gc.current.FillRule context.FillRule = gc.Current.FillRule
context.Dash = gc.current.Dash context.Dash = gc.Current.Dash
context.DashOffset = gc.current.DashOffset context.DashOffset = gc.Current.DashOffset
context.Cap = gc.current.Cap context.Cap = gc.Current.Cap
context.Join = gc.current.Join context.Join = gc.Current.Join
context.Path = gc.current.Path.Copy() context.Path = gc.Current.Path.Copy()
copy(context.Tr[:], gc.current.Tr[:]) copy(context.Tr[:], gc.Current.Tr[:])
context.previous = gc.current context.previous = gc.Current
gc.current = context gc.Current = context
} }
func (gc *StackGraphicContext) Restore() { func (gc *StackGraphicContext) Restore() {
if gc.current.previous != nil { if gc.Current.previous != nil {
oldContext := gc.current oldContext := gc.Current
gc.current = gc.current.previous gc.Current = gc.Current.previous
oldContext.previous = nil oldContext.previous = nil
} }
} }

View file

@ -1 +1,158 @@
package draw2dgl package draw2dgl
import (
"image"
"exp/draw"
"gl"
"freetype-go.googlecode.com/hg/freetype/raster"
"draw2d.googlecode.com/hg/draw2d"
)
type GLPainter struct {
// The Porter-Duff composition operator.
Op draw.Op
// The 16-bit color to paint the spans.
cr, cg, cb uint8
ca uint32
}
const M16 uint32 = 1<<16 - 1
// Paint satisfies the Painter interface by painting ss onto an image.RGBA.
func (p *GLPainter) Paint(ss []raster.Span, done bool) {
gl.Begin(gl.LINES)
for _, s := range ss {
ma := s.A >> 16
a := ma * p.ca / M16
gl.Color4ub(p.cr, p.cg, p.cb, uint8(a>>8))
gl.Vertex2i(s.X0, s.Y)
gl.Vertex2i(s.X1, s.Y)
}
gl.End()
}
// SetColor sets the color to paint the spans.
func (p *GLPainter) SetColor(c image.Color) {
r, g, b, a := c.RGBA()
if a == 0 {
p.cr = 0
p.cg = 0
p.cb = 0
p.ca = a
} else {
p.cr = uint8((r * M16 / a) >> 8)
p.cg = uint8((g * M16 / a) >> 8)
p.cb = uint8((b * M16 / a) >> 8)
p.ca = a
}
}
// NewRGBAPainter creates a new RGBAPainter for the given image.
func NewGLPainter() *GLPainter {
return &GLPainter{}
}
type GraphicContext struct {
*draw2d.StackGraphicContext
painter *GLPainter
fillRasterizer *raster.Rasterizer
strokeRasterizer *raster.Rasterizer
}
/**
* Create a new Graphic context from an image
*/
func NewGraphicContext(width, height int) *GraphicContext {
gc := &GraphicContext{
draw2d.NewStackGraphicContext(),
NewGLPainter(),
raster.NewRasterizer(width, height),
raster.NewRasterizer(width, height),
}
return gc
}
func (gc *GraphicContext) SetDPI(dpi int) {
}
func (gc *GraphicContext) GetDPI() int {
return -1
}
func (gc *GraphicContext) Clear() {
}
func (gc *GraphicContext) ClearRect(x1, y1, x2, y2 int) {
}
func (gc *GraphicContext) DrawImage(img image.Image) {
}
func (gc *GraphicContext) FillString(text string) (cursor float64) {
return 0
}
func (gc *GraphicContext) paint(rasterizer *raster.Rasterizer, color image.Color) {
gc.painter.SetColor(color)
rasterizer.Rasterize(gc.painter)
rasterizer.Clear()
}
func (gc *GraphicContext) Stroke(paths ...*draw2d.PathStorage) {
paths = append(paths, gc.Current.Path)
gc.strokeRasterizer.UseNonZeroWinding = true
stroker := draw2d.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.NewVertexMatrixTransform(gc.Current.Tr, draw2d.NewVertexAdder(gc.strokeRasterizer)))
stroker.HalfLineWidth = gc.Current.LineWidth / 2
var pathConverter *draw2d.PathConverter
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
dasher := draw2d.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
pathConverter = draw2d.NewPathConverter(dasher)
} else {
pathConverter = draw2d.NewPathConverter(stroker)
}
pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...)
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
gc.Current.Path = new(draw2d.PathStorage)
}
func (gc *GraphicContext) Fill(paths ...*draw2d.PathStorage) {
paths = append(paths, gc.Current.Path)
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
pathConverter := draw2d.NewPathConverter(draw2d.NewVertexMatrixTransform(gc.Current.Tr, draw2d.NewVertexAdder(gc.fillRasterizer)))
pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...)
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
gc.Current.Path = new(draw2d.PathStorage)
}
func (gc *GraphicContext) FillStroke(paths ...*draw2d.PathStorage) {
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
gc.strokeRasterizer.UseNonZeroWinding = true
filler := draw2d.NewVertexMatrixTransform(gc.Current.Tr, draw2d.NewVertexAdder(gc.fillRasterizer))
stroker := draw2d.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.NewVertexMatrixTransform(gc.Current.Tr, draw2d.NewVertexAdder(gc.strokeRasterizer)))
stroker.HalfLineWidth = gc.Current.LineWidth / 2
demux := draw2d.NewDemuxConverter(filler, stroker)
paths = append(paths, gc.Current.Path)
pathConverter := draw2d.NewPathConverter(demux)
pathConverter.ApproximationScale = gc.Current.Tr.GetMaxAbsScaling()
pathConverter.Convert(paths...)
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
gc.Current.Path = new(draw2d.PathStorage)
}