resolve bug on samples array initialization
This commit is contained in:
parent
b0b792a0e8
commit
f4c73f5f01
7 changed files with 1522 additions and 794 deletions
|
@ -3,79 +3,132 @@
|
|||
package raster
|
||||
|
||||
var SUBPIXEL_OFFSETS_SAMPLE_8 = [8]float64{
|
||||
5 / 8,
|
||||
0 / 8,
|
||||
3 / 8,
|
||||
6 / 8,
|
||||
1 / 8,
|
||||
4 / 8,
|
||||
7 / 8,
|
||||
2 / 8,
|
||||
}
|
||||
|
||||
var SUBPIXEL_OFFSETS_SAMPLE_8_FIXED = [8]Fix{
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[0]*FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[1]*FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[2]*FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[3]*FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[4]*FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[5]*FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[6]*FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[7]*FIXED_FLOAT_COEF),
|
||||
5.0 / 8,
|
||||
0.0 / 8,
|
||||
3.0 / 8,
|
||||
6.0 / 8,
|
||||
1.0 / 8,
|
||||
4.0 / 8,
|
||||
7.0 / 8,
|
||||
2.0 / 8,
|
||||
}
|
||||
|
||||
var SUBPIXEL_OFFSETS_SAMPLE_8_FIXED = [8]Fix{
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[0] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[1] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[2] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[3] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[4] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[5] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[6] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_8[7] * FIXED_FLOAT_COEF),
|
||||
}
|
||||
|
||||
var SUBPIXEL_OFFSETS_SAMPLE_16 = [16]float64{
|
||||
(1 / 16),
|
||||
(8 / 16),
|
||||
(4 / 16),
|
||||
(15 / 16),
|
||||
(11 / 16),
|
||||
(2 / 16),
|
||||
(6 / 16),
|
||||
(14 / 16),
|
||||
(10 / 16),
|
||||
(3 / 16),
|
||||
(7 / 16),
|
||||
(12 / 16),
|
||||
(0 / 16),
|
||||
(9 / 16),
|
||||
(5 / 16),
|
||||
(13 / 16),
|
||||
1.0 / 16,
|
||||
8.0 / 16,
|
||||
4.0 / 16,
|
||||
15.0 / 16,
|
||||
11.0 / 16,
|
||||
2.0 / 16,
|
||||
6.0 / 16,
|
||||
14.0 / 16,
|
||||
10.0 / 16,
|
||||
3.0 / 16,
|
||||
7.0 / 16,
|
||||
12.0 / 16,
|
||||
0.0 / 16,
|
||||
9.0 / 16,
|
||||
5.0 / 16,
|
||||
13.0 / 16,
|
||||
}
|
||||
|
||||
var SUBPIXEL_OFFSETS_SAMPLE_16_FIXED = [16]Fix{
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[0] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[1] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[2] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[3] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[4] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[5] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[6] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[7] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[8] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[9] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[10] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[11] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[12] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[13] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[14] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_16[15] * FIXED_FLOAT_COEF),
|
||||
}
|
||||
|
||||
var SUBPIXEL_OFFSETS_SAMPLE_32 = [32]float64{
|
||||
28 / 32,
|
||||
13 / 32,
|
||||
6 / 32,
|
||||
23 / 32,
|
||||
0 / 32,
|
||||
17 / 32,
|
||||
10 / 32,
|
||||
27 / 32,
|
||||
4 / 32,
|
||||
21 / 32,
|
||||
14 / 32,
|
||||
31 / 32,
|
||||
8 / 32,
|
||||
25 / 32,
|
||||
18 / 32,
|
||||
3 / 32,
|
||||
12 / 32,
|
||||
29 / 32,
|
||||
22 / 32,
|
||||
7 / 32,
|
||||
16 / 32,
|
||||
1 / 32,
|
||||
26 / 32,
|
||||
11 / 32,
|
||||
20 / 32,
|
||||
5 / 32,
|
||||
30 / 32,
|
||||
15 / 32,
|
||||
24 / 32,
|
||||
9 / 32,
|
||||
2 / 32,
|
||||
19 / 32,
|
||||
28.0 / 32,
|
||||
13.0 / 32,
|
||||
6.0 / 32,
|
||||
23.0 / 32,
|
||||
0.0 / 32,
|
||||
17.0 / 32,
|
||||
10.0 / 32,
|
||||
27.0 / 32,
|
||||
4.0 / 32,
|
||||
21.0 / 32,
|
||||
14.0 / 32,
|
||||
31.0 / 32,
|
||||
8.0 / 32,
|
||||
25.0 / 32,
|
||||
18.0 / 32,
|
||||
3.0 / 32,
|
||||
12.0 / 32,
|
||||
29.0 / 32,
|
||||
22.0 / 32,
|
||||
7.0 / 32,
|
||||
16.0 / 32,
|
||||
1.0 / 32,
|
||||
26.0 / 32,
|
||||
11.0 / 32,
|
||||
20.0 / 32,
|
||||
5.0 / 32,
|
||||
30.0 / 32,
|
||||
15.0 / 32,
|
||||
24.0 / 32,
|
||||
9.0 / 32,
|
||||
2.0 / 32,
|
||||
19.0 / 32,
|
||||
}
|
||||
var SUBPIXEL_OFFSETS_SAMPLE_32_FIXED = [32]Fix{
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[0] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[1] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[2] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[3] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[4] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[5] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[6] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[7] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[8] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[9] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[10] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[11] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[12] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[13] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[14] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[15] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[16] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[17] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[18] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[19] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[20] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[21] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[22] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[23] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[24] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[25] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[26] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[27] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[28] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[29] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[30] * FIXED_FLOAT_COEF),
|
||||
Fix(SUBPIXEL_OFFSETS_SAMPLE_32[31] * FIXED_FLOAT_COEF),
|
||||
}
|
||||
|
||||
var coverageTable = [256]uint8{
|
||||
|
@ -146,5 +199,5 @@ var coverageTable = [256]uint8{
|
|||
}
|
||||
|
||||
func pixelCoverage(a uint8) uint8 {
|
||||
return (((a) & 1) + (((a) >> 1) & 1) + (((a) >> 2) & 1) + (((a) >> 3) & 1) + (((a) >> 4) & 1) + (((a) >> 5) & 1) + (((a) >> 6) & 1) + (((a) >> 7) & 1))
|
||||
return a&1 + a>>1&1 + a>>2&1 + a>>3&1 + a>>4&1 + a>>5&1 + a>>6&1 + a>>7&1
|
||||
}
|
||||
|
|
|
@ -1,320 +1,320 @@
|
|||
// Copyright 2011 The draw2d Authors. All rights reserved.
|
||||
// created: 27/05/2011 by Laurent Le Goff
|
||||
package raster
|
||||
|
||||
import (
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SUBPIXEL_SHIFT = 3
|
||||
SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
|
||||
)
|
||||
|
||||
var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8_FIXED
|
||||
|
||||
type SUBPIXEL_DATA uint8
|
||||
type NON_ZERO_MASK_DATA_UNIT uint8
|
||||
|
||||
type Rasterizer8BitsSample struct {
|
||||
MaskBuffer []SUBPIXEL_DATA
|
||||
WindingBuffer []NON_ZERO_MASK_DATA_UNIT
|
||||
|
||||
Width int
|
||||
BufferWidth int
|
||||
Height int
|
||||
ClipBound [4]float64
|
||||
RemappingMatrix [6]float64
|
||||
}
|
||||
|
||||
package raster
|
||||
|
||||
import (
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SUBPIXEL_SHIFT = 3
|
||||
SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
|
||||
)
|
||||
|
||||
var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8_FIXED
|
||||
|
||||
type SUBPIXEL_DATA uint8
|
||||
type NON_ZERO_MASK_DATA_UNIT uint8
|
||||
|
||||
type Rasterizer8BitsSample struct {
|
||||
MaskBuffer []SUBPIXEL_DATA
|
||||
WindingBuffer []NON_ZERO_MASK_DATA_UNIT
|
||||
|
||||
Width int
|
||||
BufferWidth int
|
||||
Height int
|
||||
ClipBound [4]float64
|
||||
RemappingMatrix [6]float64
|
||||
}
|
||||
|
||||
/* width and height define the maximum output size for the filler.
|
||||
* The filler will output to larger bitmaps as well, but the output will
|
||||
* be cropped.
|
||||
*/
|
||||
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
|
||||
var r Rasterizer8BitsSample
|
||||
*/
|
||||
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
|
||||
var r Rasterizer8BitsSample
|
||||
// Scale the coordinates by SUBPIXEL_COUNT in vertical direction
|
||||
// The sampling point for the sub-pixel is at the top right corner. This
|
||||
// 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.Width = width
|
||||
r.Height = height
|
||||
r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
|
||||
r.Width = width
|
||||
r.Height = height
|
||||
// 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
|
||||
// after the actually drawn edge.
|
||||
r.BufferWidth = width + 1
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
|
||||
r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
|
||||
return &r
|
||||
}
|
||||
|
||||
func clip(x, y, width, height, scale int) [4]float64 {
|
||||
var clipBound [4]float64
|
||||
|
||||
offset := 0.99 / float64(scale)
|
||||
|
||||
clipBound[0] = float64(x) + offset
|
||||
clipBound[2] = float64(x+width) - offset
|
||||
|
||||
clipBound[1] = float64(y * scale)
|
||||
clipBound[3] = float64((y + height) * scale)
|
||||
return clipBound
|
||||
}
|
||||
|
||||
func intersect(r1, r2 [4]float64) [4]float64 {
|
||||
if r1[0] < r2[0] {
|
||||
r1[0] = r2[0]
|
||||
}
|
||||
if r1[2] > r2[2] {
|
||||
r1[2] = r2[2]
|
||||
}
|
||||
if r1[0] > r1[2] {
|
||||
r1[0] = r1[2]
|
||||
}
|
||||
|
||||
if r1[1] < r2[1] {
|
||||
r1[1] = r2[1]
|
||||
}
|
||||
if r1[3] > r2[3] {
|
||||
r1[3] = r2[3]
|
||||
}
|
||||
if r1[1] > r1[3] {
|
||||
r1[1] = r1[3]
|
||||
}
|
||||
return r1
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
r.BufferWidth = width + 1
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
|
||||
r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
|
||||
return &r
|
||||
}
|
||||
|
||||
func clip(x, y, width, height, scale int) [4]float64 {
|
||||
var clipBound [4]float64
|
||||
|
||||
offset := 0.99 / float64(scale)
|
||||
|
||||
clipBound[0] = float64(x) + offset
|
||||
clipBound[2] = float64(x+width) - offset
|
||||
|
||||
clipBound[1] = float64(y * scale)
|
||||
clipBound[3] = float64((y + height) * scale)
|
||||
return clipBound
|
||||
}
|
||||
|
||||
func intersect(r1, r2 [4]float64) [4]float64 {
|
||||
if r1[0] < r2[0] {
|
||||
r1[0] = r2[0]
|
||||
}
|
||||
if r1[2] > r2[2] {
|
||||
r1[2] = r2[2]
|
||||
}
|
||||
if r1[0] > r1[2] {
|
||||
r1[0] = r1[2]
|
||||
}
|
||||
|
||||
if r1[1] < r2[1] {
|
||||
r1[1] = r2[1]
|
||||
}
|
||||
if r1[3] > r2[3] {
|
||||
r1[3] = r2[3]
|
||||
}
|
||||
if r1[1] > r1[3] {
|
||||
r1[1] = r1[3]
|
||||
}
|
||||
return r1
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
// 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
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addEvenOddEdge(&(edges[k]))
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillEvenOdd(img, color, clipRect)
|
||||
}
|
||||
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addEvenOddEdge(&edges[k])
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillEvenOdd(img, color, clipRect)
|
||||
}
|
||||
|
||||
//! Adds an edge to be used with even-odd fill.
|
||||
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
|
||||
x := Fix(edge.X * FIXED_FLOAT_COEF)
|
||||
slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
|
||||
slopeFix := Fix(0)
|
||||
if (edge.LastLine - edge.FirstLine >= SLOPE_FIX_STEP) {
|
||||
slopeFix = Fix(edge.Slope * SLOPE_FIX_STEP * FIXED_FLOAT_COEF) - (slope << SLOPE_FIX_SHIFT);
|
||||
}
|
||||
|
||||
var mask SUBPIXEL_DATA
|
||||
var ySub uint32
|
||||
var xp, yLine int
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = uint32(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
|
||||
x += slope
|
||||
if (y & SLOPE_FIX_MASK) == 0 {
|
||||
x += slopeFix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
|
||||
x := Fix(edge.X * FIXED_FLOAT_COEF)
|
||||
slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
|
||||
slopeFix := Fix(0)
|
||||
if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
|
||||
slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
|
||||
}
|
||||
|
||||
var mask SUBPIXEL_DATA
|
||||
var ySub uint32
|
||||
var xp, yLine int
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = uint32(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
|
||||
x += slope
|
||||
if y&SLOPE_FIX_MASK == 0 {
|
||||
x += slopeFix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Adds an edge to be used with non-zero winding fill.
|
||||
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
|
||||
x := Fix(edge.X * FIXED_FLOAT_COEF)
|
||||
slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
|
||||
slopeFix := Fix(0)
|
||||
if (edge.LastLine - edge.FirstLine >= SLOPE_FIX_STEP) {
|
||||
slopeFix = Fix(edge.Slope * SLOPE_FIX_STEP * FIXED_FLOAT_COEF) - (slope << SLOPE_FIX_SHIFT);
|
||||
}
|
||||
var mask SUBPIXEL_DATA
|
||||
var ySub uint32
|
||||
var xp, yLine int
|
||||
winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = uint32(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
|
||||
r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
|
||||
x += slope
|
||||
if (y & SLOPE_FIX_MASK) == 0 {
|
||||
x += slopeFix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
|
||||
x := Fix(edge.X * FIXED_FLOAT_COEF)
|
||||
slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
|
||||
slopeFix := Fix(0)
|
||||
if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
|
||||
slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
|
||||
}
|
||||
var mask SUBPIXEL_DATA
|
||||
var ySub uint32
|
||||
var xp, yLine int
|
||||
winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = uint32(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
|
||||
r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
|
||||
x += slope
|
||||
if y&SLOPE_FIX_MASK == 0 {
|
||||
x += slopeFix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the mask to the canvas with even-odd fill.
|
||||
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
|
||||
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
|
||||
|
||||
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> 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)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := (*pixColor >> 8) & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
pixColor := (*uint32)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := *pixColor >> 8 & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
// 8bits
|
||||
alpha := uint32(coverageTable[mask])
|
||||
alpha := uint32(coverageTable[mask])
|
||||
// 16bits
|
||||
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
|
||||
// 32bits
|
||||
//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
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := (*p & 0xff00ff) * invAlpha
|
||||
ct2 := ((*p >> 8) & 0xff00ff) * invAlpha
|
||||
|
||||
ct1 = ((ct1 + cs1*alpha) >> SUBPIXEL_SHIFT) & 0xff00ff
|
||||
ct2 = ((ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT)) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invAlpha := SUBPIXEL_COUNT - alpha
|
||||
|
||||
ct1 := *p & 0xff00ff * invAlpha
|
||||
ct2 := *p >> 8 & 0xff00ff * invAlpha
|
||||
|
||||
ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
|
||||
ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Renders the polygon with non-zero winding fill.
|
||||
* param aTarget the target bitmap.
|
||||
* param aPolygon the polygon to render.
|
||||
* param aColor the color to be used for rendering.
|
||||
* param aTransformation the transformation matrix.
|
||||
*/
|
||||
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
|
||||
|
||||
*/
|
||||
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
|
||||
|
||||
// inline matrix multiplication
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addNonZeroEdge(&(edges[k]))
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillNonZero(img, color, clipRect)
|
||||
}
|
||||
|
||||
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addNonZeroEdge(&edges[k])
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillNonZero(img, color, clipRect)
|
||||
}
|
||||
|
||||
|
||||
//! Renders the mask to the canvas with non-zero winding fill.
|
||||
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
|
||||
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
|
||||
|
||||
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> 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)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := (*pixColor >> 8) & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
var n uint32
|
||||
var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
values[n] = 0
|
||||
}
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
if temp != 0 {
|
||||
var bit SUBPIXEL_DATA = 1
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
if (temp & bit) != 0 {
|
||||
t := values[n]
|
||||
values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
|
||||
if (t == 0 || values[n] == 0 )&& t != values[n] {
|
||||
mask ^= bit
|
||||
}
|
||||
}
|
||||
bit <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
pixColor := (*uint32)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := *pixColor >> 8 & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
var n uint32
|
||||
var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
values[n] = 0
|
||||
}
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
if temp != 0 {
|
||||
var bit SUBPIXEL_DATA = 1
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
if temp&bit != 0 {
|
||||
t := values[n]
|
||||
values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
|
||||
if (t == 0 || values[n] == 0) && t != values[n] {
|
||||
mask ^= bit
|
||||
}
|
||||
}
|
||||
bit <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
// 8bits
|
||||
alpha := uint32(coverageTable[mask])
|
||||
alpha := uint32(coverageTable[mask])
|
||||
// 16bits
|
||||
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
|
||||
// 32bits
|
||||
//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
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := (*p & 0xff00ff) * invAlpha
|
||||
ct2 := ((*p >> 8) & 0xff00ff) * invAlpha
|
||||
|
||||
ct1 = ((ct1 + cs1*alpha) >> SUBPIXEL_SHIFT) & 0xff00ff
|
||||
ct2 = ((ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT)) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := *p & 0xff00ff * invAlpha
|
||||
ct2 := *p >> 8 & 0xff00ff * invAlpha
|
||||
|
||||
ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
|
||||
ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,302 +1,302 @@
|
|||
// Copyright 2011 The draw2d Authors. All rights reserved.
|
||||
// created: 27/05/2011 by Laurent Le Goff
|
||||
package raster
|
||||
|
||||
import (
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SUBPIXEL_SHIFT = 3
|
||||
SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
|
||||
)
|
||||
|
||||
var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8
|
||||
|
||||
type SUBPIXEL_DATA uint16
|
||||
type NON_ZERO_MASK_DATA_UNIT uint8
|
||||
|
||||
type Rasterizer8BitsSample struct {
|
||||
MaskBuffer []SUBPIXEL_DATA
|
||||
WindingBuffer []NON_ZERO_MASK_DATA_UNIT
|
||||
|
||||
Width int
|
||||
BufferWidth int
|
||||
Height int
|
||||
ClipBound [4]float64
|
||||
RemappingMatrix [6]float64
|
||||
}
|
||||
|
||||
package raster
|
||||
|
||||
import (
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SUBPIXEL_SHIFT = 3
|
||||
SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
|
||||
)
|
||||
|
||||
var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8
|
||||
|
||||
type SUBPIXEL_DATA uint16
|
||||
type NON_ZERO_MASK_DATA_UNIT uint8
|
||||
|
||||
type Rasterizer8BitsSample struct {
|
||||
MaskBuffer []SUBPIXEL_DATA
|
||||
WindingBuffer []NON_ZERO_MASK_DATA_UNIT
|
||||
|
||||
Width int
|
||||
BufferWidth int
|
||||
Height int
|
||||
ClipBound [4]float64
|
||||
RemappingMatrix [6]float64
|
||||
}
|
||||
|
||||
/* width and height define the maximum output size for the filler.
|
||||
* The filler will output to larger bitmaps as well, but the output will
|
||||
* be cropped.
|
||||
*/
|
||||
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
|
||||
var r Rasterizer8BitsSample
|
||||
*/
|
||||
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
|
||||
var r Rasterizer8BitsSample
|
||||
// Scale the coordinates by SUBPIXEL_COUNT in vertical direction
|
||||
// The sampling point for the sub-pixel is at the top right corner. This
|
||||
// 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.Width = width
|
||||
r.Height = height
|
||||
r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT}
|
||||
r.Width = width
|
||||
r.Height = height
|
||||
// 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
|
||||
// after the actually drawn edge.
|
||||
r.BufferWidth = width + 1
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
|
||||
r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
|
||||
return &r
|
||||
}
|
||||
|
||||
func clip(x, y, width, height, scale int) [4]float64 {
|
||||
var clipBound [4]float64
|
||||
|
||||
offset := 0.99 / float64(scale)
|
||||
|
||||
clipBound[0] = float64(x) + offset
|
||||
clipBound[2] = float64(x+width) - offset
|
||||
|
||||
clipBound[1] = float64(y * scale)
|
||||
clipBound[3] = float64((y + height) * scale)
|
||||
return clipBound
|
||||
}
|
||||
|
||||
func intersect(r1, r2 [4]float64) [4]float64 {
|
||||
if r1[0] < r2[0] {
|
||||
r1[0] = r2[0]
|
||||
}
|
||||
if r1[2] > r2[2] {
|
||||
r1[2] = r2[2]
|
||||
}
|
||||
if r1[0] > r1[2] {
|
||||
r1[0] = r1[2]
|
||||
}
|
||||
|
||||
if r1[1] < r2[1] {
|
||||
r1[1] = r2[1]
|
||||
}
|
||||
if r1[3] > r2[3] {
|
||||
r1[3] = r2[3]
|
||||
}
|
||||
if r1[1] > r1[3] {
|
||||
r1[1] = r1[3]
|
||||
}
|
||||
return r1
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
r.BufferWidth = width + 1
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
|
||||
r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
|
||||
return &r
|
||||
}
|
||||
|
||||
func clip(x, y, width, height, scale int) [4]float64 {
|
||||
var clipBound [4]float64
|
||||
|
||||
offset := 0.99 / float64(scale)
|
||||
|
||||
clipBound[0] = float64(x) + offset
|
||||
clipBound[2] = float64(x+width) - offset
|
||||
|
||||
clipBound[1] = float64(y * scale)
|
||||
clipBound[3] = float64((y + height) * scale)
|
||||
return clipBound
|
||||
}
|
||||
|
||||
func intersect(r1, r2 [4]float64) [4]float64 {
|
||||
if r1[0] < r2[0] {
|
||||
r1[0] = r2[0]
|
||||
}
|
||||
if r1[2] > r2[2] {
|
||||
r1[2] = r2[2]
|
||||
}
|
||||
if r1[0] > r1[2] {
|
||||
r1[0] = r1[2]
|
||||
}
|
||||
|
||||
if r1[1] < r2[1] {
|
||||
r1[1] = r2[1]
|
||||
}
|
||||
if r1[3] > r2[3] {
|
||||
r1[3] = r2[3]
|
||||
}
|
||||
if r1[1] > r1[3] {
|
||||
r1[1] = r1[3]
|
||||
}
|
||||
return r1
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
// 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
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addEvenOddEdge(&(edges[k]))
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillEvenOdd(img, color, clipRect)
|
||||
}
|
||||
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addEvenOddEdge(&edges[k])
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillEvenOdd(img, color, clipRect)
|
||||
}
|
||||
|
||||
//! Adds an edge to be used with even-odd fill.
|
||||
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
|
||||
x := edge.X
|
||||
slope := edge.Slope
|
||||
var ySub, mask SUBPIXEL_DATA
|
||||
var xp, yLine int
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = (int)(x + SUBPIXEL_OFFSETS[ySub])
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
|
||||
x += slope
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
|
||||
x := edge.X
|
||||
slope := edge.Slope
|
||||
var ySub, mask SUBPIXEL_DATA
|
||||
var xp, yLine int
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int(x + SUBPIXEL_OFFSETS[ySub])
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
|
||||
x += slope
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the mask to the canvas with even-odd fill.
|
||||
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
|
||||
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
|
||||
|
||||
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> 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)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := (*pixColor >> 8) & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
pixColor := (*uint32)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := *pixColor >> 8 & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
// 8bits
|
||||
alpha := uint32(coverageTable[mask])
|
||||
alpha := uint32(coverageTable[mask])
|
||||
// 16bits
|
||||
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
|
||||
// 32bits
|
||||
//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
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := (*p & 0xff00ff) * invAlpha
|
||||
ct2 := ((*p >> 8) & 0xff00ff) * invAlpha
|
||||
|
||||
ct1 = ((ct1 + cs1*alpha) >> SUBPIXEL_SHIFT) & 0xff00ff
|
||||
ct2 = ((ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT)) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := *p & 0xff00ff * invAlpha
|
||||
ct2 := *p >> 8 & 0xff00ff * invAlpha
|
||||
|
||||
ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
|
||||
ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Renders the polygon with non-zero winding fill.
|
||||
* param aTarget the target bitmap.
|
||||
* param aPolygon the polygon to render.
|
||||
* param aColor the color to be used for rendering.
|
||||
* param aTransformation the transformation matrix.
|
||||
*/
|
||||
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
|
||||
|
||||
*/
|
||||
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
|
||||
|
||||
// inline matrix multiplication
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addNonZeroEdge(&(edges[k]))
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillNonZero(img, color, clipRect)
|
||||
}
|
||||
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addNonZeroEdge(&edges[k])
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillNonZero(img, color, clipRect)
|
||||
}
|
||||
|
||||
//! Adds an edge to be used with non-zero winding fill.
|
||||
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
|
||||
x := edge.X
|
||||
slope := edge.Slope
|
||||
var ySub, mask SUBPIXEL_DATA
|
||||
var xp, yLine int
|
||||
winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = (int)(x + SUBPIXEL_OFFSETS[ySub])
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
|
||||
r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
|
||||
x += slope
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
|
||||
x := edge.X
|
||||
slope := edge.Slope
|
||||
var ySub, mask SUBPIXEL_DATA
|
||||
var xp, yLine int
|
||||
winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int(x + SUBPIXEL_OFFSETS[ySub])
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
|
||||
r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
|
||||
x += slope
|
||||
}
|
||||
}
|
||||
|
||||
//! Renders the mask to the canvas with non-zero winding fill.
|
||||
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT
|
||||
maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT
|
||||
|
||||
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> 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)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := (*pixColor >> 8) & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
var n uint32
|
||||
var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
values[n] = 0
|
||||
}
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
if temp != 0 {
|
||||
var bit SUBPIXEL_DATA = 1
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
if (temp & bit) != 0 {
|
||||
t := values[n]
|
||||
values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
|
||||
if (t == 0 || values[n] == 0 )&& t != values[n] {
|
||||
mask ^= bit
|
||||
}
|
||||
}
|
||||
bit <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
pixColor := (*uint32)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := *pixColor >> 8 & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
var n uint32
|
||||
var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
values[n] = 0
|
||||
}
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
if temp != 0 {
|
||||
var bit SUBPIXEL_DATA = 1
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
if temp&bit != 0 {
|
||||
t := values[n]
|
||||
values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
|
||||
if (t == 0 || values[n] == 0) && t != values[n] {
|
||||
mask ^= bit
|
||||
}
|
||||
}
|
||||
bit <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
// 8bits
|
||||
alpha := uint32(coverageTable[mask])
|
||||
alpha := uint32(coverageTable[mask])
|
||||
// 16bits
|
||||
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
|
||||
// 32bits
|
||||
//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
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := (*p & 0xff00ff) * invAlpha
|
||||
ct2 := ((*p >> 8) & 0xff00ff) * invAlpha
|
||||
|
||||
ct1 = ((ct1 + cs1*alpha) >> SUBPIXEL_SHIFT) & 0xff00ff
|
||||
ct2 = ((ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT)) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := *p & 0xff00ff * invAlpha
|
||||
ct2 := *p >> 8 & 0xff00ff * invAlpha
|
||||
|
||||
ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
|
||||
ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
320
draw2d/raster/fillerV2/fillerAA.go
Normal file
320
draw2d/raster/fillerV2/fillerAA.go
Normal file
|
@ -0,0 +1,320 @@
|
|||
// Copyright 2011 The draw2d Authors. All rights reserved.
|
||||
// created: 27/05/2011 by Laurent Le Goff
|
||||
package raster
|
||||
|
||||
import (
|
||||
"image"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SUBPIXEL_SHIFT = 5
|
||||
SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
|
||||
)
|
||||
|
||||
var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_32_FIXED
|
||||
|
||||
type SUBPIXEL_DATA uint32
|
||||
type NON_ZERO_MASK_DATA_UNIT uint8
|
||||
|
||||
type Rasterizer8BitsSample struct {
|
||||
MaskBuffer []SUBPIXEL_DATA
|
||||
WindingBuffer []NON_ZERO_MASK_DATA_UNIT
|
||||
|
||||
Width int
|
||||
BufferWidth int
|
||||
Height int
|
||||
ClipBound [4]float64
|
||||
RemappingMatrix [6]float64
|
||||
}
|
||||
|
||||
/* width and height define the maximum output size for the filler.
|
||||
* The filler will output to larger bitmaps as well, but the output will
|
||||
* be cropped.
|
||||
*/
|
||||
func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample {
|
||||
var r Rasterizer8BitsSample
|
||||
// Scale the coordinates by SUBPIXEL_COUNT in vertical direction
|
||||
// The sampling point for the sub-pixel is at the top right corner. This
|
||||
// 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.Width = width
|
||||
r.Height = height
|
||||
// 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
|
||||
// after the actually drawn edge.
|
||||
r.BufferWidth = width + 1
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT)
|
||||
r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT)
|
||||
return &r
|
||||
}
|
||||
|
||||
func clip(x, y, width, height, scale int) [4]float64 {
|
||||
var clipBound [4]float64
|
||||
|
||||
offset := 0.99 / float64(scale)
|
||||
|
||||
clipBound[0] = float64(x) + offset
|
||||
clipBound[2] = float64(x+width) - offset
|
||||
|
||||
clipBound[1] = float64(y * scale)
|
||||
clipBound[3] = float64((y + height) * scale)
|
||||
return clipBound
|
||||
}
|
||||
|
||||
func intersect(r1, r2 [4]float64) [4]float64 {
|
||||
if r1[0] < r2[0] {
|
||||
r1[0] = r2[0]
|
||||
}
|
||||
if r1[2] > r2[2] {
|
||||
r1[2] = r2[2]
|
||||
}
|
||||
if r1[0] > r1[2] {
|
||||
r1[0] = r1[2]
|
||||
}
|
||||
|
||||
if r1[1] < r2[1] {
|
||||
r1[1] = r2[1]
|
||||
}
|
||||
if r1[3] > r2[3] {
|
||||
r1[3] = r2[3]
|
||||
}
|
||||
if r1[1] > r1[3] {
|
||||
r1[1] = r1[3]
|
||||
}
|
||||
return r1
|
||||
}
|
||||
|
||||
func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
// memset 0 the mask buffer
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
|
||||
|
||||
// inline matrix multiplication
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addEvenOddEdge(&edges[k])
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillEvenOdd(img, color, clipRect)
|
||||
}
|
||||
|
||||
//! Adds an edge to be used with even-odd fill.
|
||||
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
|
||||
x := Fix(edge.X * FIXED_FLOAT_COEF)
|
||||
slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
|
||||
slopeFix := Fix(0)
|
||||
if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
|
||||
slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
|
||||
}
|
||||
|
||||
var mask SUBPIXEL_DATA
|
||||
var ySub uint32
|
||||
var xp, yLine int
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = uint32(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
|
||||
x += slope
|
||||
if y&SLOPE_FIX_MASK == 0 {
|
||||
x += slopeFix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Adds an edge to be used with non-zero winding fill.
|
||||
func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) {
|
||||
x := Fix(edge.X * FIXED_FLOAT_COEF)
|
||||
slope := Fix(edge.Slope * FIXED_FLOAT_COEF)
|
||||
slopeFix := Fix(0)
|
||||
if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP {
|
||||
slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<<SLOPE_FIX_SHIFT
|
||||
}
|
||||
var mask SUBPIXEL_DATA
|
||||
var ySub uint32
|
||||
var xp, yLine int
|
||||
winding := NON_ZERO_MASK_DATA_UNIT(edge.Winding)
|
||||
for y := edge.FirstLine; y <= edge.LastLine; y++ {
|
||||
ySub = uint32(y & (SUBPIXEL_COUNT - 1))
|
||||
xp = int((x + SUBPIXEL_OFFSETS[ySub]) >> FIXED_SHIFT)
|
||||
mask = SUBPIXEL_DATA(1 << ySub)
|
||||
yLine = y >> SUBPIXEL_SHIFT
|
||||
r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask
|
||||
r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding
|
||||
x += slope
|
||||
if y&SLOPE_FIX_MASK == 0 {
|
||||
x += slopeFix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the mask to the canvas with even-odd fill.
|
||||
func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> 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)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := *pixColor >> 8 & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
// 8bits
|
||||
//alpha := uint32(coverageTable[mask])
|
||||
// 16bits
|
||||
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
|
||||
// 32bits
|
||||
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
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := *p & 0xff00ff * invAlpha
|
||||
ct2 := *p >> 8 & 0xff00ff * invAlpha
|
||||
|
||||
ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
|
||||
ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Renders the polygon with non-zero winding fill.
|
||||
* param aTarget the target bitmap.
|
||||
* param aPolygon the polygon to render.
|
||||
* param aColor the color to be used for rendering.
|
||||
* param aTransformation the transformation matrix.
|
||||
*/
|
||||
func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) {
|
||||
|
||||
r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height)
|
||||
r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT)
|
||||
|
||||
// inline matrix multiplication
|
||||
transform := [6]float64{
|
||||
tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2],
|
||||
tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1],
|
||||
tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2],
|
||||
tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1],
|
||||
tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4],
|
||||
tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5],
|
||||
}
|
||||
|
||||
clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT)
|
||||
clipRect = intersect(clipRect, r.ClipBound)
|
||||
|
||||
p := 0
|
||||
l := len(*polygon) / 2
|
||||
var edges [32]PolygonEdge
|
||||
for p < l {
|
||||
edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
|
||||
for k := 0; k < edgeCount; k++ {
|
||||
r.addNonZeroEdge(&edges[k])
|
||||
}
|
||||
p += 16
|
||||
}
|
||||
|
||||
r.fillNonZero(img, color, clipRect)
|
||||
}
|
||||
|
||||
|
||||
//! Renders the mask to the canvas with non-zero winding fill.
|
||||
func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) {
|
||||
var x, y uint32
|
||||
|
||||
minX := uint32(clipBound[0])
|
||||
maxX := uint32(clipBound[2])
|
||||
|
||||
minY := uint32(clipBound[1]) >> 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)(unsafe.Pointer(color))
|
||||
cs1 := *pixColor & 0xff00ff
|
||||
cs2 := *pixColor >> 8 & 0xff00ff
|
||||
|
||||
stride := uint32(img.Stride)
|
||||
var mask SUBPIXEL_DATA
|
||||
var n uint32
|
||||
var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
values[n] = 0
|
||||
}
|
||||
|
||||
for y = minY; y < maxY; y++ {
|
||||
tp := img.Pix[y*stride:]
|
||||
|
||||
mask = 0
|
||||
for x = minX; x <= maxX; x++ {
|
||||
p := (*uint32)(unsafe.Pointer(&tp[x]))
|
||||
temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x]
|
||||
if temp != 0 {
|
||||
var bit SUBPIXEL_DATA = 1
|
||||
for n = 0; n < SUBPIXEL_COUNT; n++ {
|
||||
if temp&bit != 0 {
|
||||
t := values[n]
|
||||
values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n]
|
||||
if (t == 0 || values[n] == 0) && t != values[n] {
|
||||
mask ^= bit
|
||||
}
|
||||
}
|
||||
bit <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
// 8bits
|
||||
//alpha := uint32(coverageTable[mask])
|
||||
// 16bits
|
||||
//alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff])
|
||||
// 32bits
|
||||
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
|
||||
invAlpha := uint32(SUBPIXEL_COUNT) - alpha
|
||||
|
||||
ct1 := *p & 0xff00ff * invAlpha
|
||||
ct2 := *p >> 8 & 0xff00ff * invAlpha
|
||||
|
||||
ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff
|
||||
ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00
|
||||
|
||||
*p = ct1 + ct2
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package raster
|
|||
type Fix int32
|
||||
|
||||
const (
|
||||
FIXED_SHIFT = 16
|
||||
FIXED_SHIFT = 16
|
||||
FIXED_FLOAT_COEF = 1 << FIXED_SHIFT
|
||||
)
|
||||
|
||||
|
@ -12,6 +12,6 @@ const (
|
|||
*/
|
||||
const (
|
||||
SLOPE_FIX_SHIFT = 8
|
||||
SLOPE_FIX_STEP = 1 << SLOPE_FIX_SHIFT
|
||||
SLOPE_FIX_MASK = SLOPE_FIX_STEP - 1
|
||||
)
|
||||
SLOPE_FIX_STEP = 1 << SLOPE_FIX_SHIFT
|
||||
SLOPE_FIX_MASK = SLOPE_FIX_STEP - 1
|
||||
)
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
// created: 27/05/2011 by Laurent Le Goff
|
||||
package raster
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
POLYGON_CLIP_NONE = iota
|
||||
POLYGON_CLIP_LEFT
|
||||
|
@ -23,6 +19,15 @@ type PolygonEdge struct {
|
|||
Winding int16
|
||||
}
|
||||
|
||||
//! A more optimized representation of a polygon edge.
|
||||
type PolygonScanEdge struct {
|
||||
FirstLine, LastLine int
|
||||
Winding int16
|
||||
X Fix
|
||||
Slope Fix
|
||||
SlopeFix Fix
|
||||
NextEdge *PolygonScanEdge
|
||||
}
|
||||
|
||||
//! Calculates the edges of the polygon with transformation and clipping to edges array.
|
||||
/*! \param startIndex the index for the first vertex.
|
||||
|
@ -34,7 +39,7 @@ type PolygonEdge struct {
|
|||
*/
|
||||
func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [6]float64, clipBound [4]float64) int {
|
||||
startIndex = startIndex * 2
|
||||
endIndex := startIndex + (vertexCount * 2)
|
||||
endIndex := startIndex + vertexCount*2
|
||||
if endIndex > len(p) {
|
||||
endIndex = len(p)
|
||||
}
|
||||
|
@ -85,20 +90,20 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
|
|||
clipUnion = prevClipFlags & clipFlags
|
||||
|
||||
// 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_RIGHT) != 0 {
|
||||
if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 {
|
||||
if clipUnion&POLYGON_CLIP_RIGHT != 0 {
|
||||
// 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++
|
||||
}
|
||||
} 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
|
||||
if getVerticalEdge(prevY, y, clipBound[0], &(edges[edgeCount]), clipBound) {
|
||||
if getVerticalEdge(prevY, y, clipBound[0], &edges[edgeCount], clipBound) {
|
||||
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
|
||||
if getEdge(prevX, prevY, x, y, &(edges[edgeCount]), clipBound) {
|
||||
if getEdge(prevX, prevY, x, y, &edges[edgeCount], clipBound) {
|
||||
edgeCount++
|
||||
}
|
||||
} else {
|
||||
|
@ -116,7 +121,7 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
|
|||
|
||||
slope := (yright - yleft) / (xright - xleft)
|
||||
|
||||
if (clipSum & POLYGON_CLIP_RIGHT) != 0 {
|
||||
if clipSum&POLYGON_CLIP_RIGHT != 0 {
|
||||
// calculate new position for the right vertex
|
||||
oldY = yright
|
||||
maxX = clipBound[2]
|
||||
|
@ -125,13 +130,13 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
|
|||
xright = maxX
|
||||
|
||||
// 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
|
||||
edgeCount++
|
||||
}
|
||||
}
|
||||
|
||||
if (clipSum & POLYGON_CLIP_LEFT) != 0 {
|
||||
if clipSum&POLYGON_CLIP_LEFT != 0 {
|
||||
// calculate new position for the left vertex
|
||||
oldY = yleft
|
||||
minX = clipBound[0]
|
||||
|
@ -140,13 +145,13 @@ func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [
|
|||
xleft = minX
|
||||
|
||||
// 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
|
||||
edgeCount++
|
||||
}
|
||||
}
|
||||
|
||||
if getEdge(xleft, yleft, xright, yright, &(edges[edgeCount]), clipBound) {
|
||||
if getEdge(xleft, yleft, xright, yright, &edges[edgeCount], clipBound) {
|
||||
edges[edgeCount].Winding *= swapWinding
|
||||
edgeCount++
|
||||
}
|
||||
|
@ -192,8 +197,8 @@ func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bo
|
|||
// also round to zero. The problems in this range can be avoided by
|
||||
// adding one to the values before conversion and subtracting after it.
|
||||
|
||||
firstLine := int(math.Floor(startY)) + 1
|
||||
lastLine := int(math.Floor(endY))
|
||||
firstLine := int(startY + 1)
|
||||
lastLine := int(endY+1) - 1
|
||||
|
||||
minClip := int(clipBound[1])
|
||||
maxClip := int(clipBound[3])
|
||||
|
@ -241,8 +246,8 @@ func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]fl
|
|||
winding = -1
|
||||
}
|
||||
|
||||
firstLine := int(math.Floor(start)) + 1
|
||||
lastLine := int(math.Floor(end))
|
||||
firstLine := int(start + 1)
|
||||
lastLine := int(end+1) - 1
|
||||
|
||||
minClip := int(clipBound[1])
|
||||
maxClip := int(clipBound[3])
|
||||
|
@ -271,3 +276,309 @@ func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]fl
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
type VertexData struct {
|
||||
X, Y float64
|
||||
ClipFlags int
|
||||
Line int
|
||||
}
|
||||
//! 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,
|
||||
* 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 aTransformation the transformation matrix for the polygon.
|
||||
* \param aClipRectangle the clip rectangle.
|
||||
* \return the amount of edges in the result.
|
||||
*/
|
||||
func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound [4]float64) int {
|
||||
var n int
|
||||
vertexData := make([]VertexData, len(p)/2+1)
|
||||
for n = 0; n < len(vertexData)-1; n = n + 1 {
|
||||
k := n * 2
|
||||
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]
|
||||
// Calculate clip flags for all vertices.
|
||||
vertexData[n].ClipFlags = POLYGON_CLIP_NONE
|
||||
if vertexData[n].X < clipBound[0] {
|
||||
vertexData[n].ClipFlags |= POLYGON_CLIP_LEFT
|
||||
} else if vertexData[n].X >= clipBound[2] {
|
||||
vertexData[n].ClipFlags |= POLYGON_CLIP_RIGHT
|
||||
}
|
||||
if vertexData[n].Y < clipBound[1] {
|
||||
vertexData[n].ClipFlags |= POLYGON_CLIP_TOP
|
||||
} else if vertexData[n].Y >= clipBound[3] {
|
||||
vertexData[n].ClipFlags |= POLYGON_CLIP_BOTTOM
|
||||
}
|
||||
|
||||
// Calculate line of the vertex. If the vertex is clipped by top or bottom, the line
|
||||
// is determined by the clip rectangle.
|
||||
if vertexData[n].ClipFlags&POLYGON_CLIP_TOP != 0 {
|
||||
vertexData[n].Line = int(clipBound[1])
|
||||
} else if vertexData[n].ClipFlags&POLYGON_CLIP_BOTTOM != 0 {
|
||||
vertexData[n].Line = int(clipBound[3] - 1)
|
||||
} else {
|
||||
vertexData[n].Line = int(vertexData[n].Y+1) - 1
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the data from 0 to the last entry to make the data to loop.
|
||||
vertexData[len(vertexData)-1] = vertexData[0]
|
||||
|
||||
// Transform the first vertex; store.
|
||||
// Process mVertexCount - 1 times, next is n+1
|
||||
// copy the first vertex to
|
||||
// Process 1 time, next is n
|
||||
|
||||
edgeCount := 0
|
||||
for n = 0; n < len(vertexData)-1; n++ {
|
||||
clipSum := vertexData[n].ClipFlags | vertexData[n+1].ClipFlags
|
||||
clipUnion := vertexData[n].ClipFlags & vertexData[n+1].ClipFlags
|
||||
|
||||
if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 &&
|
||||
vertexData[n].Line != vertexData[n+1].Line {
|
||||
var startIndex, endIndex int
|
||||
var winding int16
|
||||
if vertexData[n].Y < vertexData[n+1].Y {
|
||||
startIndex = n
|
||||
endIndex = n + 1
|
||||
winding = 1
|
||||
} else {
|
||||
startIndex = n + 1
|
||||
endIndex = n
|
||||
winding = -1
|
||||
}
|
||||
|
||||
firstLine := vertexData[startIndex].Line + 1
|
||||
lastLine := vertexData[endIndex].Line
|
||||
|
||||
if clipUnion&POLYGON_CLIP_RIGHT != 0 {
|
||||
// Both clip to right, edge is a vertical line on the right side
|
||||
edges[edgeCount].FirstLine = firstLine
|
||||
edges[edgeCount].LastLine = lastLine
|
||||
edges[edgeCount].Winding = winding
|
||||
edges[edgeCount].X = Fix(clipBound[2] * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = 0
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
|
||||
edgeCount++
|
||||
} else if clipUnion&POLYGON_CLIP_LEFT != 0 {
|
||||
// Both clip to left, edge is a vertical line on the left side
|
||||
edges[edgeCount].FirstLine = firstLine
|
||||
edges[edgeCount].LastLine = lastLine
|
||||
edges[edgeCount].Winding = winding
|
||||
edges[edgeCount].X = Fix(clipBound[0] * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = 0
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
|
||||
edgeCount++
|
||||
} else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 {
|
||||
// No clipping in the horizontal direction
|
||||
slope := (vertexData[endIndex].X -
|
||||
vertexData[startIndex].X) /
|
||||
(vertexData[endIndex].Y -
|
||||
vertexData[startIndex].Y)
|
||||
|
||||
// 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
|
||||
// where the edge crosses the first scanline.
|
||||
startx := vertexData[startIndex].X +
|
||||
(float64(firstLine)-vertexData[startIndex].Y)*slope
|
||||
|
||||
edges[edgeCount].FirstLine = firstLine
|
||||
edges[edgeCount].LastLine = lastLine
|
||||
edges[edgeCount].Winding = winding
|
||||
edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
|
||||
|
||||
if lastLine-firstLine >= SLOPE_FIX_STEP {
|
||||
edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
|
||||
edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
|
||||
} else {
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
}
|
||||
|
||||
edgeCount++
|
||||
} else {
|
||||
// Clips to left or right or both.
|
||||
slope := (vertexData[endIndex].X -
|
||||
vertexData[startIndex].X) /
|
||||
(vertexData[endIndex].Y -
|
||||
vertexData[startIndex].Y)
|
||||
|
||||
// The edge may clip to both left and right.
|
||||
// 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
|
||||
// ignored.
|
||||
|
||||
// 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
|
||||
// clip flags of the vertex later, so they are initialized here.
|
||||
var clipVertices [2]VertexData
|
||||
|
||||
if vertexData[startIndex].X <
|
||||
vertexData[endIndex].X {
|
||||
clipVertices[0].X = clipBound[0]
|
||||
clipVertices[1].X = clipBound[2]
|
||||
clipVertices[0].ClipFlags = POLYGON_CLIP_LEFT
|
||||
clipVertices[1].ClipFlags = POLYGON_CLIP_RIGHT
|
||||
} else {
|
||||
clipVertices[0].X = clipBound[2]
|
||||
clipVertices[1].X = clipBound[0]
|
||||
clipVertices[0].ClipFlags = POLYGON_CLIP_RIGHT
|
||||
clipVertices[1].ClipFlags = POLYGON_CLIP_LEFT
|
||||
}
|
||||
|
||||
var p int
|
||||
for p = 0; p < 2; p++ {
|
||||
// Check if either of the vertices crosses the edge marked for the clip vertex
|
||||
if clipSum&clipVertices[p].ClipFlags != 0 {
|
||||
// The the vertex is required, calculate it.
|
||||
clipVertices[p].Y = vertexData[startIndex].Y +
|
||||
(clipVertices[p].X-
|
||||
vertexData[startIndex].X)/slope
|
||||
|
||||
// If there is clipping in the vertical direction, the new vertex may be clipped.
|
||||
if clipSum&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) != 0 {
|
||||
if clipVertices[p].Y < clipBound[1] {
|
||||
clipVertices[p].ClipFlags = POLYGON_CLIP_TOP
|
||||
clipVertices[p].Line = int(clipBound[1])
|
||||
} else if clipVertices[p].Y > clipBound[3] {
|
||||
clipVertices[p].ClipFlags = POLYGON_CLIP_BOTTOM
|
||||
clipVertices[p].Line = int(clipBound[3] - 1)
|
||||
} else {
|
||||
clipVertices[p].ClipFlags = 0
|
||||
clipVertices[p].Line = int(clipVertices[p].Y+1) - 1
|
||||
}
|
||||
} else {
|
||||
clipVertices[p].ClipFlags = 0
|
||||
clipVertices[p].Line = int(clipVertices[p].Y+1) - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// clip flags.
|
||||
// -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 the line of two vertices is the same, the edge is not generated, since the edge doesn't
|
||||
// cross any scanlines.
|
||||
|
||||
// The alternative patterns are:
|
||||
// start - clip0 - clip1 - end
|
||||
// start - clip0 - end
|
||||
// start - clip1 - end
|
||||
|
||||
var topClipIndex, bottomClipIndex int
|
||||
if (clipVertices[0].ClipFlags|clipVertices[1].ClipFlags)&
|
||||
(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) == 0 {
|
||||
// Both sides are clipped, the order is start-clip0-clip1-end
|
||||
topClipIndex = 0
|
||||
bottomClipIndex = 1
|
||||
|
||||
// Add the edge from clip0 to clip1
|
||||
// Check that the line is different for the vertices.
|
||||
if clipVertices[0].Line != clipVertices[1].Line {
|
||||
firstClipLine := clipVertices[0].Line + 1
|
||||
|
||||
startx := vertexData[startIndex].X +
|
||||
(float64(firstClipLine)-vertexData[startIndex].Y)*slope
|
||||
|
||||
edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].FirstLine = firstClipLine
|
||||
edges[edgeCount].LastLine = clipVertices[1].Line
|
||||
edges[edgeCount].Winding = winding
|
||||
|
||||
if edges[edgeCount].LastLine-edges[edgeCount].FirstLine >= SLOPE_FIX_STEP {
|
||||
edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
|
||||
edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
|
||||
} else {
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
}
|
||||
|
||||
edgeCount++
|
||||
}
|
||||
} else {
|
||||
// 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.
|
||||
if clipVertices[0].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
|
||||
topClipIndex = 1
|
||||
bottomClipIndex = 1
|
||||
} else {
|
||||
topClipIndex = 0
|
||||
bottomClipIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// clipped vertex.
|
||||
|
||||
// Check that the line is different for the vertices.
|
||||
if vertexData[startIndex].Line != clipVertices[topClipIndex].Line {
|
||||
edges[edgeCount].FirstLine = firstLine
|
||||
edges[edgeCount].LastLine = clipVertices[topClipIndex].Line
|
||||
edges[edgeCount].Winding = winding
|
||||
|
||||
// If startIndex is clipped, the edge is a vertical one.
|
||||
if vertexData[startIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
|
||||
edges[edgeCount].X = Fix(clipVertices[topClipIndex].X * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = 0
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
} else {
|
||||
startx := vertexData[startIndex].X +
|
||||
(float64(firstLine)-vertexData[startIndex].Y)*slope
|
||||
|
||||
edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
|
||||
|
||||
if edges[edgeCount].LastLine-edges[edgeCount].FirstLine >= SLOPE_FIX_STEP {
|
||||
edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
|
||||
edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
|
||||
} else {
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
}
|
||||
}
|
||||
|
||||
edgeCount++
|
||||
}
|
||||
|
||||
// Check that the line is different for the vertices.
|
||||
if clipVertices[bottomClipIndex].Line != vertexData[endIndex].Line {
|
||||
firstClipLine := clipVertices[bottomClipIndex].Line + 1
|
||||
|
||||
edges[edgeCount].FirstLine = firstClipLine
|
||||
edges[edgeCount].LastLine = lastLine
|
||||
edges[edgeCount].Winding = winding
|
||||
|
||||
// If endIndex is clipped, the edge is a vertical one.
|
||||
if vertexData[endIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
|
||||
edges[edgeCount].X = Fix(clipVertices[bottomClipIndex].X * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = 0
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
} else {
|
||||
startx := vertexData[startIndex].X +
|
||||
(float64(firstClipLine)-vertexData[startIndex].Y)*slope
|
||||
|
||||
edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
|
||||
edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
|
||||
|
||||
if edges[edgeCount].LastLine-edges[edgeCount].FirstLine >= SLOPE_FIX_STEP {
|
||||
edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) -
|
||||
edges[edgeCount].Slope<<SLOPE_FIX_SHIFT
|
||||
} else {
|
||||
edges[edgeCount].SlopeFix = 0
|
||||
}
|
||||
}
|
||||
|
||||
edgeCount++
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return edgeCount
|
||||
}
|
||||
|
|
|
@ -1,157 +1,201 @@
|
|||
package raster
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"log"
|
||||
"image"
|
||||
"os"
|
||||
"bufio"
|
||||
"image/png"
|
||||
"draw2d.googlecode.com/hg/draw2d/curve"
|
||||
"freetype-go.googlecode.com/hg/freetype/raster"
|
||||
)
|
||||
|
||||
var flattening_threshold float64 = 0.5
|
||||
|
||||
func savepng(filePath string, m image.Image) {
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
b := bufio.NewWriter(f)
|
||||
err = png.Encode(b, m)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
type Path struct {
|
||||
points []float64
|
||||
}
|
||||
|
||||
func (p *Path) LineTo(x, y float64) {
|
||||
if len(p.points)+2 > cap(p.points) {
|
||||
points := make([]float64, len(p.points)+2, len(p.points)+32)
|
||||
copy(points, p.points)
|
||||
p.points = points
|
||||
} else {
|
||||
p.points = p.points[0 : len(p.points)+2]
|
||||
}
|
||||
p.points[len(p.points)-2] = x
|
||||
p.points[len(p.points)-1] = y
|
||||
}
|
||||
|
||||
func TestFreetype(t *testing.T) {
|
||||
var p Path
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := raster.NewRasterizer(200, 200)
|
||||
rasterizer.UseNonZeroWinding = false
|
||||
rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
|
||||
for j := 0; j < len(poly); j = j + 2 {
|
||||
rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
|
||||
}
|
||||
painter := raster.NewRGBAPainter(img)
|
||||
painter.SetColor(color)
|
||||
rasterizer.Rasterize(painter)
|
||||
|
||||
savepng("_testFreetype.png", img)
|
||||
}
|
||||
|
||||
func TestRasterizer(t *testing.T) {
|
||||
img := image.NewRGBA(200, 200)
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
r := NewRasterizer8BitsSample(200, 200)
|
||||
package raster
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"log"
|
||||
"image"
|
||||
"os"
|
||||
"bufio"
|
||||
"image/png"
|
||||
"draw2d.googlecode.com/hg/draw2d/curve"
|
||||
"freetype-go.googlecode.com/hg/freetype/raster"
|
||||
)
|
||||
|
||||
var flattening_threshold float64 = 0.5
|
||||
|
||||
func savepng(filePath string, m image.Image) {
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
b := bufio.NewWriter(f)
|
||||
err = png.Encode(b, m)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
type Path struct {
|
||||
points []float64
|
||||
}
|
||||
|
||||
func (p *Path) LineTo(x, y float64) {
|
||||
if len(p.points)+2 > cap(p.points) {
|
||||
points := make([]float64, len(p.points)+2, len(p.points)+32)
|
||||
copy(points, p.points)
|
||||
p.points = points
|
||||
} else {
|
||||
p.points = p.points[0 : len(p.points)+2]
|
||||
}
|
||||
p.points[len(p.points)-2] = x
|
||||
p.points[len(p.points)-1] = y
|
||||
}
|
||||
|
||||
func TestFreetype(t *testing.T) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := raster.NewRasterizer(200, 200)
|
||||
rasterizer.UseNonZeroWinding = false
|
||||
rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
|
||||
for j := 0; j < len(poly); j = j + 2 {
|
||||
rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
|
||||
}
|
||||
painter := raster.NewRGBAPainter(img)
|
||||
painter.SetColor(color)
|
||||
rasterizer.Rasterize(painter)
|
||||
|
||||
savepng("_testFreetype.png", img)
|
||||
}
|
||||
|
||||
func TestFreetypeNonZeroWinding(t *testing.T) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := raster.NewRasterizer(200, 200)
|
||||
rasterizer.UseNonZeroWinding = true
|
||||
rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
|
||||
for j := 0; j < len(poly); j = j + 2 {
|
||||
rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
|
||||
}
|
||||
painter := raster.NewRGBAPainter(img)
|
||||
painter.SetColor(color)
|
||||
rasterizer.Rasterize(painter)
|
||||
|
||||
savepng("_testFreetypeNonZeroWinding.png", img)
|
||||
}
|
||||
|
||||
func TestRasterizer(t *testing.T) {
|
||||
img := image.NewRGBA(200, 200)
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
r := NewRasterizer8BitsSample(200, 200)
|
||||
//PolylineBresenham(img, image.Black, poly...)
|
||||
|
||||
|
||||
r.RenderEvenOdd(img, &color, &poly, tr)
|
||||
savepng("_testRasterizer.png", img)
|
||||
}
|
||||
|
||||
func TestRasterizerNonZeroWinding(t *testing.T) {
|
||||
img := image.NewRGBA(200, 200)
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
r := NewRasterizer8BitsSample(200, 200)
|
||||
|
||||
|
||||
r.RenderEvenOdd(img, &color, &poly, tr)
|
||||
savepng("_testRasterizer.png", img)
|
||||
}
|
||||
|
||||
func TestRasterizerNonZeroWinding(t *testing.T) {
|
||||
img := image.NewRGBA(200, 200)
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
r := NewRasterizer8BitsSample(200, 200)
|
||||
//PolylineBresenham(img, image.Black, poly...)
|
||||
|
||||
|
||||
r.RenderNonZeroWinding(img, &color, &poly, tr)
|
||||
savepng("_testRasterizerNonZeroWinding.png", img)
|
||||
}
|
||||
|
||||
func BenchmarkFreetype(b *testing.B) {
|
||||
var p Path
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := raster.NewRasterizer(200, 200)
|
||||
rasterizer.UseNonZeroWinding = false
|
||||
rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
|
||||
for j := 0; j < len(poly); j = j + 2 {
|
||||
rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
|
||||
}
|
||||
painter := raster.NewRGBAPainter(img)
|
||||
painter.SetColor(color)
|
||||
rasterizer.Rasterize(painter)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRasterizerNonZeroWinding(b *testing.B) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
for i := 0; i < b.N; i++ {
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := NewRasterizer8BitsSample(200, 200)
|
||||
rasterizer.RenderNonZeroWinding(img, &color, &poly, tr)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRasterizer(b *testing.B) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
for i := 0; i < b.N; i++ {
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := NewRasterizer8BitsSample(200, 200)
|
||||
rasterizer.RenderEvenOdd(img, &color, &poly, tr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
r.RenderNonZeroWinding(img, &color, &poly, tr)
|
||||
savepng("_testRasterizerNonZeroWinding.png", img)
|
||||
}
|
||||
|
||||
func BenchmarkFreetype(b *testing.B) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := raster.NewRasterizer(200, 200)
|
||||
rasterizer.UseNonZeroWinding = false
|
||||
rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
|
||||
for j := 0; j < len(poly); j = j + 2 {
|
||||
rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
|
||||
}
|
||||
painter := raster.NewRGBAPainter(img)
|
||||
painter.SetColor(color)
|
||||
rasterizer.Rasterize(painter)
|
||||
}
|
||||
}
|
||||
func BenchmarkFreetypeNonZeroWinding(b *testing.B) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := raster.NewRasterizer(200, 200)
|
||||
rasterizer.UseNonZeroWinding = true
|
||||
rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)})
|
||||
for j := 0; j < len(poly); j = j + 2 {
|
||||
rasterizer.Add1(raster.Point{raster.Fix32(poly[j] * 256), raster.Fix32(poly[j+1] * 256)})
|
||||
}
|
||||
painter := raster.NewRGBAPainter(img)
|
||||
painter.SetColor(color)
|
||||
rasterizer.Rasterize(painter)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRasterizerNonZeroWinding(b *testing.B) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
for i := 0; i < b.N; i++ {
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := NewRasterizer8BitsSample(200, 200)
|
||||
rasterizer.RenderNonZeroWinding(img, &color, &poly, tr)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRasterizer(b *testing.B) {
|
||||
var p Path
|
||||
p.LineTo(10, 190)
|
||||
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
|
||||
c.Segment(&p, flattening_threshold)
|
||||
poly := Polygon(p.points)
|
||||
color := image.RGBAColor{0, 0, 0, 0xff}
|
||||
tr := [6]float64{1, 0, 0, 1, 0, 0}
|
||||
for i := 0; i < b.N; i++ {
|
||||
img := image.NewRGBA(200, 200)
|
||||
rasterizer := NewRasterizer8BitsSample(200, 200)
|
||||
rasterizer.RenderEvenOdd(img, &color, &poly, tr)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue