Merge branch 'sbinet-github-imports'
This commit is contained in:
commit
3d2a09c9e2
43 changed files with 941 additions and 921 deletions
12
Makefile
12
Makefile
|
@ -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
8
README
|
@ -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]
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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++
|
||||||
}
|
}
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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++
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
166
wingui/winapi.go
166
wingui/winapi.go
|
@ -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)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue