Merge branch 'sbinet-github-imports'

This commit is contained in:
Laurent Le Goff 2015-04-17 11:17:23 +02:00
commit 3d2a09c9e2
43 changed files with 941 additions and 921 deletions

View File

@ -1,7 +1,7 @@
#include $(GOROOT)/src/Make.inc #include $(GOROOT)/src/Make.inc
all: install all: install test
install: install:
cd draw2d && go install cd draw2d && go install
@ -15,6 +15,16 @@ build:
cd postscript && go build cd postscript && go build
# cd wingui && make build # cd wingui && make build
test:
#cd cmd && go build draw2dgl.go
cd cmd && go build gettingStarted.go
cd cmd && go build testandroid.go
cd cmd && go build testdraw2d.go
cd cmd && go build testgopher.go
cd cmd && go build testimage.go
cd cmd && go build testpostscript.go
#cd cmd && go build testX11draw.go
clean: clean:
cd draw2d && go clean cd draw2d && go clean
# cd draw2dgl && make clean # cd draw2dgl && make clean

8
README
View File

@ -11,14 +11,14 @@ Some algorithm have been translated from http://www.antigrain.com project ([http
Once you have Go installed, to install draw2d: Once you have Go installed, to install draw2d:
* First see the installation procedure of [http://code.google.com/p/freetype-go/ freetype-go] * First see the installation procedure of [http://code.google.com/p/freetype-go/ freetype-go]
* goinstall draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d * `go get github.com/llgcode/draw2d/draw2d`
a good starting point is the [http://code.google.com/p/draw2d/wiki/GettingStarted getting started] a good starting point is the [http://github.com/llgcode/draw2d/wiki/GettingStarted getting started]
=== [http://code.google.com/p/draw2d/wiki/Samples Samples] === === [http://github.com/llgcode/draw2d/wiki/Samples Samples] ===
Sample images generated by draw2d (inspired by [http://cairographics.org/samples/ cairo samples]): Sample images generated by draw2d (inspired by [http://cairographics.org/samples/ cairo samples]):
there's already some bugs please refer to [http://code.google.com/p/draw2d/issues/list issue tracking] there's already some bugs please refer to [http://github.com/llgcode/draw2d/issues issue tracking]
[http://draw2d.googlecode.com/svn/wiki/test_results/TestPath.png] [http://draw2d.googlecode.com/svn/wiki/test_results/TestPath.png]
[http://draw2d.googlecode.com/svn/wiki/test_results/TestDrawArc.png] [http://draw2d.googlecode.com/svn/wiki/test_results/TestDrawArc.png]

View File

@ -1,25 +1,23 @@
// Ported from GLUT's samples. Original copyright below applies. // Ported from GLUT's samples. Original copyright below applies.
/* Copyright (c) Mark J. Kilgard, 1996. */ /* Copyright (c) Mark J. Kilgard, 1996. */
/* This program is freely distributable without licensing fees /* This program is freely distributable without licensing fees
and is provided without guarantee or warrantee expressed or and is provided without guarantee or warrantee expressed or
implied. This program is -not- in the public domain. */ implied. This program is -not- in the public domain. */
/* This program is a response to a question posed by Gil Colgate /* This program is a response to a question posed by Gil Colgate
<gcolgate@sirius.com> about how lengthy a program is required using <gcolgate@sirius.com> about how lengthy a program is required using
OpenGL compared to using Direct3D immediate mode to "draw a OpenGL compared to using Direct3D immediate mode to "draw a
triangle at screen coordinates 0,0, to 200,200 to 20,200, and I 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 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 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 program is; Gil has used Direct3D and his guess is "about 3000
lines of code". */ lines of code". */
package main package main
import ( import (
"code.google.com/p/draw2d/draw2dgl"
"code.google.com/p/draw2d/postscript"
"gl" "gl"
"glut" "glut"
"io/ioutil" "io/ioutil"
@ -28,6 +26,9 @@ import (
"os" "os"
"strings" "strings"
"time" "time"
"github.com/llgcode/draw2d/draw2dgl"
"github.com/llgcode/draw2d/postscript"
) )
var postscriptContent string var postscriptContent string
@ -38,13 +39,13 @@ var (
) )
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) gl.ClearColor(1, 1, 1, 1)
//fmt.Println(gl.GetString(gl.EXTENSIONS)) //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. */

View File

@ -6,12 +6,12 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"image"
"image/png"
"log" "log"
"os" "os"
"code.google.com/p/draw2d/draw2d" "github.com/llgcode/draw2d/draw2d"
"image"
"image/png"
) )
func saveToPngFile(filePath string, m image.Image) { func saveToPngFile(filePath string, m image.Image) {

View File

@ -1,12 +1,13 @@
package main package main
import ( import (
"code.google.com/p/draw2d/draw2d"
"exp/gui" "exp/gui"
"exp/gui/x11" "exp/gui/x11"
"fmt" "fmt"
"image" "image"
"math" "math"
"github.com/llgcode/draw2d/draw2d"
) )
func main() { func main() {

View File

@ -3,14 +3,14 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"log"
"os"
"code.google.com/p/draw2d/draw2d"
"image" "image"
"image/color" "image/color"
"image/png" "image/png"
"log"
"math" "math"
"os"
"github.com/llgcode/draw2d/draw2d"
) )
const ( const (
@ -28,7 +28,7 @@ func initGc(w, h int) (image.Image, draw2d.GraphicContext) {
gc.SetStrokeColor(image.Black) gc.SetStrokeColor(image.Black)
gc.SetFillColor(image.White) gc.SetFillColor(image.White)
// fill the background // fill the background
//gc.Clear() //gc.Clear()
return i, gc return i, gc

View File

@ -6,14 +6,14 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"log"
"os"
"code.google.com/p/draw2d/draw2d"
"image" "image"
"image/color" "image/color"
"image/png" "image/png"
"log"
"math" "math"
"os"
"github.com/llgcode/draw2d/draw2d"
) )
const ( const (

View File

@ -3,14 +3,14 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"image"
"image/color"
"image/png"
"log" "log"
"math" "math"
"os" "os"
"code.google.com/p/draw2d/draw2d" "github.com/llgcode/draw2d/draw2d"
"image"
"image/color"
"image/png"
) )
const ( const (
@ -28,7 +28,7 @@ func initGc(w, h int) (image.Image, draw2d.GraphicContext) {
gc.SetStrokeColor(image.Black) gc.SetStrokeColor(image.Black)
gc.SetFillColor(image.White) gc.SetFillColor(image.White)
// fill the background // fill the background
//gc.Clear() //gc.Clear()
return i, gc return i, gc

View File

@ -2,7 +2,6 @@ package main
import ( import (
"bufio" "bufio"
"code.google.com/p/draw2d/draw2d"
"fmt" "fmt"
"image" "image"
"image/draw" "image/draw"
@ -10,6 +9,8 @@ import (
"log" "log"
"math" "math"
"os" "os"
"github.com/llgcode/draw2d/draw2d"
) )
func saveToPngFile(filePath string, m image.Image) { func saveToPngFile(filePath string, m image.Image) {

View File

@ -2,8 +2,6 @@ package main
import ( import (
"bufio" "bufio"
"code.google.com/p/draw2d/draw2d"
"code.google.com/p/draw2d/postscript"
"fmt" "fmt"
"image" "image"
"image/png" "image/png"
@ -11,6 +9,9 @@ import (
"log" "log"
"os" "os"
"strings" "strings"
"github.com/llgcode/draw2d/draw2d"
"github.com/llgcode/draw2d/postscript"
) )
func saveToPngFile(filePath string, m image.Image) { func saveToPngFile(filePath string, m image.Image) {

View File

@ -4,8 +4,9 @@
package draw2d package draw2d
import ( import (
"code.google.com/p/freetype-go/freetype/raster"
"math" "math"
"code.google.com/p/freetype-go/freetype/raster"
) )
func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) { func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {

View File

@ -1,6 +1,6 @@
package main package main
import "code.google.com/p/draw2d/draw2d/curve" import "github.com/llgcode/draw2d/draw2d/curve"
import "testing" import "testing"
import __os__ "os" import __os__ "os"
import __regexp__ "regexp" import __regexp__ "regexp"

View File

@ -24,7 +24,7 @@ func SegmentArc(t LineTracer, x, y, rx, ry, start, angle, scale float64) {
if (angle < end-da/4) != clockWise { if (angle < end-da/4) != clockWise {
curX = x + math.Cos(end)*rx curX = x + math.Cos(end)*rx
curY = y + math.Sin(end)*ry curY = y + math.Sin(end)*ry
break; break
} }
curX = x + math.Cos(angle)*rx curX = x + math.Cos(angle)*rx
curY = y + math.Sin(angle)*ry curY = y + math.Sin(angle)*ry

View File

@ -1,5 +1,5 @@
// Copyright 2010 The draw2d Authors. All rights reserved. // Copyright 2010 The draw2d Authors. All rights reserved.
// created: 17/05/2011 by Laurent Le Goff // created: 17/05/2011 by Laurent Le Goff
package curve package curve
import ( import (
@ -10,7 +10,7 @@ const (
CurveRecursionLimit = 32 CurveRecursionLimit = 32
) )
// X1, Y1, X2, Y2, X3, Y3, X4, Y4 float64 // X1, Y1, X2, Y2, X3, Y3, X4, Y4 float64
type CubicCurveFloat64 [8]float64 type CubicCurveFloat64 [8]float64
type LineTracer interface { type LineTracer interface {
@ -18,8 +18,8 @@ type LineTracer interface {
} }
func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) (x23, y23 float64) { func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) (x23, y23 float64) {
// Calculate all the mid-points of the line segments // Calculate all the mid-points of the line segments
//---------------------- //----------------------
c1[0], c1[1] = c[0], c[1] c1[0], c1[1] = c[0], c[1]
c2[6], c2[7] = c[6], c[7] c2[6], c2[7] = c[6], c[7]
c1[2] = (c[0] + c[2]) / 2 c1[2] = (c[0] + c[2]) / 2
@ -42,7 +42,7 @@ func (curve *CubicCurveFloat64) Segment(t LineTracer, flattening_threshold float
var curves [CurveRecursionLimit]CubicCurveFloat64 var curves [CurveRecursionLimit]CubicCurveFloat64
curves[0] = *curve curves[0] = *curve
i := 0 i := 0
// current curve // current curve
var c *CubicCurveFloat64 var c *CubicCurveFloat64
var dx, dy, d2, d3 float64 var dx, dy, d2, d3 float64
@ -59,7 +59,7 @@ func (curve *CubicCurveFloat64) Segment(t LineTracer, flattening_threshold float
t.LineTo(c[6], c[7]) t.LineTo(c[6], c[7])
i-- i--
} else { } else {
// second half of bezier go lower onto the stack // second half of bezier go lower onto the stack
c.Subdivide(&curves[i+1], &curves[i]) c.Subdivide(&curves[i+1], &curves[i])
i++ i++
} }

View File

@ -1,5 +1,5 @@
// Copyright 2010 The draw2d Authors. All rights reserved. // Copyright 2010 The draw2d Authors. All rights reserved.
// created: 17/05/2011 by Laurent Le Goff // created: 17/05/2011 by Laurent Le Goff
package curve package curve
import ( import (
@ -11,7 +11,7 @@ const (
CurveAngleToleranceEpsilon = 0.01 CurveAngleToleranceEpsilon = 0.01
) )
//mu ranges from 0 to 1, start to end of curve //mu ranges from 0 to 1, start to end of curve
func (c *CubicCurveFloat64) ArbitraryPoint(mu float64) (x, y float64) { func (c *CubicCurveFloat64) ArbitraryPoint(mu float64) (x, y float64) {
mum1 := 1 - mu mum1 := 1 - mu
@ -60,7 +60,7 @@ func (c *CubicCurveFloat64) EstimateDistance() float64 {
return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3) return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3)
} }
// subdivide the curve in straight lines using line approximation and Casteljau recursive subdivision // subdivide the curve in straight lines using line approximation and Casteljau recursive subdivision
func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) { func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) {
c.segmentRec(t, flattening_threshold) c.segmentRec(t, flattening_threshold)
t.LineTo(c[6], c[7]) t.LineTo(c[6], c[7])
@ -70,8 +70,8 @@ func (c *CubicCurveFloat64) segmentRec(t LineTracer, flattening_threshold float6
var c1, c2 CubicCurveFloat64 var c1, c2 CubicCurveFloat64
c.Subdivide(&c1, &c2) c.Subdivide(&c1, &c2)
// Try to approximate the full cubic curve by a single straight line // Try to approximate the full cubic curve by a single straight line
//------------------ //------------------
dx := c[6] - c[0] dx := c[6] - c[0]
dy := c[7] - c[1] dy := c[7] - c[1]
@ -82,31 +82,31 @@ func (c *CubicCurveFloat64) segmentRec(t LineTracer, flattening_threshold float6
t.LineTo(c[6], c[7]) t.LineTo(c[6], c[7])
return return
} }
// Continue subdivision // Continue subdivision
//---------------------- //----------------------
c1.segmentRec(t, flattening_threshold) c1.segmentRec(t, flattening_threshold)
c2.segmentRec(t, flattening_threshold) c2.segmentRec(t, flattening_threshold)
} }
/* /*
The function has the following parameters: The function has the following parameters:
approximationScale : approximationScale :
Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one. Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one.
It always has some scaling coefficient. It always has some scaling coefficient.
The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels. The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels.
Usually it looks as follows: Usually it looks as follows:
curved.approximationScale(transform.scale()); curved.approximationScale(transform.scale());
where transform is the affine matrix that includes all the transformations, including viewport and zoom. where transform is the affine matrix that includes all the transformations, including viewport and zoom.
angleTolerance : angleTolerance :
You set it in radians. You set it in radians.
The less this value is the more accurate will be the approximation at sharp turns. The less this value is the more accurate will be the approximation at sharp turns.
But 0 means that we don't consider angle conditions at all. But 0 means that we don't consider angle conditions at all.
cuspLimit : cuspLimit :
An angle in radians. An angle in radians.
If 0, only the real cusps will have bevel cuts. If 0, only the real cusps will have bevel cuts.
If more than 0, it will restrict the sharpness. If more than 0, it will restrict the sharpness.
The more this value is the less sharp turns will be cut. The more this value is the less sharp turns will be cut.
Typically it should not exceed 10-15 degrees. Typically it should not exceed 10-15 degrees.
*/ */
func (c *CubicCurveFloat64) AdaptiveSegmentRec(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) { func (c *CubicCurveFloat64) AdaptiveSegmentRec(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) {
cuspLimit = computeCuspLimit(cuspLimit) cuspLimit = computeCuspLimit(cuspLimit)
@ -131,8 +131,8 @@ func squareDistance(x1, y1, x2, y2 float64) float64 {
return dx*dx + dy*dy return dx*dx + dy*dy
} }
/** /**
* http://www.antigrain.com/research/adaptive_bezier/index.html * http://www.antigrain.com/research/adaptive_bezier/index.html
*/ */
func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) { func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) {
if level > CurveRecursionLimit { if level > CurveRecursionLimit {
@ -141,8 +141,8 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
var c1, c2 CubicCurveFloat64 var c1, c2 CubicCurveFloat64
x23, y23 := c.Subdivide(&c1, &c2) x23, y23 := c.Subdivide(&c1, &c2)
// Try to approximate the full cubic curve by a single straight line // Try to approximate the full cubic curve by a single straight line
//------------------ //------------------
dx := c[6] - c[0] dx := c[6] - c[0]
dy := c[7] - c[1] dy := c[7] - c[1]
@ -150,8 +150,8 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
d3 := math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) d3 := math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx))
switch { switch {
case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
// All collinear OR p1==p4 // All collinear OR p1==p4
//---------------------- //----------------------
k := dx*dx + dy*dy k := dx*dx + dy*dy
if k == 0 { if k == 0 {
d2 = squareDistance(c[0], c[1], c[2], c[3]) d2 = squareDistance(c[0], c[1], c[2], c[3])
@ -165,8 +165,8 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
da2 = c[5] - c[1] da2 = c[5] - c[1]
d3 = k * (da1*dx + da2*dy) d3 = k * (da1*dx + da2*dy)
if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 {
// Simple collinear case, 1---2---3---4 // Simple collinear case, 1---2---3---4
// We can leave just two endpoints // We can leave just two endpoints
return return
} }
if d2 <= 0 { if d2 <= 0 {
@ -198,16 +198,16 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
} }
case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
// p1,p2,p4 are collinear, p3 is significant // p1,p2,p4 are collinear, p3 is significant
//---------------------- //----------------------
if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
if angleTolerance < CurveAngleToleranceEpsilon { if angleTolerance < CurveAngleToleranceEpsilon {
t.LineTo(x23, y23) t.LineTo(x23, y23)
return return
} }
// Angle Condition // Angle Condition
//---------------------- //----------------------
da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2]))
if da1 >= math.Pi { if da1 >= math.Pi {
da1 = 2*math.Pi - da1 da1 = 2*math.Pi - da1
@ -228,16 +228,16 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
} }
case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
// p1,p3,p4 are collinear, p2 is significant // p1,p3,p4 are collinear, p2 is significant
//---------------------- //----------------------
if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
if angleTolerance < CurveAngleToleranceEpsilon { if angleTolerance < CurveAngleToleranceEpsilon {
t.LineTo(x23, y23) t.LineTo(x23, y23)
return return
} }
// Angle Condition // Angle Condition
//---------------------- //----------------------
da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0]))
if da1 >= math.Pi { if da1 >= math.Pi {
da1 = 2*math.Pi - da1 da1 = 2*math.Pi - da1
@ -258,19 +258,19 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
} }
case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
// Regular case // Regular case
//----------------- //-----------------
if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) {
// If the curvature doesn't exceed the distanceTolerance value // If the curvature doesn't exceed the distanceTolerance value
// we tend to finish subdivisions. // we tend to finish subdivisions.
//---------------------- //----------------------
if angleTolerance < CurveAngleToleranceEpsilon { if angleTolerance < CurveAngleToleranceEpsilon {
t.LineTo(x23, y23) t.LineTo(x23, y23)
return return
} }
// Angle & Cusp Condition // Angle & Cusp Condition
//---------------------- //----------------------
k := math.Atan2(c[5]-c[3], c[4]-c[2]) k := math.Atan2(c[5]-c[3], c[4]-c[2])
da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0]))
da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k)
@ -282,8 +282,8 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
} }
if da1+da2 < angleTolerance { if da1+da2 < angleTolerance {
// Finally we can stop the recursion // Finally we can stop the recursion
//---------------------- //----------------------
t.LineTo(x23, y23) t.LineTo(x23, y23)
return return
} }
@ -302,8 +302,8 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
} }
} }
// Continue subdivision // Continue subdivision
//---------------------- //----------------------
c1.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) c1.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
c2.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) c2.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
@ -317,7 +317,7 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
var curves [CurveRecursionLimit]CubicCurveFloat64 var curves [CurveRecursionLimit]CubicCurveFloat64
curves[0] = *curve curves[0] = *curve
i := 0 i := 0
// current curve // current curve
var c *CubicCurveFloat64 var c *CubicCurveFloat64
var c1, c2 CubicCurveFloat64 var c1, c2 CubicCurveFloat64
var dx, dy, d2, d3, k, x23, y23 float64 var dx, dy, d2, d3, k, x23, y23 float64
@ -325,8 +325,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
c = &curves[i] c = &curves[i]
x23, y23 = c.Subdivide(&c1, &c2) x23, y23 = c.Subdivide(&c1, &c2)
// Try to approximate the full cubic curve by a single straight line // Try to approximate the full cubic curve by a single straight line
//------------------ //------------------
dx = c[6] - c[0] dx = c[6] - c[0]
dy = c[7] - c[1] dy = c[7] - c[1]
@ -338,8 +338,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
i-- i--
continue continue
case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
// All collinear OR p1==p4 // All collinear OR p1==p4
//---------------------- //----------------------
k = dx*dx + dy*dy k = dx*dx + dy*dy
if k == 0 { if k == 0 {
d2 = squareDistance(c[0], c[1], c[2], c[3]) d2 = squareDistance(c[0], c[1], c[2], c[3])
@ -353,8 +353,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
da2 = c[5] - c[1] da2 = c[5] - c[1]
d3 = k * (da1*dx + da2*dy) d3 = k * (da1*dx + da2*dy)
if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 {
// Simple collinear case, 1---2---3---4 // Simple collinear case, 1---2---3---4
// We can leave just two endpoints // We can leave just two endpoints
i-- i--
continue continue
} }
@ -389,8 +389,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
} }
case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
// p1,p2,p4 are collinear, p3 is significant // p1,p2,p4 are collinear, p3 is significant
//---------------------- //----------------------
if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
if angleTolerance < CurveAngleToleranceEpsilon { if angleTolerance < CurveAngleToleranceEpsilon {
t.LineTo(x23, y23) t.LineTo(x23, y23)
@ -398,8 +398,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
continue continue
} }
// Angle Condition // Angle Condition
//---------------------- //----------------------
da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2]))
if da1 >= math.Pi { if da1 >= math.Pi {
da1 = 2*math.Pi - da1 da1 = 2*math.Pi - da1
@ -422,8 +422,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
} }
case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
// p1,p3,p4 are collinear, p2 is significant // p1,p3,p4 are collinear, p2 is significant
//---------------------- //----------------------
if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
if angleTolerance < CurveAngleToleranceEpsilon { if angleTolerance < CurveAngleToleranceEpsilon {
t.LineTo(x23, y23) t.LineTo(x23, y23)
@ -431,8 +431,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
continue continue
} }
// Angle Condition // Angle Condition
//---------------------- //----------------------
da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0]))
if da1 >= math.Pi { if da1 >= math.Pi {
da1 = 2*math.Pi - da1 da1 = 2*math.Pi - da1
@ -455,20 +455,20 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
} }
case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
// Regular case // Regular case
//----------------- //-----------------
if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) {
// If the curvature doesn't exceed the distanceTolerance value // If the curvature doesn't exceed the distanceTolerance value
// we tend to finish subdivisions. // we tend to finish subdivisions.
//---------------------- //----------------------
if angleTolerance < CurveAngleToleranceEpsilon { if angleTolerance < CurveAngleToleranceEpsilon {
t.LineTo(x23, y23) t.LineTo(x23, y23)
i-- i--
continue continue
} }
// Angle & Cusp Condition // Angle & Cusp Condition
//---------------------- //----------------------
k := math.Atan2(c[5]-c[3], c[4]-c[2]) k := math.Atan2(c[5]-c[3], c[4]-c[2])
da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0]))
da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k)
@ -480,8 +480,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
} }
if da1+da2 < angleTolerance { if da1+da2 < angleTolerance {
// Finally we can stop the recursion // Finally we can stop the recursion
//---------------------- //----------------------
t.LineTo(x23, y23) t.LineTo(x23, y23)
i-- i--
continue continue
@ -503,8 +503,8 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
} }
} }
// Continue subdivision // Continue subdivision
//---------------------- //----------------------
curves[i+1], curves[i] = c1, c2 curves[i+1], curves[i] = c1, c2
i++ i++
} }
@ -513,27 +513,27 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
/********************** Ahmad thesis *******************/ /********************** Ahmad thesis *******************/
/************************************************************************************** /**************************************************************************************
* This code is the implementation of the Parabolic Approximation (PA). Although * * This code is the implementation of the Parabolic Approximation (PA). Although *
* it uses recursive subdivision as a safe net for the failing cases, this is an * * it uses recursive subdivision as a safe net for the failing cases, this is an *
* iterative routine and reduces considerably the number of vertices (point) * * iterative routine and reduces considerably the number of vertices (point) *
* generation. * * generation. *
**************************************************************************************/ **************************************************************************************/
func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) { func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) {
estimatedIFP := c.numberOfInflectionPoints() estimatedIFP := c.numberOfInflectionPoints()
if estimatedIFP == 0 { if estimatedIFP == 0 {
// If no inflection points then apply PA on the full Bezier segment. // If no inflection points then apply PA on the full Bezier segment.
c.doParabolicApproximation(t, flattening_threshold) c.doParabolicApproximation(t, flattening_threshold)
return return
} }
// If one or more inflection point then we will have to subdivide the curve // If one or more inflection point then we will have to subdivide the curve
numOfIfP, t1, t2 := c.findInflectionPoints() numOfIfP, t1, t2 := c.findInflectionPoints()
if numOfIfP == 2 { if numOfIfP == 2 {
// Case when 2 inflection points then divide at the smallest one first // Case when 2 inflection points then divide at the smallest one first
var sub1, tmp1, sub2, sub3 CubicCurveFloat64 var sub1, tmp1, sub2, sub3 CubicCurveFloat64
c.SubdivideAt(&sub1, &tmp1, t1) c.SubdivideAt(&sub1, &tmp1, t1)
// Now find the second inflection point in the second curve an subdivide // Now find the second inflection point in the second curve an subdivide
numOfIfP, t1, t2 = tmp1.findInflectionPoints() numOfIfP, t1, t2 = tmp1.findInflectionPoints()
if numOfIfP == 2 { if numOfIfP == 2 {
tmp1.SubdivideAt(&sub2, &sub3, t2) tmp1.SubdivideAt(&sub2, &sub3, t2)
@ -542,29 +542,29 @@ func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold
} else { } else {
return return
} }
// Use PA for first subsegment // Use PA for first subsegment
sub1.doParabolicApproximation(t, flattening_threshold) sub1.doParabolicApproximation(t, flattening_threshold)
// Use RS for the second (middle) subsegment // Use RS for the second (middle) subsegment
sub2.Segment(t, flattening_threshold) sub2.Segment(t, flattening_threshold)
// Drop the last point in the array will be added by the PA in third subsegment // Drop the last point in the array will be added by the PA in third subsegment
//noOfPoints--; //noOfPoints--;
// Use PA for the third curve // Use PA for the third curve
sub3.doParabolicApproximation(t, flattening_threshold) sub3.doParabolicApproximation(t, flattening_threshold)
} else if numOfIfP == 1 { } else if numOfIfP == 1 {
// Case where there is one inflection point, subdivide once and use PA on // Case where there is one inflection point, subdivide once and use PA on
// both subsegments // both subsegments
var sub1, sub2 CubicCurveFloat64 var sub1, sub2 CubicCurveFloat64
c.SubdivideAt(&sub1, &sub2, t1) c.SubdivideAt(&sub1, &sub2, t1)
sub1.doParabolicApproximation(t, flattening_threshold) sub1.doParabolicApproximation(t, flattening_threshold)
//noOfPoints--; //noOfPoints--;
sub2.doParabolicApproximation(t, flattening_threshold) sub2.doParabolicApproximation(t, flattening_threshold)
} else { } else {
// Case where there is no inflection USA PA directly // Case where there is no inflection USA PA directly
c.doParabolicApproximation(t, flattening_threshold) c.doParabolicApproximation(t, flattening_threshold)
} }
} }
// Find the third control point deviation form the axis // Find the third control point deviation form the axis
func (c *CubicCurveFloat64) thirdControlPointDeviation() float64 { func (c *CubicCurveFloat64) thirdControlPointDeviation() float64 {
dx := c[2] - c[0] dx := c[2] - c[0]
dy := c[3] - c[1] dy := c[3] - c[1]
@ -579,7 +579,7 @@ func (c *CubicCurveFloat64) thirdControlPointDeviation() float64 {
return math.Abs(r*c[4] + s*c[5] + u) return math.Abs(r*c[4] + s*c[5] + u)
} }
// Find the number of inflection point // Find the number of inflection point
func (c *CubicCurveFloat64) numberOfInflectionPoints() int { func (c *CubicCurveFloat64) numberOfInflectionPoints() int {
dx21 := (c[2] - c[0]) dx21 := (c[2] - c[0])
dy21 := (c[3] - c[1]) dy21 := (c[3] - c[1])
@ -588,21 +588,21 @@ func (c *CubicCurveFloat64) numberOfInflectionPoints() int {
dx43 := (c[6] - c[4]) dx43 := (c[6] - c[4])
dy43 := (c[7] - c[5]) dy43 := (c[7] - c[5])
if ((dx21*dy32 - dy21*dx32) * (dx32*dy43 - dy32*dx43)) < 0 { if ((dx21*dy32 - dy21*dx32) * (dx32*dy43 - dy32*dx43)) < 0 {
return 1 // One inflection point return 1 // One inflection point
} else if ((dx21*dy32 - dy21*dx32) * (dx21*dy43 - dy21*dx43)) > 0 { } else if ((dx21*dy32 - dy21*dx32) * (dx21*dy43 - dy21*dx43)) > 0 {
return 0 // No inflection point return 0 // No inflection point
} else { } else {
// Most cases no inflection point // Most cases no inflection point
b1 := (dx21*dx32 + dy21*dy32) > 0 b1 := (dx21*dx32 + dy21*dy32) > 0
b2 := (dx32*dx43 + dy32*dy43) > 0 b2 := (dx32*dx43 + dy32*dy43) > 0
if b1 || b2 && !(b1 && b2) { // xor!! if b1 || b2 && !(b1 && b2) { // xor!!
return 0 return 0
} }
} }
return -1 // cases where there in zero or two inflection points return -1 // cases where there in zero or two inflection points
} }
// This is the main function where all the work is done // This is the main function where all the work is done
func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flattening_threshold float64) { func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flattening_threshold float64) {
var c *CubicCurveFloat64 var c *CubicCurveFloat64
c = curve c = curve
@ -615,23 +615,23 @@ func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flat
d3 = math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) d3 = math.Abs(((c[4]-c[6])*dy - (c[5]-c[7])*dx))
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) { if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) {
// If the subsegment deviation satisfy the flatness then store the last // If the subsegment deviation satisfy the flatness then store the last
// point and stop // point and stop
tracer.LineTo(c[6], c[7]) tracer.LineTo(c[6], c[7])
break break
} }
// Find the third control point deviation and the t values for subdivision // Find the third control point deviation and the t values for subdivision
d = c.thirdControlPointDeviation() d = c.thirdControlPointDeviation()
t = 2 * math.Sqrt(flattening_threshold/d/3) t = 2 * math.Sqrt(flattening_threshold/d/3)
if t > 1 { if t > 1 {
// Case where the t value calculated is invalid so using RS // Case where the t value calculated is invalid so using RS
c.Segment(tracer, flattening_threshold) c.Segment(tracer, flattening_threshold)
break break
} }
// Valid t value to subdivide at that calculated value // Valid t value to subdivide at that calculated value
var b1, b2 CubicCurveFloat64 var b1, b2 CubicCurveFloat64
c.SubdivideAt(&b1, &b2, t) c.SubdivideAt(&b1, &b2, t)
// First subsegment should have its deviation equal to flatness // First subsegment should have its deviation equal to flatness
dx = b1[6] - b1[0] dx = b1[6] - b1[0]
dy = b1[7] - b1[1] dy = b1[7] - b1[1]
@ -639,24 +639,24 @@ func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flat
d3 = math.Abs(((b1[4]-b1[6])*dy - (b1[5]-b1[7])*dx)) d3 = math.Abs(((b1[4]-b1[6])*dy - (b1[5]-b1[7])*dx))
if (d2+d3)*(d2+d3) > flattening_threshold*(dx*dx+dy*dy) { if (d2+d3)*(d2+d3) > flattening_threshold*(dx*dx+dy*dy) {
// if not then use RS to handle any mathematical errors // if not then use RS to handle any mathematical errors
b1.Segment(tracer, flattening_threshold) b1.Segment(tracer, flattening_threshold)
} else { } else {
tracer.LineTo(b1[6], b1[7]) tracer.LineTo(b1[6], b1[7])
} }
// repeat the process for the left over subsegment. // repeat the process for the left over subsegment.
c = &b2 c = &b2
} }
} }
// Find the actual inflection points and return the number of inflection points found // Find the actual inflection points and return the number of inflection points found
// if 2 inflection points found, the first one returned will be with smaller t value. // if 2 inflection points found, the first one returned will be with smaller t value.
func (curve *CubicCurveFloat64) findInflectionPoints() (int, firstIfp, secondIfp float64) { func (curve *CubicCurveFloat64) findInflectionPoints() (int, firstIfp, secondIfp float64) {
// For Cubic Bezier curve with equation P=a*t^3 + b*t^2 + c*t + d // For Cubic Bezier curve with equation P=a*t^3 + b*t^2 + c*t + d
// slope of the curve dP/dt = 3*a*t^2 + 2*b*t + c // slope of the curve dP/dt = 3*a*t^2 + 2*b*t + c
// a = (float)(-bez.p1 + 3*bez.p2 - 3*bez.p3 + bez.p4); // a = (float)(-bez.p1 + 3*bez.p2 - 3*bez.p3 + bez.p4);
// b = (float)(3*bez.p1 - 6*bez.p2 + 3*bez.p3); // b = (float)(3*bez.p1 - 6*bez.p2 + 3*bez.p3);
// c = (float)(-3*bez.p1 + 3*bez.p2); // c = (float)(-3*bez.p1 + 3*bez.p2);
ax := (-curve[0] + 3*curve[2] - 3*curve[4] + curve[6]) ax := (-curve[0] + 3*curve[2] - 3*curve[4] + curve[6])
bx := (3*curve[0] - 6*curve[2] + 3*curve[4]) bx := (3*curve[0] - 6*curve[2] + 3*curve[4])
cx := (-3*curve[0] + 3*curve[2]) cx := (-3*curve[0] + 3*curve[2])

View File

@ -2,7 +2,6 @@ package curve
import ( import (
"bufio" "bufio"
"code.google.com/p/draw2d/draw2d/raster"
"fmt" "fmt"
"image" "image"
"image/color" "image/color"
@ -11,6 +10,8 @@ import (
"log" "log"
"os" "os"
"testing" "testing"
"github.com/llgcode/draw2d/draw2d/raster"
) )
var ( var (
@ -89,17 +90,17 @@ func savepng(filePath string, m image.Image) {
} }
func drawPoints(img draw.Image, c color.Color, s ...float64) image.Image { func drawPoints(img draw.Image, c color.Color, s ...float64) image.Image {
/*for i := 0; i < len(s); i += 2 { /*for i := 0; i < len(s); i += 2 {
x, y := int(s[i]+0.5), int(s[i+1]+0.5) x, y := int(s[i]+0.5), int(s[i+1]+0.5)
img.Set(x, y, c) img.Set(x, y, c)
img.Set(x, y+1, c) img.Set(x, y+1, c)
img.Set(x, y-1, c) img.Set(x, y-1, c)
img.Set(x+1, y, c) img.Set(x+1, y, c)
img.Set(x+1, y+1, c) img.Set(x+1, y+1, c)
img.Set(x+1, y-1, c) img.Set(x+1, y-1, c)
img.Set(x-1, y, c) img.Set(x-1, y, c)
img.Set(x-1, y+1, c) img.Set(x-1, y+1, c)
img.Set(x-1, y-1, c) img.Set(x-1, y-1, c)
}*/ }*/
return img return img
@ -113,7 +114,7 @@ func TestCubicCurveRec(t *testing.T) {
img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
raster.PolylineBresenham(img, image.Black, p.points...) raster.PolylineBresenham(img, image.Black, p.points...)
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
savepng(fmt.Sprintf("_testRec%d.png", i), img) savepng(fmt.Sprintf("_testRec%d.png", i), img)
log.Printf("Num of points: %d\n", len(p.points)) log.Printf("Num of points: %d\n", len(p.points))
@ -129,7 +130,7 @@ func TestCubicCurve(t *testing.T) {
img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
raster.PolylineBresenham(img, image.Black, p.points...) raster.PolylineBresenham(img, image.Black, p.points...)
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
savepng(fmt.Sprintf("_test%d.png", i), img) savepng(fmt.Sprintf("_test%d.png", i), img)
log.Printf("Num of points: %d\n", len(p.points)) log.Printf("Num of points: %d\n", len(p.points))
@ -145,7 +146,7 @@ func TestCubicCurveAdaptiveRec(t *testing.T) {
img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
raster.PolylineBresenham(img, image.Black, p.points...) raster.PolylineBresenham(img, image.Black, p.points...)
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
savepng(fmt.Sprintf("_testAdaptiveRec%d.png", i), img) savepng(fmt.Sprintf("_testAdaptiveRec%d.png", i), img)
log.Printf("Num of points: %d\n", len(p.points)) log.Printf("Num of points: %d\n", len(p.points))
@ -161,7 +162,7 @@ func TestCubicCurveAdaptive(t *testing.T) {
img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
raster.PolylineBresenham(img, image.Black, p.points...) raster.PolylineBresenham(img, image.Black, p.points...)
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
savepng(fmt.Sprintf("_testAdaptive%d.png", i), img) savepng(fmt.Sprintf("_testAdaptive%d.png", i), img)
log.Printf("Num of points: %d\n", len(p.points)) log.Printf("Num of points: %d\n", len(p.points))
@ -177,7 +178,7 @@ func TestCubicCurveParabolic(t *testing.T) {
img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
raster.PolylineBresenham(img, image.Black, p.points...) raster.PolylineBresenham(img, image.Black, p.points...)
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
savepng(fmt.Sprintf("_testParabolic%d.png", i), img) savepng(fmt.Sprintf("_testParabolic%d.png", i), img)
log.Printf("Num of points: %d\n", len(p.points)) log.Printf("Num of points: %d\n", len(p.points))
@ -193,7 +194,7 @@ func TestQuadCurve(t *testing.T) {
img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...)
raster.PolylineBresenham(img, image.Black, p.points...) raster.PolylineBresenham(img, image.Black, p.points...)
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
savepng(fmt.Sprintf("_testQuad%d.png", i), img) savepng(fmt.Sprintf("_testQuad%d.png", i), img)
log.Printf("Num of points: %d\n", len(p.points)) log.Printf("Num of points: %d\n", len(p.points))

View File

@ -1,17 +1,17 @@
// Copyright 2010 The draw2d Authors. All rights reserved. // Copyright 2010 The draw2d Authors. All rights reserved.
// created: 17/05/2011 by Laurent Le Goff // created: 17/05/2011 by Laurent Le Goff
package curve package curve
import ( import (
"math" "math"
) )
//X1, Y1, X2, Y2, X3, Y3 float64 //X1, Y1, X2, Y2, X3, Y3 float64
type QuadCurveFloat64 [6]float64 type QuadCurveFloat64 [6]float64
func (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) { func (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) {
// Calculate all the mid-points of the line segments // Calculate all the mid-points of the line segments
//---------------------- //----------------------
c1[0], c1[1] = c[0], c[1] c1[0], c1[1] = c[0], c[1]
c2[4], c2[5] = c[4], c[5] c2[4], c2[5] = c[4], c[5]
c1[2] = (c[0] + c[2]) / 2 c1[2] = (c[0] + c[2]) / 2
@ -28,7 +28,7 @@ func (curve *QuadCurveFloat64) Segment(t LineTracer, flattening_threshold float6
var curves [CurveRecursionLimit]QuadCurveFloat64 var curves [CurveRecursionLimit]QuadCurveFloat64
curves[0] = *curve curves[0] = *curve
i := 0 i := 0
// current curve // current curve
var c *QuadCurveFloat64 var c *QuadCurveFloat64
var dx, dy, d float64 var dx, dy, d float64
@ -43,7 +43,7 @@ func (curve *QuadCurveFloat64) Segment(t LineTracer, flattening_threshold float6
t.LineTo(c[4], c[5]) t.LineTo(c[4], c[5])
i-- i--
} else { } else {
// second half of bezier go lower onto the stack // second half of bezier go lower onto the stack
c.Subdivide(&curves[i+1], &curves[i]) c.Subdivide(&curves[i+1], &curves[i])
i++ i++
} }

View File

@ -15,22 +15,22 @@ var (
/* /*
The function has the following parameters: The function has the following parameters:
approximationScale : approximationScale :
Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one. Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one.
It always has some scaling coefficient. It always has some scaling coefficient.
The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels. The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels.
Usually it looks as follows: Usually it looks as follows:
curved.approximationScale(transform.scale()); curved.approximationScale(transform.scale());
where transform is the affine matrix that includes all the transformations, including viewport and zoom. where transform is the affine matrix that includes all the transformations, including viewport and zoom.
angleTolerance : angleTolerance :
You set it in radians. You set it in radians.
The less this value is the more accurate will be the approximation at sharp turns. The less this value is the more accurate will be the approximation at sharp turns.
But 0 means that we don't consider angle conditions at all. But 0 means that we don't consider angle conditions at all.
cuspLimit : cuspLimit :
An angle in radians. An angle in radians.
If 0, only the real cusps will have bevel cuts. If 0, only the real cusps will have bevel cuts.
If more than 0, it will restrict the sharpness. If more than 0, it will restrict the sharpness.
The more this value is the less sharp turns will be cut. The more this value is the less sharp turns will be cut.
Typically it should not exceed 10-15 degrees. Typically it should not exceed 10-15 degrees.
*/ */
func cubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float64) { func cubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float64) {

View File

@ -1,5 +1,5 @@
// Copyright 2010 The draw2d Authors. All rights reserved. // Copyright 2010 The draw2d Authors. All rights reserved.
// created: 13/12/2010 by Laurent Le Goff // created: 13/12/2010 by Laurent Le Goff
// The package draw2d provide a Graphic Context that can draw vectorial figure on surface. // The package draw2d provide a Graphic Context that can draw vectorial figure on surface.
package draw2d package draw2d

View File

@ -4,10 +4,11 @@
package draw2d package draw2d
import ( import (
"code.google.com/p/freetype-go/freetype/truetype"
"io/ioutil" "io/ioutil"
"log" "log"
"path" "path"
"code.google.com/p/freetype-go/freetype/truetype"
) )
var ( var (

View File

@ -4,14 +4,15 @@
package draw2d package draw2d
import ( import (
"code.google.com/p/freetype-go/freetype/raster"
"code.google.com/p/freetype-go/freetype/truetype"
"errors" "errors"
"image" "image"
"image/color" "image/color"
"image/draw" "image/draw"
"log" "log"
"math" "math"
"code.google.com/p/freetype-go/freetype/raster"
"code.google.com/p/freetype-go/freetype/truetype"
) )
type Painter interface { type Painter interface {

View File

@ -8,12 +8,12 @@ type Path interface {
LastPoint() (x, y float64) LastPoint() (x, y float64)
// Create a new subpath that start at the specified point // Create a new subpath that start at the specified point
MoveTo(x, y float64) MoveTo(x, y float64)
// Create a new subpath that start at the specified point // Create a new subpath that start at the specified point
// relative to the current point // relative to the current point
RMoveTo(dx, dy float64) RMoveTo(dx, dy float64)
// Add a line to the current subpath // Add a line to the current subpath
LineTo(x, y float64) LineTo(x, y float64)
// Add a line to the current subpath // Add a line to the current subpath
// relative to the current point // relative to the current point
RLineTo(dx, dy float64) RLineTo(dx, dy float64)

View File

@ -1,5 +1,5 @@
// Copyright 2011 The draw2d Authors. All rights reserved. // Copyright 2011 The draw2d Authors. All rights reserved.
// created: 27/05/2011 by Laurent Le Goff // created: 27/05/2011 by Laurent Le Goff
package raster package raster
var SUBPIXEL_OFFSETS_SAMPLE_8 = [8]float64{ var SUBPIXEL_OFFSETS_SAMPLE_8 = [8]float64{

View File

@ -1,5 +1,5 @@
// Copyright 2011 The draw2d Authors. All rights reserved. // Copyright 2011 The draw2d Authors. All rights reserved.
// created: 27/05/2011 by Laurent Le Goff // created: 27/05/2011 by Laurent Le Goff
package raster package raster
import ( import (
@ -29,21 +29,21 @@ type Rasterizer8BitsSample struct {
RemappingMatrix [6]float64 RemappingMatrix [6]float64
} }
/* width and height define the maximum output size for the filler. /* width and height define the maximum output size for the filler.
* The filler will output to larger bitmaps as well, but the output will * The filler will output to larger bitmaps as well, but the output will
* be cropped. * be cropped.
*/ */
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample { func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
var r Rasterizer8BitsSample var r Rasterizer8BitsSample
// Scale the coordinates by SUBPIXEL_COUNT in vertical direction // Scale the coordinates by SUBPIXEL_COUNT in vertical direction
// The sampling point for the sub-pixel is at the top right corner. This // The sampling point for the sub-pixel is at the top right corner. This
// adjustment moves it to the pixel center. // adjustment moves it to the pixel center.
r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT} r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
r.Width = width r.Width = width
r.Height = height r.Height = height
// The buffer used for filling needs to be one pixel wider than the bitmap. // The buffer used for filling needs to be one pixel wider than the bitmap.
// This is because the end flag that turns the fill of is the first pixel // This is because the end flag that turns the fill of is the first pixel
// after the actually drawn edge. // after the actually drawn edge.
r.BufferWidth = width + 1 r.BufferWidth = width + 1
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
@ -89,10 +89,10 @@ func intersect(r1, r2 [4]float64) [4]float64 {
} }
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
// memset 0 the mask buffer // memset 0 the mask buffer
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
// inline matrix multiplication // inline matrix multiplication
transform := [6]float64{ transform := [6]float64{
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
@ -118,7 +118,7 @@ func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA
r.fillEvenOdd(img, color, clipRect) r.fillEvenOdd(img, color, clipRect)
} }
//! Adds an edge to be used with even-odd fill. //! Adds an edge to be used with even-odd fill.
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
x := Fix(edge.X * FIXED_FLOAT_COEF) x := Fix(edge.X * FIXED_FLOAT_COEF)
slope := Fix(edge.Slope * FIXED_FLOAT_COEF) slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
@ -143,7 +143,7 @@ func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
} }
} }
//! Adds an edge to be used with non-zero winding fill. //! Adds an edge to be used with non-zero winding fill.
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
x := Fix(edge.X * FIXED_FLOAT_COEF) x := Fix(edge.X * FIXED_FLOAT_COEF)
slope := Fix(edge.Slope * FIXED_FLOAT_COEF) slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
@ -169,7 +169,7 @@ func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
} }
} }
// Renders the mask to the canvas with even-odd fill. // Renders the mask to the canvas with even-odd fill.
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
var x, y uint32 var x, y uint32
@ -179,7 +179,7 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
//pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
pixColor := (*uint32)(unsafe.Pointer(color)) pixColor := (*uint32)(unsafe.Pointer(color))
cs1 := *pixColor & 0xff00ff cs1 := *pixColor & 0xff00ff
cs2 := *pixColor >> 8 & 0xff00ff cs2 := *pixColor >> 8 & 0xff00ff
@ -194,14 +194,14 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
for x = minX; x <= maxX; x++ { for x = minX; x <= maxX; x++ {
p := (*uint32)(unsafe.Pointer(&tp[x])) p := (*uint32)(unsafe.Pointer(&tp[x]))
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x] mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
// 8bits // 8bits
alpha := uint32(coverageTable[mask]) alpha := uint32(coverageTable[mask])
// 16bits // 16bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
// 32bits // 32bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
// alpha is in range of 0 to SUBPIXEL_COUNT // alpha is in range of 0 to SUBPIXEL_COUNT
invAlpha := SUBPIXEL_COUNT - alpha invAlpha := SUBPIXEL_COUNT - alpha
ct1 := *p & 0xff00ff * invAlpha ct1 := *p & 0xff00ff * invAlpha
@ -215,19 +215,19 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
} }
} }
/* /*
* Renders the polygon with non-zero winding fill. * Renders the polygon with non-zero winding fill.
* param aTarget the target bitmap. * param aTarget the target bitmap.
* param aPolygon the polygon to render. * param aPolygon the polygon to render.
* param aColor the color to be used for rendering. * param aColor the color to be used for rendering.
* param aTransformation the transformation matrix. * param aTransformation the transformation matrix.
*/ */
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
// inline matrix multiplication // inline matrix multiplication
transform := [6]float64{ transform := [6]float64{
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
@ -254,7 +254,7 @@ func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *col
r.fillNonZero(img, color, clipRect) r.fillNonZero(img, color, clipRect)
} }
//! Renders the mask to the canvas with non-zero winding fill. //! Renders the mask to the canvas with non-zero winding fill.
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
var x, y uint32 var x, y uint32
@ -264,7 +264,7 @@ func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA,
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
//pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
pixColor := (*uint32)(unsafe.Pointer(color)) pixColor := (*uint32)(unsafe.Pointer(color))
cs1 := *pixColor & 0xff00ff cs1 := *pixColor & 0xff00ff
cs2 := *pixColor >> 8 & 0xff00ff cs2 := *pixColor >> 8 & 0xff00ff
@ -298,14 +298,14 @@ func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA,
} }
} }
// 8bits // 8bits
alpha := uint32(coverageTable[mask]) alpha := uint32(coverageTable[mask])
// 16bits // 16bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
// 32bits // 32bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
// alpha is in range of 0 to SUBPIXEL_COUNT // alpha is in range of 0 to SUBPIXEL_COUNT
invAlpha := uint32(SUBPIXEL_COUNT) - alpha invAlpha := uint32(SUBPIXEL_COUNT) - alpha
ct1 := *p & 0xff00ff * invAlpha ct1 := *p & 0xff00ff * invAlpha

View File

@ -1,5 +1,5 @@
// Copyright 2011 The draw2d Authors. All rights reserved. // Copyright 2011 The draw2d Authors. All rights reserved.
// created: 27/05/2011 by Laurent Le Goff // created: 27/05/2011 by Laurent Le Goff
package raster package raster
import ( import (
@ -29,21 +29,21 @@ type Rasterizer8BitsSample struct {
RemappingMatrix [6]float64 RemappingMatrix [6]float64
} }
/* width and height define the maximum output size for the filler. /* width and height define the maximum output size for the filler.
* The filler will output to larger bitmaps as well, but the output will * The filler will output to larger bitmaps as well, but the output will
* be cropped. * be cropped.
*/ */
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample { func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
var r Rasterizer8BitsSample var r Rasterizer8BitsSample
// Scale the coordinates by SUBPIXEL_COUNT in vertical direction // Scale the coordinates by SUBPIXEL_COUNT in vertical direction
// The sampling point for the sub-pixel is at the top right corner. This // The sampling point for the sub-pixel is at the top right corner. This
// adjustment moves it to the pixel center. // adjustment moves it to the pixel center.
r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT} r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
r.Width = width r.Width = width
r.Height = height r.Height = height
// The buffer used for filling needs to be one pixel wider than the bitmap. // The buffer used for filling needs to be one pixel wider than the bitmap.
// This is because the end flag that turns the fill of is the first pixel // This is because the end flag that turns the fill of is the first pixel
// after the actually drawn edge. // after the actually drawn edge.
r.BufferWidth = width + 1 r.BufferWidth = width + 1
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
@ -89,10 +89,10 @@ func intersect(r1, r2 [4]float64) [4]float64 {
} }
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
// memset 0 the mask buffer // memset 0 the mask buffer
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
// inline matrix multiplication // inline matrix multiplication
transform := [6]float64{ transform := [6]float64{
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
@ -118,7 +118,7 @@ func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA
r.fillEvenOdd(img, color, clipRect) r.fillEvenOdd(img, color, clipRect)
} }
//! Adds an edge to be used with even-odd fill. //! Adds an edge to be used with even-odd fill.
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
x := edge.X x := edge.X
slope := edge.Slope slope := edge.Slope
@ -134,7 +134,7 @@ func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
} }
} }
// Renders the mask to the canvas with even-odd fill. // Renders the mask to the canvas with even-odd fill.
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
var x, y uint32 var x, y uint32
@ -144,7 +144,7 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
//pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
pixColor := (*uint32)(unsafe.Pointer(color)) pixColor := (*uint32)(unsafe.Pointer(color))
cs1 := *pixColor & 0xff00ff cs1 := *pixColor & 0xff00ff
cs2 := *pixColor >> 8 & 0xff00ff cs2 := *pixColor >> 8 & 0xff00ff
@ -159,14 +159,14 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
for x = minX; x <= maxX; x++ { for x = minX; x <= maxX; x++ {
p := (*uint32)(unsafe.Pointer(&tp[x])) p := (*uint32)(unsafe.Pointer(&tp[x]))
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x] mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
// 8bits // 8bits
alpha := uint32(coverageTable[mask]) alpha := uint32(coverageTable[mask])
// 16bits // 16bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
// 32bits // 32bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
// alpha is in range of 0 to SUBPIXEL_COUNT // alpha is in range of 0 to SUBPIXEL_COUNT
invAlpha := uint32(SUBPIXEL_COUNT) - alpha invAlpha := uint32(SUBPIXEL_COUNT) - alpha
ct1 := *p & 0xff00ff * invAlpha ct1 := *p & 0xff00ff * invAlpha
@ -180,19 +180,19 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
} }
} }
/* /*
* Renders the polygon with non-zero winding fill. * Renders the polygon with non-zero winding fill.
* param aTarget the target bitmap. * param aTarget the target bitmap.
* param aPolygon the polygon to render. * param aPolygon the polygon to render.
* param aColor the color to be used for rendering. * param aColor the color to be used for rendering.
* param aTransformation the transformation matrix. * param aTransformation the transformation matrix.
*/ */
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
// inline matrix multiplication // inline matrix multiplication
transform := [6]float64{ transform := [6]float64{
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
@ -219,7 +219,7 @@ func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *col
r.fillNonZero(img, color, clipRect) r.fillNonZero(img, color, clipRect)
} }
//! Adds an edge to be used with non-zero winding fill. //! Adds an edge to be used with non-zero winding fill.
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
x := edge.X x := edge.X
slope := edge.Slope slope := edge.Slope
@ -237,7 +237,7 @@ func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
} }
} }
//! Renders the mask to the canvas with non-zero winding fill. //! Renders the mask to the canvas with non-zero winding fill.
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
var x, y uint32 var x, y uint32
@ -247,7 +247,7 @@ func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA,
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
//pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
pixColor := (*uint32)(unsafe.Pointer(color)) pixColor := (*uint32)(unsafe.Pointer(color))
cs1 := *pixColor & 0xff00ff cs1 := *pixColor & 0xff00ff
cs2 := *pixColor >> 8 & 0xff00ff cs2 := *pixColor >> 8 & 0xff00ff
@ -281,14 +281,14 @@ func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA,
} }
} }
// 8bits // 8bits
alpha := uint32(coverageTable[mask]) alpha := uint32(coverageTable[mask])
// 16bits // 16bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
// 32bits // 32bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff])
// alpha is in range of 0 to SUBPIXEL_COUNT // alpha is in range of 0 to SUBPIXEL_COUNT
invAlpha := uint32(SUBPIXEL_COUNT) - alpha invAlpha := uint32(SUBPIXEL_COUNT) - alpha
ct1 := *p & 0xff00ff * invAlpha ct1 := *p & 0xff00ff * invAlpha

View File

@ -1,5 +1,5 @@
// Copyright 2011 The draw2d Authors. All rights reserved. // Copyright 2011 The draw2d Authors. All rights reserved.
// created: 27/05/2011 by Laurent Le Goff // created: 27/05/2011 by Laurent Le Goff
package raster package raster
import ( import (
@ -29,21 +29,21 @@ type Rasterizer8BitsSample struct {
RemappingMatrix [6]float64 RemappingMatrix [6]float64
} }
/* width and height define the maximum output size for the filler. /* width and height define the maximum output size for the filler.
* The filler will output to larger bitmaps as well, but the output will * The filler will output to larger bitmaps as well, but the output will
* be cropped. * be cropped.
*/ */
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample { func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
var r Rasterizer8BitsSample var r Rasterizer8BitsSample
// Scale the coordinates by SUBPIXEL_COUNT in vertical direction // Scale the coordinates by SUBPIXEL_COUNT in vertical direction
// The sampling point for the sub-pixel is at the top right corner. This // The sampling point for the sub-pixel is at the top right corner. This
// adjustment moves it to the pixel center. // adjustment moves it to the pixel center.
r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT} r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
r.Width = width r.Width = width
r.Height = height r.Height = height
// The buffer used for filling needs to be one pixel wider than the bitmap. // The buffer used for filling needs to be one pixel wider than the bitmap.
// This is because the end flag that turns the fill of is the first pixel // This is because the end flag that turns the fill of is the first pixel
// after the actually drawn edge. // after the actually drawn edge.
r.BufferWidth = width + 1 r.BufferWidth = width + 1
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
@ -89,10 +89,10 @@ func intersect(r1, r2 [4]float64) [4]float64 {
} }
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
// memset 0 the mask buffer // memset 0 the mask buffer
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
// inline matrix multiplication // inline matrix multiplication
transform := [6]float64{ transform := [6]float64{
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
@ -118,7 +118,7 @@ func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA
r.fillEvenOdd(img, color, clipRect) r.fillEvenOdd(img, color, clipRect)
} }
//! Adds an edge to be used with even-odd fill. //! Adds an edge to be used with even-odd fill.
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
x := Fix(edge.X * FIXED_FLOAT_COEF) x := Fix(edge.X * FIXED_FLOAT_COEF)
slope := Fix(edge.Slope * FIXED_FLOAT_COEF) slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
@ -143,7 +143,7 @@ func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
} }
} }
//! Adds an edge to be used with non-zero winding fill. //! Adds an edge to be used with non-zero winding fill.
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
x := Fix(edge.X * FIXED_FLOAT_COEF) x := Fix(edge.X * FIXED_FLOAT_COEF)
slope := Fix(edge.Slope * FIXED_FLOAT_COEF) slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
@ -169,7 +169,7 @@ func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
} }
} }
// Renders the mask to the canvas with even-odd fill. // Renders the mask to the canvas with even-odd fill.
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
var x, y uint32 var x, y uint32
@ -179,7 +179,7 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
//pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
pixColor := (*uint32)(unsafe.Pointer(color)) pixColor := (*uint32)(unsafe.Pointer(color))
cs1 := *pixColor & 0xff00ff cs1 := *pixColor & 0xff00ff
cs2 := *pixColor >> 8 & 0xff00ff cs2 := *pixColor >> 8 & 0xff00ff
@ -194,14 +194,14 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
for x = minX; x <= maxX; x++ { for x = minX; x <= maxX; x++ {
p := (*uint32)(unsafe.Pointer(&tp[x])) p := (*uint32)(unsafe.Pointer(&tp[x]))
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x] mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
// 8bits // 8bits
//alpha := uint32(coverageTable[mask]) //alpha := uint32(coverageTable[mask])
// 16bits // 16bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
// 32bits // 32bits
alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff]) alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff])
// alpha is in range of 0 to SUBPIXEL_COUNT // alpha is in range of 0 to SUBPIXEL_COUNT
invAlpha := uint32(SUBPIXEL_COUNT) - alpha invAlpha := uint32(SUBPIXEL_COUNT) - alpha
ct1 := *p & 0xff00ff * invAlpha ct1 := *p & 0xff00ff * invAlpha
@ -215,19 +215,19 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA,
} }
} }
/* /*
* Renders the polygon with non-zero winding fill. * Renders the polygon with non-zero winding fill.
* param aTarget the target bitmap. * param aTarget the target bitmap.
* param aPolygon the polygon to render. * param aPolygon the polygon to render.
* param aColor the color to be used for rendering. * param aColor the color to be used for rendering.
* param aTransformation the transformation matrix. * param aTransformation the transformation matrix.
*/ */
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) {
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
// inline matrix multiplication // inline matrix multiplication
transform := [6]float64{ transform := [6]float64{
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
@ -254,7 +254,7 @@ func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *col
r.fillNonZero(img, color, clipRect) r.fillNonZero(img, color, clipRect)
} }
//! Renders the mask to the canvas with non-zero winding fill. //! Renders the mask to the canvas with non-zero winding fill.
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) {
var x, y uint32 var x, y uint32
@ -264,7 +264,7 @@ func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA,
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
//pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A)
pixColor := (*uint32)(unsafe.Pointer(color)) pixColor := (*uint32)(unsafe.Pointer(color))
cs1 := *pixColor & 0xff00ff cs1 := *pixColor & 0xff00ff
cs2 := *pixColor >> 8 & 0xff00ff cs2 := *pixColor >> 8 & 0xff00ff
@ -298,14 +298,14 @@ func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA,
} }
} }
// 8bits // 8bits
//alpha := uint32(coverageTable[mask]) //alpha := uint32(coverageTable[mask])
// 16bits // 16bits
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
// 32bits // 32bits
alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff]) alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff])
// alpha is in range of 0 to SUBPIXEL_COUNT // alpha is in range of 0 to SUBPIXEL_COUNT
invAlpha := uint32(SUBPIXEL_COUNT) - alpha invAlpha := uint32(SUBPIXEL_COUNT) - alpha
ct1 := *p & 0xff00ff * invAlpha ct1 := *p & 0xff00ff * invAlpha

View File

@ -1,5 +1,5 @@
// Copyright 2011 The draw2d Authors. All rights reserved. // Copyright 2011 The draw2d Authors. All rights reserved.
// created: 27/05/2011 by Laurent Le Goff // created: 27/05/2011 by Laurent Le Goff
package raster package raster
import ( import (

View File

@ -1,5 +1,5 @@
// Copyright 2011 The draw2d Authors. All rights reserved. // Copyright 2011 The draw2d Authors. All rights reserved.
// created: 27/05/2011 by Laurent Le Goff // created: 27/05/2011 by Laurent Le Goff
package raster package raster
const ( const (
@ -18,7 +18,7 @@ type PolygonEdge struct {
Winding int16 Winding int16
} }
//! A more optimized representation of a polygon edge. //! A more optimized representation of a polygon edge.
type PolygonScanEdge struct { type PolygonScanEdge struct {
FirstLine, LastLine int FirstLine, LastLine int
Winding int16 Winding int16
@ -28,13 +28,13 @@ type PolygonScanEdge struct {
NextEdge *PolygonScanEdge NextEdge *PolygonScanEdge
} }
//! Calculates the edges of the polygon with transformation and clipping to edges array. //! Calculates the edges of the polygon with transformation and clipping to edges array.
/*! \param startIndex the index for the first vertex. /*! \param startIndex the index for the first vertex.
* \param vertexCount the amount of vertices to convert. * \param vertexCount the amount of vertices to convert.
* \param edges the array for result edges. This should be able to contain 2*aVertexCount edges. * \param edges the array for result edges. This should be able to contain 2*aVertexCount edges.
* \param tr the transformation matrix for the polygon. * \param tr the transformation matrix for the polygon.
* \param aClipRectangle the clip rectangle. * \param aClipRectangle the clip rectangle.
* \return the amount of edges in the result. * \return the amount of edges in the result.
*/ */
func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [6]float64, clipBound [4]float64) int { func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [6]float64, clipBound [4]float64) int {
startIndex = startIndex * 2 startIndex = startIndex * 2
@ -45,11 +45,11 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
x := p[startIndex] x := p[startIndex]
y := p[startIndex+1] y := p[startIndex+1]
// inline transformation // inline transformation
prevX := x*tr[0] + y*tr[2] + tr[4] prevX := x*tr[0] + y*tr[2] + tr[4]
prevY := x*tr[1] + y*tr[3] + tr[5] prevY := x*tr[1] + y*tr[3] + tr[5]
//! Calculates the clip flags for a point. //! Calculates the clip flags for a point.
prevClipFlags := POLYGON_CLIP_NONE prevClipFlags := POLYGON_CLIP_NONE
if prevX < clipBound[0] { if prevX < clipBound[0] {
prevClipFlags |= POLYGON_CLIP_LEFT prevClipFlags |= POLYGON_CLIP_LEFT
@ -72,7 +72,7 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
x = p[k]*tr[0] + p[k+1]*tr[2] + tr[4] x = p[k]*tr[0] + p[k+1]*tr[2] + tr[4]
y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5] y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5]
//! Calculates the clip flags for a point. //! Calculates the clip flags for a point.
clipFlags = POLYGON_CLIP_NONE clipFlags = POLYGON_CLIP_NONE
if prevX < clipBound[0] { if prevX < clipBound[0] {
clipFlags |= POLYGON_CLIP_LEFT clipFlags |= POLYGON_CLIP_LEFT
@ -88,25 +88,25 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
clipSum = prevClipFlags | clipFlags clipSum = prevClipFlags | clipFlags
clipUnion = prevClipFlags & clipFlags clipUnion = prevClipFlags & clipFlags
// Skip all edges that are either completely outside at the top or at the bottom. // Skip all edges that are either completely outside at the top or at the bottom.
if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 { if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 {
if clipUnion&POLYGON_CLIP_RIGHT != 0 { if clipUnion&POLYGON_CLIP_RIGHT != 0 {
// Both clip to right, edge is a vertical line on the right side // Both clip to right, edge is a vertical line on the right side
if getVerticalEdge(prevY, y, clipBound[2], &edges[edgeCount], clipBound) { if getVerticalEdge(prevY, y, clipBound[2], &edges[edgeCount], clipBound) {
edgeCount++ edgeCount++
} }
} else if clipUnion&POLYGON_CLIP_LEFT != 0 { } else if clipUnion&POLYGON_CLIP_LEFT != 0 {
// Both clip to left, edge is a vertical line on the left side // Both clip to left, edge is a vertical line on the left side
if getVerticalEdge(prevY, y, clipBound[0], &edges[edgeCount], clipBound) { if getVerticalEdge(prevY, y, clipBound[0], &edges[edgeCount], clipBound) {
edgeCount++ edgeCount++
} }
} else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 { } else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 {
// No clipping in the horizontal direction // No clipping in the horizontal direction
if getEdge(prevX, prevY, x, y, &edges[edgeCount], clipBound) { if getEdge(prevX, prevY, x, y, &edges[edgeCount], clipBound) {
edgeCount++ edgeCount++
} }
} else { } else {
// Clips to left or right or both. // Clips to left or right or both.
if x < prevX { if x < prevX {
xleft, yleft = x, y xleft, yleft = x, y
@ -121,14 +121,14 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
slope := (yright - yleft) / (xright - xleft) slope := (yright - yleft) / (xright - xleft)
if clipSum&POLYGON_CLIP_RIGHT != 0 { if clipSum&POLYGON_CLIP_RIGHT != 0 {
// calculate new position for the right vertex // calculate new position for the right vertex
oldY = yright oldY = yright
maxX = clipBound[2] maxX = clipBound[2]
yright = yleft + (maxX-xleft)*slope yright = yleft + (maxX-xleft)*slope
xright = maxX xright = maxX
// add vertical edge for the overflowing part // add vertical edge for the overflowing part
if getVerticalEdge(yright, oldY, maxX, &edges[edgeCount], clipBound) { if getVerticalEdge(yright, oldY, maxX, &edges[edgeCount], clipBound) {
edges[edgeCount].Winding *= swapWinding edges[edgeCount].Winding *= swapWinding
edgeCount++ edgeCount++
@ -136,14 +136,14 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
} }
if clipSum&POLYGON_CLIP_LEFT != 0 { if clipSum&POLYGON_CLIP_LEFT != 0 {
// calculate new position for the left vertex // calculate new position for the left vertex
oldY = yleft oldY = yleft
minX = clipBound[0] minX = clipBound[0]
yleft = yleft + (minX-xleft)*slope yleft = yleft + (minX-xleft)*slope
xleft = minX xleft = minX
// add vertical edge for the overflowing part // add vertical edge for the overflowing part
if getVerticalEdge(oldY, yleft, minX, &edges[edgeCount], clipBound) { if getVerticalEdge(oldY, yleft, minX, &edges[edgeCount], clipBound) {
edges[edgeCount].Winding *= swapWinding edges[edgeCount].Winding *= swapWinding
edgeCount++ edgeCount++
@ -165,9 +165,9 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
return edgeCount return edgeCount
} }
//! Creates a polygon edge between two vectors. //! Creates a polygon edge between two vectors.
/*! Clips the edge vertically to the clip rectangle. Returns true for edges that /*! Clips the edge vertically to the clip rectangle. Returns true for edges that
* should be rendered, false for others. * should be rendered, false for others.
*/ */
func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bool { func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bool {
var startX, startY, endX, endY float64 var startX, startY, endX, endY float64
@ -187,13 +187,13 @@ func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bo
winding = -1 winding = -1
} }
// Essentially, firstLine is floor(startY + 1) and lastLine is floor(endY). // Essentially, firstLine is floor(startY + 1) and lastLine is floor(endY).
// These are refactored to integer casts in order to avoid function // These are refactored to integer casts in order to avoid function
// calls. The difference with integer cast is that numbers are always // calls. The difference with integer cast is that numbers are always
// rounded towards zero. Since values smaller than zero get clipped away, // rounded towards zero. Since values smaller than zero get clipped away,
// only coordinates between 0 and -1 require greater attention as they // only coordinates between 0 and -1 require greater attention as they
// also round to zero. The problems in this range can be avoided by // also round to zero. The problems in this range can be avoided by
// adding one to the values before conversion and subtracting after it. // adding one to the values before conversion and subtracting after it.
firstLine := int(startY + 1) firstLine := int(startY + 1)
lastLine := int(endY+1) - 1 lastLine := int(endY+1) - 1
@ -201,15 +201,15 @@ func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bo
minClip := int(clipBound[1]) minClip := int(clipBound[1])
maxClip := int(clipBound[3]) maxClip := int(clipBound[3])
// If start and end are on the same line, the edge doesn't cross // If start and end are on the same line, the edge doesn't cross
// any lines and thus can be ignored. // any lines and thus can be ignored.
// If the end is smaller than the first line, edge is out. // If the end is smaller than the first line, edge is out.
// If the start is larger than the last line, edge is out. // If the start is larger than the last line, edge is out.
if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip { if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip {
return false return false
} }
// Adjust the start based on the target. // Adjust the start based on the target.
if firstLine < minClip { if firstLine < minClip {
firstLine = minClip firstLine = minClip
} }
@ -226,9 +226,9 @@ func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bo
return true return true
} }
//! Creates a vertical polygon edge between two y values. //! Creates a vertical polygon edge between two y values.
/*! Clips the edge vertically to the clip rectangle. Returns true for edges that /*! Clips the edge vertically to the clip rectangle. Returns true for edges that
* should be rendered, false for others. * should be rendered, false for others.
*/ */
func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]float64) bool { func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]float64) bool {
var start, end float64 var start, end float64
@ -249,15 +249,15 @@ func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]fl
minClip := int(clipBound[1]) minClip := int(clipBound[1])
maxClip := int(clipBound[3]) maxClip := int(clipBound[3])
// If start and end are on the same line, the edge doesn't cross // If start and end are on the same line, the edge doesn't cross
// any lines and thus can be ignored. // any lines and thus can be ignored.
// If the end is smaller than the first line, edge is out. // If the end is smaller than the first line, edge is out.
// If the start is larger than the last line, edge is out. // If the start is larger than the last line, edge is out.
if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip { if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip {
return false return false
} }
// Adjust the start based on the clip rect. // Adjust the start based on the clip rect.
if firstLine < minClip { if firstLine < minClip {
firstLine = minClip firstLine = minClip
} }
@ -280,13 +280,13 @@ type VertexData struct {
Line int Line int
} }
//! Calculates the edges of the polygon with transformation and clipping to edges array. //! Calculates the edges of the polygon with transformation and clipping to edges array.
/*! Note that this may return upto three times the amount of edges that the polygon has vertices, /*! Note that this may return upto three times the amount of edges that the polygon has vertices,
* in the unlucky case where both left and right side get clipped for all edges. * in the unlucky case where both left and right side get clipped for all edges.
* \param edges the array for result edges. This should be able to contain 2*aVertexCount edges. * \param edges the array for result edges. This should be able to contain 2*aVertexCount edges.
* \param aTransformation the transformation matrix for the polygon. * \param aTransformation the transformation matrix for the polygon.
* \param aClipRectangle the clip rectangle. * \param aClipRectangle the clip rectangle.
* \return the amount of edges in the result. * \return the amount of edges in the result.
*/ */
func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound [4]float64) int { func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound [4]float64) int {
var n int var n int
@ -295,7 +295,7 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
k := n * 2 k := n * 2
vertexData[n].X = p[k]*tr[0] + p[k+1]*tr[2] + tr[4] vertexData[n].X = p[k]*tr[0] + p[k+1]*tr[2] + tr[4]
vertexData[n].Y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5] vertexData[n].Y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5]
// Calculate clip flags for all vertices. // Calculate clip flags for all vertices.
vertexData[n].ClipFlags = POLYGON_CLIP_NONE vertexData[n].ClipFlags = POLYGON_CLIP_NONE
if vertexData[n].X < clipBound[0] { if vertexData[n].X < clipBound[0] {
vertexData[n].ClipFlags |= POLYGON_CLIP_LEFT vertexData[n].ClipFlags |= POLYGON_CLIP_LEFT
@ -308,8 +308,8 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
vertexData[n].ClipFlags |= POLYGON_CLIP_BOTTOM vertexData[n].ClipFlags |= POLYGON_CLIP_BOTTOM
} }
// Calculate line of the vertex. If the vertex is clipped by top or bottom, the line // Calculate line of the vertex. If the vertex is clipped by top or bottom, the line
// is determined by the clip rectangle. // is determined by the clip rectangle.
if vertexData[n].ClipFlags&POLYGON_CLIP_TOP != 0 { if vertexData[n].ClipFlags&POLYGON_CLIP_TOP != 0 {
vertexData[n].Line = int(clipBound[1]) vertexData[n].Line = int(clipBound[1])
} else if vertexData[n].ClipFlags&POLYGON_CLIP_BOTTOM != 0 { } else if vertexData[n].ClipFlags&POLYGON_CLIP_BOTTOM != 0 {
@ -319,13 +319,13 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
} }
} }
// Copy the data from 0 to the last entry to make the data to loop. // Copy the data from 0 to the last entry to make the data to loop.
vertexData[len(vertexData)-1] = vertexData[0] vertexData[len(vertexData)-1] = vertexData[0]
// Transform the first vertex; store. // Transform the first vertex; store.
// Process mVertexCount - 1 times, next is n+1 // Process mVertexCount - 1 times, next is n+1
// copy the first vertex to // copy the first vertex to
// Process 1 time, next is n // Process 1 time, next is n
edgeCount := 0 edgeCount := 0
for n = 0; n < len(vertexData)-1; n++ { for n = 0; n < len(vertexData)-1; n++ {
@ -350,7 +350,7 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
lastLine := vertexData[endIndex].Line lastLine := vertexData[endIndex].Line
if clipUnion&POLYGON_CLIP_RIGHT != 0 { if clipUnion&POLYGON_CLIP_RIGHT != 0 {
// Both clip to right, edge is a vertical line on the right side // Both clip to right, edge is a vertical line on the right side
edges[edgeCount].FirstLine = firstLine edges[edgeCount].FirstLine = firstLine
edges[edgeCount].LastLine = lastLine edges[edgeCount].LastLine = lastLine
edges[edgeCount].Winding = winding edges[edgeCount].Winding = winding
@ -360,7 +360,7 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
edgeCount++ edgeCount++
} else if clipUnion&POLYGON_CLIP_LEFT != 0 { } else if clipUnion&POLYGON_CLIP_LEFT != 0 {
// Both clip to left, edge is a vertical line on the left side // Both clip to left, edge is a vertical line on the left side
edges[edgeCount].FirstLine = firstLine edges[edgeCount].FirstLine = firstLine
edges[edgeCount].LastLine = lastLine edges[edgeCount].LastLine = lastLine
edges[edgeCount].Winding = winding edges[edgeCount].Winding = winding
@ -370,15 +370,15 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
edgeCount++ edgeCount++
} else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 { } else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 {
// No clipping in the horizontal direction // No clipping in the horizontal direction
slope := (vertexData[endIndex].X - slope := (vertexData[endIndex].X -
vertexData[startIndex].X) / vertexData[startIndex].X) /
(vertexData[endIndex].Y - (vertexData[endIndex].Y -
vertexData[startIndex].Y) vertexData[startIndex].Y)
// If there is vertical clip (for the top) it will be processed here. The calculation // If there is vertical clip (for the top) it will be processed here. The calculation
// should be done for all non-clipping edges as well to determine the accurate position // should be done for all non-clipping edges as well to determine the accurate position
// where the edge crosses the first scanline. // where the edge crosses the first scanline.
startx := vertexData[startIndex].X + startx := vertexData[startIndex].X +
(float64(firstLine)-vertexData[startIndex].Y)*slope (float64(firstLine)-vertexData[startIndex].Y)*slope
@ -397,20 +397,20 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
edgeCount++ edgeCount++
} else { } else {
// Clips to left or right or both. // Clips to left or right or both.
slope := (vertexData[endIndex].X - slope := (vertexData[endIndex].X -
vertexData[startIndex].X) / vertexData[startIndex].X) /
(vertexData[endIndex].Y - (vertexData[endIndex].Y -
vertexData[startIndex].Y) vertexData[startIndex].Y)
// The edge may clip to both left and right. // The edge may clip to both left and right.
// The clip results in one or two new vertices, and one to three segments. // The clip results in one or two new vertices, and one to three segments.
// The rounding for scanlines may produce a result where any of the segments is // The rounding for scanlines may produce a result where any of the segments is
// ignored. // ignored.
// The start is always above the end. Calculate the clip positions to clipVertices. // The start is always above the end. Calculate the clip positions to clipVertices.
// It is possible that only one of the vertices exist. This will be detected from the // It is possible that only one of the vertices exist. This will be detected from the
// clip flags of the vertex later, so they are initialized here. // clip flags of the vertex later, so they are initialized here.
var clipVertices [2]VertexData var clipVertices [2]VertexData
if vertexData[startIndex].X < if vertexData[startIndex].X <
@ -428,14 +428,14 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
var p int var p int
for p = 0; p < 2; p++ { for p = 0; p < 2; p++ {
// Check if either of the vertices crosses the edge marked for the clip vertex // Check if either of the vertices crosses the edge marked for the clip vertex
if clipSum&clipVertices[p].ClipFlags != 0 { if clipSum&clipVertices[p].ClipFlags != 0 {
// The the vertex is required, calculate it. // The the vertex is required, calculate it.
clipVertices[p].Y = vertexData[startIndex].Y + clipVertices[p].Y = vertexData[startIndex].Y +
(clipVertices[p].X- (clipVertices[p].X-
vertexData[startIndex].X)/slope vertexData[startIndex].X)/slope
// If there is clipping in the vertical direction, the new vertex may be clipped. // If there is clipping in the vertical direction, the new vertex may be clipped.
if clipSum&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) != 0 { if clipSum&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) != 0 {
if clipVertices[p].Y < clipBound[1] { if clipVertices[p].Y < clipBound[1] {
clipVertices[p].ClipFlags = POLYGON_CLIP_TOP clipVertices[p].ClipFlags = POLYGON_CLIP_TOP
@ -454,28 +454,28 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
} }
} }
// Now there are three or four vertices, in the top-to-bottom order of start, clip0, clip1, // Now there are three or four vertices, in the top-to-bottom order of start, clip0, clip1,
// end. What kind of edges are required for connecting these can be determined from the // end. What kind of edges are required for connecting these can be determined from the
// clip flags. // clip flags.
// -if clip vertex has horizontal clip flags, it doesn't exist. No edge is generated. // -if clip vertex has horizontal clip flags, it doesn't exist. No edge is generated.
// -if start vertex or end vertex has horizontal clip flag, the edge to/from the clip vertex is vertical // -if start vertex or end vertex has horizontal clip flag, the edge to/from the clip vertex is vertical
// -if the line of two vertices is the same, the edge is not generated, since the edge doesn't // -if the line of two vertices is the same, the edge is not generated, since the edge doesn't
// cross any scanlines. // cross any scanlines.
// The alternative patterns are: // The alternative patterns are:
// start - clip0 - clip1 - end // start - clip0 - clip1 - end
// start - clip0 - end // start - clip0 - end
// start - clip1 - end // start - clip1 - end
var topClipIndex, bottomClipIndex int var topClipIndex, bottomClipIndex int
if (clipVertices[0].ClipFlags|clipVertices[1].ClipFlags)& if (clipVertices[0].ClipFlags|clipVertices[1].ClipFlags)&
(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) == 0 { (POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) == 0 {
// Both sides are clipped, the order is start-clip0-clip1-end // Both sides are clipped, the order is start-clip0-clip1-end
topClipIndex = 0 topClipIndex = 0
bottomClipIndex = 1 bottomClipIndex = 1
// Add the edge from clip0 to clip1 // Add the edge from clip0 to clip1
// Check that the line is different for the vertices. // Check that the line is different for the vertices.
if clipVertices[0].Line != clipVertices[1].Line { if clipVertices[0].Line != clipVertices[1].Line {
firstClipLine := clipVertices[0].Line + 1 firstClipLine := clipVertices[0].Line + 1
@ -498,8 +498,8 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
edgeCount++ edgeCount++
} }
} else { } else {
// Clip at either side, check which side. The clip flag is on for the vertex // Clip at either side, check which side. The clip flag is on for the vertex
// that doesn't exist, i.e. has not been clipped to be inside the rect. // that doesn't exist, i.e. has not been clipped to be inside the rect.
if clipVertices[0].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 { if clipVertices[0].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
topClipIndex = 1 topClipIndex = 1
bottomClipIndex = 1 bottomClipIndex = 1
@ -509,17 +509,17 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
} }
} }
// Generate the edges from start - clip top and clip bottom - end // Generate the edges from start - clip top and clip bottom - end
// Clip top and clip bottom may be the same vertex if there is only one // Clip top and clip bottom may be the same vertex if there is only one
// clipped vertex. // clipped vertex.
// Check that the line is different for the vertices. // Check that the line is different for the vertices.
if vertexData[startIndex].Line != clipVertices[topClipIndex].Line { if vertexData[startIndex].Line != clipVertices[topClipIndex].Line {
edges[edgeCount].FirstLine = firstLine edges[edgeCount].FirstLine = firstLine
edges[edgeCount].LastLine = clipVertices[topClipIndex].Line edges[edgeCount].LastLine = clipVertices[topClipIndex].Line
edges[edgeCount].Winding = winding edges[edgeCount].Winding = winding
// If startIndex is clipped, the edge is a vertical one. // If startIndex is clipped, the edge is a vertical one.
if vertexData[startIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 { if vertexData[startIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
edges[edgeCount].X = Fix(clipVertices[topClipIndex].X * FIXED_FLOAT_COEF) edges[edgeCount].X = Fix(clipVertices[topClipIndex].X * FIXED_FLOAT_COEF)
edges[edgeCount].Slope = 0 edges[edgeCount].Slope = 0
@ -542,7 +542,7 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
edgeCount++ edgeCount++
} }
// Check that the line is different for the vertices. // Check that the line is different for the vertices.
if clipVertices[bottomClipIndex].Line != vertexData[endIndex].Line { if clipVertices[bottomClipIndex].Line != vertexData[endIndex].Line {
firstClipLine := clipVertices[bottomClipIndex].Line + 1 firstClipLine := clipVertices[bottomClipIndex].Line + 1
@ -550,7 +550,7 @@ func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound
edges[edgeCount].LastLine = lastLine edges[edgeCount].LastLine = lastLine
edges[edgeCount].Winding = winding edges[edgeCount].Winding = winding
// If endIndex is clipped, the edge is a vertical one. // If endIndex is clipped, the edge is a vertical one.
if vertexData[endIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 { if vertexData[endIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
edges[edgeCount].X = Fix(clipVertices[bottomClipIndex].X * FIXED_FLOAT_COEF) edges[edgeCount].X = Fix(clipVertices[bottomClipIndex].X * FIXED_FLOAT_COEF)
edges[edgeCount].Slope = 0 edges[edgeCount].Slope = 0

View File

@ -2,14 +2,15 @@ package raster
import ( import (
"bufio" "bufio"
"code.google.com/p/draw2d/draw2d/curve"
"code.google.com/p/freetype-go/freetype/raster"
"image" "image"
"image/color" "image/color"
"image/png" "image/png"
"log" "log"
"os" "os"
"testing" "testing"
"code.google.com/p/freetype-go/freetype/raster"
"github.com/llgcode/draw2d/draw2d/curve"
) )
var flattening_threshold float64 = 0.5 var flattening_threshold float64 = 0.5
@ -104,7 +105,7 @@ func TestRasterizer(t *testing.T) {
color := color.RGBA{0, 0, 0, 0xff} color := color.RGBA{0, 0, 0, 0xff}
tr := [6]float64{1, 0, 0, 1, 0, 0} tr := [6]float64{1, 0, 0, 1, 0, 0}
r := NewRasterizer8BitsSample(200, 200) r := NewRasterizer8BitsSample(200, 200)
//PolylineBresenham(img, image.Black, poly...) //PolylineBresenham(img, image.Black, poly...)
r.RenderEvenOdd(img, &color, &poly, tr) r.RenderEvenOdd(img, &color, &poly, tr)
savepng("_testRasterizer.png", img) savepng("_testRasterizer.png", img)
@ -120,7 +121,7 @@ func TestRasterizerNonZeroWinding(t *testing.T) {
color := color.RGBA{0, 0, 0, 0xff} color := color.RGBA{0, 0, 0, 0xff}
tr := [6]float64{1, 0, 0, 1, 0, 0} tr := [6]float64{1, 0, 0, 1, 0, 0}
r := NewRasterizer8BitsSample(200, 200) r := NewRasterizer8BitsSample(200, 200)
//PolylineBresenham(img, image.Black, poly...) //PolylineBresenham(img, image.Black, poly...)
r.RenderNonZeroWinding(img, &color, &poly, tr) r.RenderNonZeroWinding(img, &color, &poly, tr)
savepng("_testRasterizerNonZeroWinding.png", img) savepng("_testRasterizerNonZeroWinding.png", img)

View File

@ -4,9 +4,10 @@
package draw2d package draw2d
import ( import (
"code.google.com/p/freetype-go/freetype/truetype"
"image" "image"
"image/color" "image/color"
"code.google.com/p/freetype-go/freetype/truetype"
) )
type StackGraphicContext struct { type StackGraphicContext struct {

View File

@ -59,7 +59,7 @@ func (l *LineStroker) NextCommand(command VertexCommand) {
l.Next.Vertex(l.vertices[0], l.vertices[1]) l.Next.Vertex(l.vertices[0], l.vertices[1])
} }
l.Next.NextCommand(VertexStopCommand) l.Next.NextCommand(VertexStopCommand)
// reinit vertices // reinit vertices
l.vertices = l.vertices[0:0] l.vertices = l.vertices[0:0]
l.rewind = l.rewind[0:0] l.rewind = l.rewind[0:0]
l.x, l.y, l.nx, l.ny = 0, 0, 0, 0 l.x, l.y, l.nx, l.ny = 0, 0, 0, 0

View File

@ -4,8 +4,9 @@
package draw2d package draw2d
import ( import (
"code.google.com/p/freetype-go/freetype/raster"
"math" "math"
"code.google.com/p/freetype-go/freetype/raster"
) )
type MatrixTransform [6]float64 type MatrixTransform [6]float64

View File

@ -1,12 +1,13 @@
package draw2dgl package draw2dgl
import ( import (
"code.google.com/p/draw2d/draw2d"
"code.google.com/p/freetype-go/freetype/raster"
"gl" "gl"
"image" "image"
"image/color" "image/color"
"image/draw" "image/draw"
"code.google.com/p/freetype-go/freetype/raster"
"github.com/llgcode/draw2d/draw2d"
//"log" //"log"
) )

View File

@ -1,64 +1,64 @@
package main package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"log" "image"
"os" "image/draw"
"image/png"
"code.google.com/p/draw2d/draw2d" "log"
"image" "math"
"image/draw" "os"
"image/png"
"math" "github.com/llgcode/draw2d/draw2d"
) )
func saveToPngFile(filePath string, m image.Image) { func saveToPngFile(filePath string, m image.Image) {
f, err := os.Create(filePath) f, err := os.Create(filePath)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
os.Exit(1) os.Exit(1)
} }
defer f.Close() defer f.Close()
b := bufio.NewWriter(f) b := bufio.NewWriter(f)
err = png.Encode(b, m) err = png.Encode(b, m)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
os.Exit(1) os.Exit(1)
} }
err = b.Flush() err = b.Flush()
if err != nil { if err != nil {
log.Println(err) log.Println(err)
os.Exit(1) os.Exit(1)
} }
fmt.Printf("Wrote %s OK.\n", filePath) fmt.Printf("Wrote %s OK.\n", filePath)
} }
func main() { func main() {
file, err := os.Open("android.png") file, err := os.Open("android.png")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer file.Close() defer file.Close()
a, _, err := image.Decode(file) a, _, err := image.Decode(file)
//load go icon image //load go icon image
file2, err := os.Open("go.png") file2, err := os.Open("go.png")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer file2.Close() defer file2.Close()
g, _, err := image.Decode(file2) g, _, err := image.Decode(file2)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
ar := a.Bounds() ar := a.Bounds()
w, h, x := ar.Dx(), ar.Dy(), 30.0 w, h, x := ar.Dx(), ar.Dy(), 30.0
i := image.NewRGBA(image.Rect(0, 0, w, h)) i := image.NewRGBA(image.Rect(0, 0, w, h))
draw.Draw(i, ar, a, ar.Min, draw.Src) draw.Draw(i, ar, a, ar.Min, draw.Src)
tr := draw2d.NewRotationMatrix(x*(math.Pi / 180.0)) tr := draw2d.NewRotationMatrix(x * (math.Pi / 180.0))
draw2d.DrawImage(g, i, tr, draw.Over, draw2d.LinearFilter) draw2d.DrawImage(g, i, tr, draw.Over, draw2d.LinearFilter)
saveToPngFile("Test2.png", i) saveToPngFile("Test2.png", i)
} }

View File

@ -4,11 +4,12 @@
package postscript package postscript
import ( import (
"code.google.com/p/draw2d/draw2d"
"io" "io"
"log" "log"
"os" "os"
"strconv" "strconv"
"github.com/llgcode/draw2d/draw2d"
) )
type Interpreter struct { type Interpreter struct {
@ -44,7 +45,7 @@ func NewDictionary(prealloc int) Dictionary {
return make(Dictionary, prealloc) return make(Dictionary, prealloc)
} }
func (interpreter *Interpreter) SetGraphicContext(gc draw2d.GraphicContext) { func (interpreter *Interpreter) SetGraphicContext(gc draw2d.GraphicContext) {
interpreter.gc = gc interpreter.gc = gc
} }

View File

@ -3,8 +3,6 @@
package postscript package postscript
import ()
//int array array -> Create array of length int //int array array -> Create array of length int
func array(interpreter *Interpreter) { func array(interpreter *Interpreter) {
interpreter.Push(make([]Value, interpreter.PopInt())) interpreter.Push(make([]Value, interpreter.PopInt()))
@ -60,7 +58,7 @@ func astore(interpreter *Interpreter) {
} }
} }
//array aload any0 … any-1 array //array aload any0 … any-1 array
//Push all elements of array on stack //Push all elements of array on stack
func aload(interpreter *Interpreter) { func aload(interpreter *Interpreter) {
array := interpreter.Pop().([]Value) array := interpreter.Pop().([]Value)

View File

@ -5,10 +5,11 @@
package postscript package postscript
import ( import (
"code.google.com/p/draw2d/draw2d"
"image/color" "image/color"
"log" "log"
"math" "math"
"github.com/llgcode/draw2d/draw2d"
) )
//Path Construction Operators //Path Construction Operators
@ -179,9 +180,9 @@ func setcmybcolor(interpreter *Interpreter) {
magenta := interpreter.PopFloat() magenta := interpreter.PopFloat()
cyan := interpreter.PopFloat() cyan := interpreter.PopFloat()
/* cyan = cyan / 255.0; /* cyan = cyan / 255.0;
magenta = magenta / 255.0; magenta = magenta / 255.0;
yellow = yellow / 255.0; yellow = yellow / 255.0;
black = black / 255.0; */ black = black / 255.0; */
red := cyan*(1.0-black) + black red := cyan*(1.0-black) + black
@ -198,7 +199,7 @@ func setcmybcolor(interpreter *Interpreter) {
} }
func setdash(interpreter *Interpreter) { func setdash(interpreter *Interpreter) {
interpreter.PopInt() // offset interpreter.PopInt() // offset
interpreter.PopArray() // dash interpreter.PopArray() // dash
//log.Printf("setdash not yet implemented dash: %v, offset: %d \n", dash, offset) //log.Printf("setdash not yet implemented dash: %v, offset: %d \n", dash, offset)
} }

View File

@ -4,10 +4,6 @@
// Miscellaneous Operators // Miscellaneous Operators
package postscript package postscript
import (
//"log"
)
//proc bind proc Replace operator names in proc with operators; perform idiom recognition //proc bind proc Replace operator names in proc with operators; perform idiom recognition
func bind(interpreter *Interpreter) { func bind(interpreter *Interpreter) {
pdef := interpreter.PopProcedureDefinition() pdef := interpreter.PopProcedureDefinition()

View File

@ -7,109 +7,109 @@
package wingui package wingui
import ( import (
"syscall" "syscall"
"unsafe" "unsafe"
) )
type Wndclassex struct { type Wndclassex struct {
Size uint32 Size uint32
Style uint32 Style uint32
WndProc uintptr WndProc uintptr
ClsExtra int32 ClsExtra int32
WndExtra int32 WndExtra int32
Instance syscall.Handle Instance syscall.Handle
Icon syscall.Handle Icon syscall.Handle
Cursor syscall.Handle Cursor syscall.Handle
Background syscall.Handle Background syscall.Handle
MenuName *uint16 MenuName *uint16
ClassName *uint16 ClassName *uint16
IconSm syscall.Handle IconSm syscall.Handle
} }
type Point struct { type Point struct {
X uintptr X uintptr
Y uintptr Y uintptr
} }
type Msg struct { type Msg struct {
Hwnd syscall.Handle Hwnd syscall.Handle
Message uint32 Message uint32
Wparam uintptr Wparam uintptr
Lparam uintptr Lparam uintptr
Time uint32 Time uint32
Pt Point Pt Point
} }
const ( const (
// Window styles // Window styles
WS_OVERLAPPED = 0 WS_OVERLAPPED = 0
WS_POPUP = 0x80000000 WS_POPUP = 0x80000000
WS_CHILD = 0x40000000 WS_CHILD = 0x40000000
WS_MINIMIZE = 0x20000000 WS_MINIMIZE = 0x20000000
WS_VISIBLE = 0x10000000 WS_VISIBLE = 0x10000000
WS_DISABLED = 0x8000000 WS_DISABLED = 0x8000000
WS_CLIPSIBLINGS = 0x4000000 WS_CLIPSIBLINGS = 0x4000000
WS_CLIPCHILDREN = 0x2000000 WS_CLIPCHILDREN = 0x2000000
WS_MAXIMIZE = 0x1000000 WS_MAXIMIZE = 0x1000000
WS_CAPTION = WS_BORDER | WS_DLGFRAME WS_CAPTION = WS_BORDER | WS_DLGFRAME
WS_BORDER = 0x800000 WS_BORDER = 0x800000
WS_DLGFRAME = 0x400000 WS_DLGFRAME = 0x400000
WS_VSCROLL = 0x200000 WS_VSCROLL = 0x200000
WS_HSCROLL = 0x100000 WS_HSCROLL = 0x100000
WS_SYSMENU = 0x80000 WS_SYSMENU = 0x80000
WS_THICKFRAME = 0x40000 WS_THICKFRAME = 0x40000
WS_GROUP = 0x20000 WS_GROUP = 0x20000
WS_TABSTOP = 0x10000 WS_TABSTOP = 0x10000
WS_MINIMIZEBOX = 0x20000 WS_MINIMIZEBOX = 0x20000
WS_MAXIMIZEBOX = 0x10000 WS_MAXIMIZEBOX = 0x10000
WS_TILED = WS_OVERLAPPED WS_TILED = WS_OVERLAPPED
WS_ICONIC = WS_MINIMIZE WS_ICONIC = WS_MINIMIZE
WS_SIZEBOX = WS_THICKFRAME WS_SIZEBOX = WS_THICKFRAME
// Common Window Styles // Common Window Styles
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU
WS_CHILDWINDOW = WS_CHILD WS_CHILDWINDOW = WS_CHILD
WS_EX_CLIENTEDGE = 0x200 WS_EX_CLIENTEDGE = 0x200
// Some windows messages // Some windows messages
WM_CREATE = 1 WM_CREATE = 1
WM_DESTROY = 2 WM_DESTROY = 2
WM_CLOSE = 16 WM_CLOSE = 16
WM_COMMAND = 273 WM_COMMAND = 273
// Some button control styles // Some button control styles
BS_DEFPUSHBUTTON = 1 BS_DEFPUSHBUTTON = 1
// Some color constants // Some color constants
COLOR_WINDOW = 5 COLOR_WINDOW = 5
COLOR_BTNFACE = 15 COLOR_BTNFACE = 15
// Default window position // Default window position
CW_USEDEFAULT = 0x80000000 - 0x100000000 CW_USEDEFAULT = 0x80000000 - 0x100000000
// Show window default style // Show window default style
SW_SHOWDEFAULT = 10 SW_SHOWDEFAULT = 10
) )
var ( var (
// Some globally known cursors // Some globally known cursors
IDC_ARROW = MakeIntResource(32512) IDC_ARROW = MakeIntResource(32512)
IDC_IBEAM = MakeIntResource(32513) IDC_IBEAM = MakeIntResource(32513)
IDC_WAIT = MakeIntResource(32514) IDC_WAIT = MakeIntResource(32514)
IDC_CROSS = MakeIntResource(32515) IDC_CROSS = MakeIntResource(32515)
// Some globally known icons // Some globally known icons
IDI_APPLICATION = MakeIntResource(32512) IDI_APPLICATION = MakeIntResource(32512)
IDI_HAND = MakeIntResource(32513) IDI_HAND = MakeIntResource(32513)
IDI_QUESTION = MakeIntResource(32514) IDI_QUESTION = MakeIntResource(32514)
IDI_EXCLAMATION = MakeIntResource(32515) IDI_EXCLAMATION = MakeIntResource(32515)
IDI_ASTERISK = MakeIntResource(32516) IDI_ASTERISK = MakeIntResource(32516)
IDI_WINLOGO = MakeIntResource(32517) IDI_WINLOGO = MakeIntResource(32517)
IDI_WARNING = IDI_EXCLAMATION IDI_WARNING = IDI_EXCLAMATION
IDI_ERROR = IDI_HAND IDI_ERROR = IDI_HAND
IDI_INFORMATION = IDI_ASTERISK IDI_INFORMATION = IDI_ASTERISK
) )
//sys GetModuleHandle(modname *uint16) (handle syscall.Handle, err error) = GetModuleHandleW //sys GetModuleHandle(modname *uint16) (handle syscall.Handle, err error) = GetModuleHandleW
@ -130,5 +130,5 @@ var (
//sys PostMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (err error) = user32.PostMessageW //sys PostMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (err error) = user32.PostMessageW
func MakeIntResource(id uint16) *uint16 { func MakeIntResource(id uint16) *uint16 {
return (*uint16)(unsafe.Pointer(uintptr(id))) return (*uint16)(unsafe.Pointer(uintptr(id)))
} }

View File

@ -8,27 +8,27 @@ import (
const ( const (
WM_PAINT = 15 WM_PAINT = 15
BI_RGB = 0 BI_RGB = 0
BI_BITFIELDS = 3 BI_BITFIELDS = 3
DIB_PAL_COLORS = 1 DIB_PAL_COLORS = 1
DIB_RGB_COLORS = 0 DIB_RGB_COLORS = 0
BLACKNESS = 0x42 BLACKNESS = 0x42
DSTINVERT = 0x550009 DSTINVERT = 0x550009
MERGECOPY = 0xC000CA MERGECOPY = 0xC000CA
MERGEPAINT = 0xBB0226 MERGEPAINT = 0xBB0226
NOTSRCCOPY = 0x330008 NOTSRCCOPY = 0x330008
NOTSRCERASE = 0x1100A6 NOTSRCERASE = 0x1100A6
PATCOPY = 0xF00021 PATCOPY = 0xF00021
PATINVERT = 0x5A0049 PATINVERT = 0x5A0049
PATPAINT = 0xFB0A09 PATPAINT = 0xFB0A09
SRCAND = 0x8800C6 SRCAND = 0x8800C6
SRCCOPY = 0xCC0020 SRCCOPY = 0xCC0020
SRCERASE = 0x440328 SRCERASE = 0x440328
SRCINVERT = 0x660046 SRCINVERT = 0x660046
SRCPAINT = 0xEE0086 SRCPAINT = 0xEE0086
WHITENESS = 0xFF0062 WHITENESS = 0xFF0062
) )
type RECT struct { type RECT struct {
@ -120,7 +120,7 @@ func SelectObject(hdc syscall.Handle, hgdiobj syscall.Handle) syscall.Handle {
return syscall.Handle(r0) return syscall.Handle(r0)
} }
func BeginPaint(hwnd syscall.Handle, ps *PAINTSTRUCT) (hdc syscall.Handle){ func BeginPaint(hwnd syscall.Handle, ps *PAINTSTRUCT) (hdc syscall.Handle) {
r0, _, _ := syscall.Syscall(procBeginPaint.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(ps)), 0) r0, _, _ := syscall.Syscall(procBeginPaint.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(ps)), 0)
hdc = syscall.Handle(r0) hdc = syscall.Handle(r0)
return return

View File

@ -1,151 +1,152 @@
package main package main
import ( import (
"fmt" "fmt"
"os" "os"
"syscall" "syscall"
"unsafe" "unsafe"
. "code.google.com/p/draw2d/wingui"
) . "github.com/llgcode/draw2d/wingui"
)
// some help functions
// some help functions
func abortf(format string, a ...interface{}) {
fmt.Fprintf(os.Stdout, format, a...) func abortf(format string, a ...interface{}) {
os.Exit(1) fmt.Fprintf(os.Stdout, format, a...)
} os.Exit(1)
}
func abortErrNo(funcname string, err error) {
errno, _ := err.(syscall.Errno) func abortErrNo(funcname string, err error) {
abortf("%s failed: %d %s\n", funcname, uint32(errno), err) errno, _ := err.(syscall.Errno)
} abortf("%s failed: %d %s\n", funcname, uint32(errno), err)
}
// global vars
// global vars
var (
mh syscall.Handle var (
bh syscall.Handle mh syscall.Handle
) bh syscall.Handle
)
// WinProc called by windows to notify us of all windows events we might be interested in.
func WndProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) (rc uintptr) { // WinProc called by windows to notify us of all windows events we might be interested in.
_ = make([]int, 100000) func WndProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) (rc uintptr) {
switch msg { _ = make([]int, 100000)
case WM_CREATE: switch msg {
var e error case WM_CREATE:
// CreateWindowEx var e error
bh, e = CreateWindowEx( // CreateWindowEx
0, bh, e = CreateWindowEx(
syscall.StringToUTF16Ptr("button"), 0,
syscall.StringToUTF16Ptr("Quit"), syscall.StringToUTF16Ptr("button"),
WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, syscall.StringToUTF16Ptr("Quit"),
75, 70, 140, 25, WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
hwnd, 1, mh, 0) 75, 70, 140, 25,
if e != nil { hwnd, 1, mh, 0)
abortErrNo("CreateWindowEx", e) if e != nil {
} abortErrNo("CreateWindowEx", e)
fmt.Printf("button handle is %x\n", bh) }
rc = DefWindowProc(hwnd, msg, wparam, lparam) fmt.Printf("button handle is %x\n", bh)
case WM_COMMAND: rc = DefWindowProc(hwnd, msg, wparam, lparam)
switch syscall.Handle(lparam) { case WM_COMMAND:
case bh: switch syscall.Handle(lparam) {
e := PostMessage(hwnd, WM_CLOSE, 0, 0) case bh:
if e != nil { e := PostMessage(hwnd, WM_CLOSE, 0, 0)
abortErrNo("PostMessage", e) if e != nil {
} abortErrNo("PostMessage", e)
default: }
rc = DefWindowProc(hwnd, msg, wparam, lparam) default:
} rc = DefWindowProc(hwnd, msg, wparam, lparam)
case WM_CLOSE: }
DestroyWindow(hwnd) case WM_CLOSE:
case WM_DESTROY: DestroyWindow(hwnd)
PostQuitMessage(0) case WM_DESTROY:
default: PostQuitMessage(0)
rc = DefWindowProc(hwnd, msg, wparam, lparam) default:
} rc = DefWindowProc(hwnd, msg, wparam, lparam)
//fmt.Printf("WndProc(0x%08x, %d, 0x%08x, 0x%08x) (%d)\n", hwnd, msg, wparam, lparam, rc) }
return //fmt.Printf("WndProc(0x%08x, %d, 0x%08x, 0x%08x) (%d)\n", hwnd, msg, wparam, lparam, rc)
} return
}
func rungui() int {
var e error func rungui() int {
var e error
// GetModuleHandle
mh, e = GetModuleHandle(nil) // GetModuleHandle
if e != nil { mh, e = GetModuleHandle(nil)
abortErrNo("GetModuleHandle", e) if e != nil {
} abortErrNo("GetModuleHandle", e)
}
// Get icon we're going to use.
myicon, e := LoadIcon(0, IDI_APPLICATION) // Get icon we're going to use.
if e != nil { myicon, e := LoadIcon(0, IDI_APPLICATION)
abortErrNo("LoadIcon", e) if e != nil {
} abortErrNo("LoadIcon", e)
}
// Get cursor we're going to use.
mycursor, e := LoadCursor(0, IDC_ARROW) // Get cursor we're going to use.
if e != nil { mycursor, e := LoadCursor(0, IDC_ARROW)
abortErrNo("LoadCursor", e) if e != nil {
} abortErrNo("LoadCursor", e)
}
// Create callback
wproc := syscall.NewCallback(WndProc) // Create callback
wproc := syscall.NewCallback(WndProc)
// RegisterClassEx
wcname := syscall.StringToUTF16Ptr("myWindowClass") // RegisterClassEx
var wc Wndclassex wcname := syscall.StringToUTF16Ptr("myWindowClass")
wc.Size = uint32(unsafe.Sizeof(wc)) var wc Wndclassex
wc.WndProc = wproc wc.Size = uint32(unsafe.Sizeof(wc))
wc.Instance = mh wc.WndProc = wproc
wc.Icon = myicon wc.Instance = mh
wc.Cursor = mycursor wc.Icon = myicon
wc.Background = COLOR_BTNFACE + 1 wc.Cursor = mycursor
wc.MenuName = nil wc.Background = COLOR_BTNFACE + 1
wc.ClassName = wcname wc.MenuName = nil
wc.IconSm = myicon wc.ClassName = wcname
if _, e := RegisterClassEx(&wc); e != nil { wc.IconSm = myicon
abortErrNo("RegisterClassEx", e) if _, e := RegisterClassEx(&wc); e != nil {
} abortErrNo("RegisterClassEx", e)
}
// CreateWindowEx
wh, e := CreateWindowEx( // CreateWindowEx
WS_EX_CLIENTEDGE, wh, e := CreateWindowEx(
wcname, WS_EX_CLIENTEDGE,
syscall.StringToUTF16Ptr("My window"), wcname,
WS_OVERLAPPEDWINDOW, syscall.StringToUTF16Ptr("My window"),
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, WS_OVERLAPPEDWINDOW,
0, 0, mh, 0) CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
if e != nil { 0, 0, mh, 0)
abortErrNo("CreateWindowEx", e) if e != nil {
} abortErrNo("CreateWindowEx", e)
fmt.Printf("main window handle is %x\n", wh) }
fmt.Printf("main window handle is %x\n", wh)
// ShowWindow
ShowWindow(wh, SW_SHOWDEFAULT) // ShowWindow
ShowWindow(wh, SW_SHOWDEFAULT)
// UpdateWindow
if e := UpdateWindow(wh); e != nil { // UpdateWindow
abortErrNo("UpdateWindow", e) if e := UpdateWindow(wh); e != nil {
} abortErrNo("UpdateWindow", e)
}
// Process all windows messages until WM_QUIT.
var m Msg // Process all windows messages until WM_QUIT.
for { var m Msg
r, e := GetMessage(&m, 0, 0, 0) for {
if e != nil { r, e := GetMessage(&m, 0, 0, 0)
abortErrNo("GetMessage", e) if e != nil {
} abortErrNo("GetMessage", e)
if r == 0 { }
// WM_QUIT received -> get out if r == 0 {
break // WM_QUIT received -> get out
} break
TranslateMessage(&m) }
DispatchMessage(&m) TranslateMessage(&m)
} DispatchMessage(&m)
return int(m.Wparam) }
} return int(m.Wparam)
}
func main() {
rc := rungui() func main() {
os.Exit(rc) rc := rungui()
} os.Exit(rc)
}

View File

@ -5,18 +5,19 @@
package main package main
import ( import (
"code.google.com/p/draw2d/draw2d"
"code.google.com/p/draw2d/wingui"
"code.google.com/p/draw2d/postscript"
"fmt" "fmt"
"image" "image"
"io/ioutil"
"image/color" "image/color"
"strings" "io/ioutil"
"os" "os"
"strings"
"syscall" "syscall"
"time" "time"
"unsafe" "unsafe"
"github.com/llgcode/draw2d/draw2d"
"github.com/llgcode/draw2d/postscript"
"github.com/llgcode/draw2d/wingui"
) )
// some help functions // some help functions
@ -56,7 +57,7 @@ func TestDrawCubicCurve(gc draw2d.GraphicContext) {
gc.Stroke() gc.Stroke()
} }
func DrawTiger(gc draw2d.GraphicContext){ func DrawTiger(gc draw2d.GraphicContext) {
if postscriptContent == "" { if postscriptContent == "" {
src, err := os.OpenFile("../../resource/postscript/tiger.ps", 0, 0) src, err := os.OpenFile("../../resource/postscript/tiger.ps", 0, 0)
if err != nil { if err != nil {
@ -73,12 +74,12 @@ func DrawTiger(gc draw2d.GraphicContext){
} }
var ( var (
mh syscall.Handle mh syscall.Handle
hdcWndBuffer syscall.Handle hdcWndBuffer syscall.Handle
wndBufferHeader syscall.Handle wndBufferHeader syscall.Handle
wndBuffer wingui.BITMAP wndBuffer wingui.BITMAP
ppvBits *uint8 ppvBits *uint8
backBuffer *image.RGBA backBuffer *image.RGBA
postscriptContent string postscriptContent string
) )
@ -119,7 +120,7 @@ func WndProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) (rc uintpt
pixel := (*[600 * 800 * 4]uint8)(unsafe.Pointer(ppvBits)) pixel := (*[600 * 800 * 4]uint8)(unsafe.Pointer(ppvBits))
pixelSlice := pixel[:] pixelSlice := pixel[:]
backBuffer = &image.RGBA{pixelSlice, 4*600, image.Rect(0, 0, 600, 800)} backBuffer = &image.RGBA{pixelSlice, 4 * 600, image.Rect(0, 0, 600, 800)}
fmt.Println("Create windows") fmt.Println("Create windows")
rc = wingui.DefWindowProc(hwnd, msg, wparam, lparam) rc = wingui.DefWindowProc(hwnd, msg, wparam, lparam)
case wingui.WM_COMMAND: case wingui.WM_COMMAND:
@ -134,7 +135,7 @@ func WndProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) (rc uintpt
gc := draw2d.NewGraphicContext(backBuffer) gc := draw2d.NewGraphicContext(backBuffer)
/*gc.SetFillColor(color.RGBA{0xFF, 0xFF, 0xFF, 0xFF}) /*gc.SetFillColor(color.RGBA{0xFF, 0xFF, 0xFF, 0xFF})
gc.Clear()*/ gc.Clear()*/
for i := 0; i < len(backBuffer.Pix); i+=1 { for i := 0; i < len(backBuffer.Pix); i += 1 {
backBuffer.Pix[i] = 0xff backBuffer.Pix[i] = 0xff
} }
gc.Save() gc.Save()
@ -143,7 +144,7 @@ func WndProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) (rc uintpt
gc.Restore() gc.Restore()
// back buf in // back buf in
var tmp uint8 var tmp uint8
for i := 0; i < len(backBuffer.Pix); i+=4 { for i := 0; i < len(backBuffer.Pix); i += 4 {
tmp = backBuffer.Pix[i] tmp = backBuffer.Pix[i]
backBuffer.Pix[i] = backBuffer.Pix[i+2] backBuffer.Pix[i] = backBuffer.Pix[i+2]
backBuffer.Pix[i+2] = tmp backBuffer.Pix[i+2] = tmp

View File

@ -8,185 +8,185 @@ import "unsafe"
import "syscall" import "syscall"
var ( var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll") modkernel32 = syscall.NewLazyDLL("kernel32.dll")
moduser32 = syscall.NewLazyDLL("user32.dll") moduser32 = syscall.NewLazyDLL("user32.dll")
procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW") procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
procRegisterClassExW = moduser32.NewProc("RegisterClassExW") procRegisterClassExW = moduser32.NewProc("RegisterClassExW")
procCreateWindowExW = moduser32.NewProc("CreateWindowExW") procCreateWindowExW = moduser32.NewProc("CreateWindowExW")
procDefWindowProcW = moduser32.NewProc("DefWindowProcW") procDefWindowProcW = moduser32.NewProc("DefWindowProcW")
procDestroyWindow = moduser32.NewProc("DestroyWindow") procDestroyWindow = moduser32.NewProc("DestroyWindow")
procPostQuitMessage = moduser32.NewProc("PostQuitMessage") procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
procShowWindow = moduser32.NewProc("ShowWindow") procShowWindow = moduser32.NewProc("ShowWindow")
procUpdateWindow = moduser32.NewProc("UpdateWindow") procUpdateWindow = moduser32.NewProc("UpdateWindow")
procGetMessageW = moduser32.NewProc("GetMessageW") procGetMessageW = moduser32.NewProc("GetMessageW")
procTranslateMessage = moduser32.NewProc("TranslateMessage") procTranslateMessage = moduser32.NewProc("TranslateMessage")
procDispatchMessageW = moduser32.NewProc("DispatchMessageW") procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
procLoadIconW = moduser32.NewProc("LoadIconW") procLoadIconW = moduser32.NewProc("LoadIconW")
procLoadCursorW = moduser32.NewProc("LoadCursorW") procLoadCursorW = moduser32.NewProc("LoadCursorW")
procSetCursor = moduser32.NewProc("SetCursor") procSetCursor = moduser32.NewProc("SetCursor")
procSendMessageW = moduser32.NewProc("SendMessageW") procSendMessageW = moduser32.NewProc("SendMessageW")
procPostMessageW = moduser32.NewProc("PostMessageW") procPostMessageW = moduser32.NewProc("PostMessageW")
) )
func GetModuleHandle(modname *uint16) (handle syscall.Handle, err error) { func GetModuleHandle(modname *uint16) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0) r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0)
handle = syscall.Handle(r0) handle = syscall.Handle(r0)
if handle == 0 { if handle == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func RegisterClassEx(wndclass *Wndclassex) (atom uint16, err error) { func RegisterClassEx(wndclass *Wndclassex) (atom uint16, err error) {
r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0) r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
atom = uint16(r0) atom = uint16(r0)
if atom == 0 { if atom == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent syscall.Handle, menu syscall.Handle, instance syscall.Handle, param uintptr) (hwnd syscall.Handle, err error) { func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent syscall.Handle, menu syscall.Handle, instance syscall.Handle, param uintptr) (hwnd syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param)) r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param))
hwnd = syscall.Handle(r0) hwnd = syscall.Handle(r0)
if hwnd == 0 { if hwnd == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func DefWindowProc(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) { func DefWindowProc(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) {
r0, _, _ := syscall.Syscall6(procDefWindowProcW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) r0, _, _ := syscall.Syscall6(procDefWindowProcW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
lresult = uintptr(r0) lresult = uintptr(r0)
return return
} }
func DestroyWindow(hwnd syscall.Handle) (err error) { func DestroyWindow(hwnd syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0) r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0)
if int(r1) == 0 { if int(r1) == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func PostQuitMessage(exitcode int32) { func PostQuitMessage(exitcode int32) {
syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0) syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0)
return return
} }
func ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) { func ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) {
r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0) r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0)
wasvisible = bool(r0 != 0) wasvisible = bool(r0 != 0)
return return
} }
func UpdateWindow(hwnd syscall.Handle) (err error) { func UpdateWindow(hwnd syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall(procUpdateWindow.Addr(), 1, uintptr(hwnd), 0, 0) r1, _, e1 := syscall.Syscall(procUpdateWindow.Addr(), 1, uintptr(hwnd), 0, 0)
if int(r1) == 0 { if int(r1) == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func GetMessage(msg *Msg, hwnd syscall.Handle, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) { func GetMessage(msg *Msg, hwnd syscall.Handle, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) {
r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0) r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0)
ret = int32(r0) ret = int32(r0)
if ret == -1 { if ret == -1 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func TranslateMessage(msg *Msg) (done bool) { func TranslateMessage(msg *Msg) (done bool) {
r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0) r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
done = bool(r0 != 0) done = bool(r0 != 0)
return return
} }
func DispatchMessage(msg *Msg) (ret int32) { func DispatchMessage(msg *Msg) (ret int32) {
r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0) r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
ret = int32(r0) ret = int32(r0)
return return
} }
func LoadIcon(instance syscall.Handle, iconname *uint16) (icon syscall.Handle, err error) { func LoadIcon(instance syscall.Handle, iconname *uint16) (icon syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0) r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
icon = syscall.Handle(r0) icon = syscall.Handle(r0)
if icon == 0 { if icon == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func LoadCursor(instance syscall.Handle, cursorname *uint16) (cursor syscall.Handle, err error) { func LoadCursor(instance syscall.Handle, cursorname *uint16) (cursor syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0) r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
cursor = syscall.Handle(r0) cursor = syscall.Handle(r0)
if cursor == 0 { if cursor == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func SetCursor(cursor syscall.Handle) (precursor syscall.Handle, err error) { func SetCursor(cursor syscall.Handle) (precursor syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0) r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0)
precursor = syscall.Handle(r0) precursor = syscall.Handle(r0)
if precursor == 0 { if precursor == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }
func SendMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) { func SendMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) {
r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
lresult = uintptr(r0) lresult = uintptr(r0)
return return
} }
func PostMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (err error) { func PostMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) r1, _, e1 := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
if int(r1) == 0 { if int(r1) == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)
} else { } else {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return
} }