fill with winding rule

This commit is contained in:
Laurent Le Goff 2011-05-27 18:19:42 +02:00
parent 25f7be3323
commit eaa2454bb3
5 changed files with 606 additions and 449 deletions

View file

@ -1,135 +1,135 @@
// 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{
5 / 8, 0 / 8, 5 / 8, 0 / 8,
3 / 8, 6 / 8, 3 / 8, 6 / 8,
1 / 8, 4 / 8, 1 / 8, 4 / 8,
7 / 8, 2 / 8, 7 / 8, 2 / 8,
} }
var SUBPIXEL_OFFSETS_SAMPLE_16 = [16]float64{ var SUBPIXEL_OFFSETS_SAMPLE_16 = [16]float64{
(1 / 16), (1 / 16),
(8 / 16), (8 / 16),
(4 / 16), (4 / 16),
(15 / 16), (15 / 16),
(11 / 16), (11 / 16),
(2 / 16), (2 / 16),
(6 / 16), (6 / 16),
(14 / 16), (14 / 16),
(10 / 16), (10 / 16),
(3 / 16), (3 / 16),
(7 / 16), (7 / 16),
(12 / 16), (12 / 16),
(0 / 16), (0 / 16),
(9 / 16), (9 / 16),
(5 / 16), (5 / 16),
(13 / 16), (13 / 16),
} }
var SUBPIXEL_OFFSETS_SAMPLE_32 = [32]float64{ var SUBPIXEL_OFFSETS_SAMPLE_32 = [32]float64{
28 / 32, 28 / 32,
13 / 32, 13 / 32,
6 / 32, 6 / 32,
23 / 32, 23 / 32,
0 / 32, 0 / 32,
17 / 32, 17 / 32,
10 / 32, 10 / 32,
27 / 32, 27 / 32,
4 / 32, 4 / 32,
21 / 32, 21 / 32,
14 / 32, 14 / 32,
31 / 32, 31 / 32,
8 / 32, 8 / 32,
25 / 32, 25 / 32,
18 / 32, 18 / 32,
3 / 32, 3 / 32,
12 / 32, 12 / 32,
29 / 32, 29 / 32,
22 / 32, 22 / 32,
7 / 32, 7 / 32,
16 / 32, 16 / 32,
1 / 32, 1 / 32,
26 / 32, 26 / 32,
11 / 32, 11 / 32,
20 / 32, 20 / 32,
5 / 32, 5 / 32,
30 / 32, 30 / 32,
15 / 32, 15 / 32,
24 / 32, 24 / 32,
9 / 32, 9 / 32,
2 / 32, 2 / 32,
19 / 32, 19 / 32,
} }
var coverageTable = [256]uint8{ var coverageTable = [256]uint8{
pixelCoverage(0x00), pixelCoverage(0x01), pixelCoverage(0x02), pixelCoverage(0x03), pixelCoverage(0x00), pixelCoverage(0x01), pixelCoverage(0x02), pixelCoverage(0x03),
pixelCoverage(0x04), pixelCoverage(0x05), pixelCoverage(0x06), pixelCoverage(0x07), pixelCoverage(0x04), pixelCoverage(0x05), pixelCoverage(0x06), pixelCoverage(0x07),
pixelCoverage(0x08), pixelCoverage(0x09), pixelCoverage(0x0a), pixelCoverage(0x0b), pixelCoverage(0x08), pixelCoverage(0x09), pixelCoverage(0x0a), pixelCoverage(0x0b),
pixelCoverage(0x0c), pixelCoverage(0x0d), pixelCoverage(0x0e), pixelCoverage(0x0f), pixelCoverage(0x0c), pixelCoverage(0x0d), pixelCoverage(0x0e), pixelCoverage(0x0f),
pixelCoverage(0x10), pixelCoverage(0x11), pixelCoverage(0x12), pixelCoverage(0x13), pixelCoverage(0x10), pixelCoverage(0x11), pixelCoverage(0x12), pixelCoverage(0x13),
pixelCoverage(0x14), pixelCoverage(0x15), pixelCoverage(0x16), pixelCoverage(0x17), pixelCoverage(0x14), pixelCoverage(0x15), pixelCoverage(0x16), pixelCoverage(0x17),
pixelCoverage(0x18), pixelCoverage(0x19), pixelCoverage(0x1a), pixelCoverage(0x1b), pixelCoverage(0x18), pixelCoverage(0x19), pixelCoverage(0x1a), pixelCoverage(0x1b),
pixelCoverage(0x1c), pixelCoverage(0x1d), pixelCoverage(0x1e), pixelCoverage(0x1f), pixelCoverage(0x1c), pixelCoverage(0x1d), pixelCoverage(0x1e), pixelCoverage(0x1f),
pixelCoverage(0x20), pixelCoverage(0x21), pixelCoverage(0x22), pixelCoverage(0x23), pixelCoverage(0x20), pixelCoverage(0x21), pixelCoverage(0x22), pixelCoverage(0x23),
pixelCoverage(0x24), pixelCoverage(0x25), pixelCoverage(0x26), pixelCoverage(0x27), pixelCoverage(0x24), pixelCoverage(0x25), pixelCoverage(0x26), pixelCoverage(0x27),
pixelCoverage(0x28), pixelCoverage(0x29), pixelCoverage(0x2a), pixelCoverage(0x2b), pixelCoverage(0x28), pixelCoverage(0x29), pixelCoverage(0x2a), pixelCoverage(0x2b),
pixelCoverage(0x2c), pixelCoverage(0x2d), pixelCoverage(0x2e), pixelCoverage(0x2f), pixelCoverage(0x2c), pixelCoverage(0x2d), pixelCoverage(0x2e), pixelCoverage(0x2f),
pixelCoverage(0x30), pixelCoverage(0x31), pixelCoverage(0x32), pixelCoverage(0x33), pixelCoverage(0x30), pixelCoverage(0x31), pixelCoverage(0x32), pixelCoverage(0x33),
pixelCoverage(0x34), pixelCoverage(0x35), pixelCoverage(0x36), pixelCoverage(0x37), pixelCoverage(0x34), pixelCoverage(0x35), pixelCoverage(0x36), pixelCoverage(0x37),
pixelCoverage(0x38), pixelCoverage(0x39), pixelCoverage(0x3a), pixelCoverage(0x3b), pixelCoverage(0x38), pixelCoverage(0x39), pixelCoverage(0x3a), pixelCoverage(0x3b),
pixelCoverage(0x3c), pixelCoverage(0x3d), pixelCoverage(0x3e), pixelCoverage(0x3f), pixelCoverage(0x3c), pixelCoverage(0x3d), pixelCoverage(0x3e), pixelCoverage(0x3f),
pixelCoverage(0x40), pixelCoverage(0x41), pixelCoverage(0x42), pixelCoverage(0x43), pixelCoverage(0x40), pixelCoverage(0x41), pixelCoverage(0x42), pixelCoverage(0x43),
pixelCoverage(0x44), pixelCoverage(0x45), pixelCoverage(0x46), pixelCoverage(0x47), pixelCoverage(0x44), pixelCoverage(0x45), pixelCoverage(0x46), pixelCoverage(0x47),
pixelCoverage(0x48), pixelCoverage(0x49), pixelCoverage(0x4a), pixelCoverage(0x4b), pixelCoverage(0x48), pixelCoverage(0x49), pixelCoverage(0x4a), pixelCoverage(0x4b),
pixelCoverage(0x4c), pixelCoverage(0x4d), pixelCoverage(0x4e), pixelCoverage(0x4f), pixelCoverage(0x4c), pixelCoverage(0x4d), pixelCoverage(0x4e), pixelCoverage(0x4f),
pixelCoverage(0x50), pixelCoverage(0x51), pixelCoverage(0x52), pixelCoverage(0x53), pixelCoverage(0x50), pixelCoverage(0x51), pixelCoverage(0x52), pixelCoverage(0x53),
pixelCoverage(0x54), pixelCoverage(0x55), pixelCoverage(0x56), pixelCoverage(0x57), pixelCoverage(0x54), pixelCoverage(0x55), pixelCoverage(0x56), pixelCoverage(0x57),
pixelCoverage(0x58), pixelCoverage(0x59), pixelCoverage(0x5a), pixelCoverage(0x5b), pixelCoverage(0x58), pixelCoverage(0x59), pixelCoverage(0x5a), pixelCoverage(0x5b),
pixelCoverage(0x5c), pixelCoverage(0x5d), pixelCoverage(0x5e), pixelCoverage(0x5f), pixelCoverage(0x5c), pixelCoverage(0x5d), pixelCoverage(0x5e), pixelCoverage(0x5f),
pixelCoverage(0x60), pixelCoverage(0x61), pixelCoverage(0x62), pixelCoverage(0x63), pixelCoverage(0x60), pixelCoverage(0x61), pixelCoverage(0x62), pixelCoverage(0x63),
pixelCoverage(0x64), pixelCoverage(0x65), pixelCoverage(0x66), pixelCoverage(0x67), pixelCoverage(0x64), pixelCoverage(0x65), pixelCoverage(0x66), pixelCoverage(0x67),
pixelCoverage(0x68), pixelCoverage(0x69), pixelCoverage(0x6a), pixelCoverage(0x6b), pixelCoverage(0x68), pixelCoverage(0x69), pixelCoverage(0x6a), pixelCoverage(0x6b),
pixelCoverage(0x6c), pixelCoverage(0x6d), pixelCoverage(0x6e), pixelCoverage(0x6f), pixelCoverage(0x6c), pixelCoverage(0x6d), pixelCoverage(0x6e), pixelCoverage(0x6f),
pixelCoverage(0x70), pixelCoverage(0x71), pixelCoverage(0x72), pixelCoverage(0x73), pixelCoverage(0x70), pixelCoverage(0x71), pixelCoverage(0x72), pixelCoverage(0x73),
pixelCoverage(0x74), pixelCoverage(0x75), pixelCoverage(0x76), pixelCoverage(0x77), pixelCoverage(0x74), pixelCoverage(0x75), pixelCoverage(0x76), pixelCoverage(0x77),
pixelCoverage(0x78), pixelCoverage(0x79), pixelCoverage(0x7a), pixelCoverage(0x7b), pixelCoverage(0x78), pixelCoverage(0x79), pixelCoverage(0x7a), pixelCoverage(0x7b),
pixelCoverage(0x7c), pixelCoverage(0x7d), pixelCoverage(0x7e), pixelCoverage(0x7f), pixelCoverage(0x7c), pixelCoverage(0x7d), pixelCoverage(0x7e), pixelCoverage(0x7f),
pixelCoverage(0x80), pixelCoverage(0x81), pixelCoverage(0x82), pixelCoverage(0x83), pixelCoverage(0x80), pixelCoverage(0x81), pixelCoverage(0x82), pixelCoverage(0x83),
pixelCoverage(0x84), pixelCoverage(0x85), pixelCoverage(0x86), pixelCoverage(0x87), pixelCoverage(0x84), pixelCoverage(0x85), pixelCoverage(0x86), pixelCoverage(0x87),
pixelCoverage(0x88), pixelCoverage(0x89), pixelCoverage(0x8a), pixelCoverage(0x8b), pixelCoverage(0x88), pixelCoverage(0x89), pixelCoverage(0x8a), pixelCoverage(0x8b),
pixelCoverage(0x8c), pixelCoverage(0x8d), pixelCoverage(0x8e), pixelCoverage(0x8f), pixelCoverage(0x8c), pixelCoverage(0x8d), pixelCoverage(0x8e), pixelCoverage(0x8f),
pixelCoverage(0x90), pixelCoverage(0x91), pixelCoverage(0x92), pixelCoverage(0x93), pixelCoverage(0x90), pixelCoverage(0x91), pixelCoverage(0x92), pixelCoverage(0x93),
pixelCoverage(0x94), pixelCoverage(0x95), pixelCoverage(0x96), pixelCoverage(0x97), pixelCoverage(0x94), pixelCoverage(0x95), pixelCoverage(0x96), pixelCoverage(0x97),
pixelCoverage(0x98), pixelCoverage(0x99), pixelCoverage(0x9a), pixelCoverage(0x9b), pixelCoverage(0x98), pixelCoverage(0x99), pixelCoverage(0x9a), pixelCoverage(0x9b),
pixelCoverage(0x9c), pixelCoverage(0x9d), pixelCoverage(0x9e), pixelCoverage(0x9f), pixelCoverage(0x9c), pixelCoverage(0x9d), pixelCoverage(0x9e), pixelCoverage(0x9f),
pixelCoverage(0xa0), pixelCoverage(0xa1), pixelCoverage(0xa2), pixelCoverage(0xa3), pixelCoverage(0xa0), pixelCoverage(0xa1), pixelCoverage(0xa2), pixelCoverage(0xa3),
pixelCoverage(0xa4), pixelCoverage(0xa5), pixelCoverage(0xa6), pixelCoverage(0xa7), pixelCoverage(0xa4), pixelCoverage(0xa5), pixelCoverage(0xa6), pixelCoverage(0xa7),
pixelCoverage(0xa8), pixelCoverage(0xa9), pixelCoverage(0xaa), pixelCoverage(0xab), pixelCoverage(0xa8), pixelCoverage(0xa9), pixelCoverage(0xaa), pixelCoverage(0xab),
pixelCoverage(0xac), pixelCoverage(0xad), pixelCoverage(0xae), pixelCoverage(0xaf), pixelCoverage(0xac), pixelCoverage(0xad), pixelCoverage(0xae), pixelCoverage(0xaf),
pixelCoverage(0xb0), pixelCoverage(0xb1), pixelCoverage(0xb2), pixelCoverage(0xb3), pixelCoverage(0xb0), pixelCoverage(0xb1), pixelCoverage(0xb2), pixelCoverage(0xb3),
pixelCoverage(0xb4), pixelCoverage(0xb5), pixelCoverage(0xb6), pixelCoverage(0xb7), pixelCoverage(0xb4), pixelCoverage(0xb5), pixelCoverage(0xb6), pixelCoverage(0xb7),
pixelCoverage(0xb8), pixelCoverage(0xb9), pixelCoverage(0xba), pixelCoverage(0xbb), pixelCoverage(0xb8), pixelCoverage(0xb9), pixelCoverage(0xba), pixelCoverage(0xbb),
pixelCoverage(0xbc), pixelCoverage(0xbd), pixelCoverage(0xbe), pixelCoverage(0xbf), pixelCoverage(0xbc), pixelCoverage(0xbd), pixelCoverage(0xbe), pixelCoverage(0xbf),
pixelCoverage(0xc0), pixelCoverage(0xc1), pixelCoverage(0xc2), pixelCoverage(0xc3), pixelCoverage(0xc0), pixelCoverage(0xc1), pixelCoverage(0xc2), pixelCoverage(0xc3),
pixelCoverage(0xc4), pixelCoverage(0xc5), pixelCoverage(0xc6), pixelCoverage(0xc7), pixelCoverage(0xc4), pixelCoverage(0xc5), pixelCoverage(0xc6), pixelCoverage(0xc7),
pixelCoverage(0xc8), pixelCoverage(0xc9), pixelCoverage(0xca), pixelCoverage(0xcb), pixelCoverage(0xc8), pixelCoverage(0xc9), pixelCoverage(0xca), pixelCoverage(0xcb),
pixelCoverage(0xcc), pixelCoverage(0xcd), pixelCoverage(0xce), pixelCoverage(0xcf), pixelCoverage(0xcc), pixelCoverage(0xcd), pixelCoverage(0xce), pixelCoverage(0xcf),
pixelCoverage(0xd0), pixelCoverage(0xd1), pixelCoverage(0xd2), pixelCoverage(0xd3), pixelCoverage(0xd0), pixelCoverage(0xd1), pixelCoverage(0xd2), pixelCoverage(0xd3),
pixelCoverage(0xd4), pixelCoverage(0xd5), pixelCoverage(0xd6), pixelCoverage(0xd7), pixelCoverage(0xd4), pixelCoverage(0xd5), pixelCoverage(0xd6), pixelCoverage(0xd7),
pixelCoverage(0xd8), pixelCoverage(0xd9), pixelCoverage(0xda), pixelCoverage(0xdb), pixelCoverage(0xd8), pixelCoverage(0xd9), pixelCoverage(0xda), pixelCoverage(0xdb),
pixelCoverage(0xdc), pixelCoverage(0xdd), pixelCoverage(0xde), pixelCoverage(0xdf), pixelCoverage(0xdc), pixelCoverage(0xdd), pixelCoverage(0xde), pixelCoverage(0xdf),
pixelCoverage(0xe0), pixelCoverage(0xe1), pixelCoverage(0xe2), pixelCoverage(0xe3), pixelCoverage(0xe0), pixelCoverage(0xe1), pixelCoverage(0xe2), pixelCoverage(0xe3),
pixelCoverage(0xe4), pixelCoverage(0xe5), pixelCoverage(0xe6), pixelCoverage(0xe7), pixelCoverage(0xe4), pixelCoverage(0xe5), pixelCoverage(0xe6), pixelCoverage(0xe7),
pixelCoverage(0xe8), pixelCoverage(0xe9), pixelCoverage(0xea), pixelCoverage(0xeb), pixelCoverage(0xe8), pixelCoverage(0xe9), pixelCoverage(0xea), pixelCoverage(0xeb),
pixelCoverage(0xec), pixelCoverage(0xed), pixelCoverage(0xee), pixelCoverage(0xef), pixelCoverage(0xec), pixelCoverage(0xed), pixelCoverage(0xee), pixelCoverage(0xef),
pixelCoverage(0xf0), pixelCoverage(0xf1), pixelCoverage(0xf2), pixelCoverage(0xf3), pixelCoverage(0xf0), pixelCoverage(0xf1), pixelCoverage(0xf2), pixelCoverage(0xf3),
pixelCoverage(0xf4), pixelCoverage(0xf5), pixelCoverage(0xf6), pixelCoverage(0xf7), pixelCoverage(0xf4), pixelCoverage(0xf5), pixelCoverage(0xf6), pixelCoverage(0xf7),
pixelCoverage(0xf8), pixelCoverage(0xf9), pixelCoverage(0xfa), pixelCoverage(0xfb), pixelCoverage(0xf8), pixelCoverage(0xf9), pixelCoverage(0xfa), pixelCoverage(0xfb),
pixelCoverage(0xfc), pixelCoverage(0xfd), pixelCoverage(0xfe), pixelCoverage(0xff), pixelCoverage(0xfc), pixelCoverage(0xfd), pixelCoverage(0xfe), pixelCoverage(0xff),
} }
func pixelCoverage(a uint8) 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))
} }

View file

@ -8,11 +8,11 @@ import (
) )
const ( const (
SUBPIXEL_SHIFT = 3 SUBPIXEL_SHIFT = 4
SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT
) )
var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8 var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_16
type SUBPIXEL_DATA uint16 type SUBPIXEL_DATA uint16
type NON_ZERO_MASK_DATA_UNIT uint8 type NON_ZERO_MASK_DATA_UNIT uint8
@ -105,13 +105,13 @@ func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBA
clipRect = intersect(clipRect, r.ClipBound) clipRect = intersect(clipRect, r.ClipBound)
p := 0 p := 0
l := len(*polygon) / 2 l := len(*polygon) / 2
var edges [32]PolygonEdge
for p < l { for p < l {
var edges [20]PolygonEdge edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect)
edgeCount := polygon.getEdges(p, 10, edges[:], transform, clipRect)
for k := 0; k < edgeCount; k++ { for k := 0; k < edgeCount; k++ {
r.addEvenOddEdge(&(edges[k])) r.addEvenOddEdge(&(edges[k]))
} }
p += 10 p += 16
} }
r.fillEvenOdd(img, color, clipRect) r.fillEvenOdd(img, color, clipRect)
@ -121,11 +121,13 @@ func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBA
func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) {
x := edge.X x := edge.X
slope := edge.Slope slope := edge.Slope
var ySub, mask SUBPIXEL_DATA
var xp, yLine int
for y := edge.FirstLine; y <= edge.LastLine; y++ { for y := edge.FirstLine; y <= edge.LastLine; y++ {
ySub := SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1)) ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1))
xp := (int)(x + SUBPIXEL_OFFSETS[ySub]) xp = (int)(x + SUBPIXEL_OFFSETS[ySub])
mask := SUBPIXEL_DATA(1 << ySub) mask = SUBPIXEL_DATA(1 << ySub)
yLine := y >> SUBPIXEL_SHIFT yLine = y >> SUBPIXEL_SHIFT
r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask
x += slope x += slope
} }
@ -157,9 +159,131 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBACo
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
//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)
}
//! 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
}
}
//! 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 // 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])

View file

@ -1,55 +1,55 @@
// 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 (
"exp/draw" "exp/draw"
"image" "image"
) )
func abs(i int) int { func abs(i int) int {
if i < 0 { if i < 0 {
return -i return -i
} }
return i return i
} }
func PolylineBresenham(img draw.Image, c image.Color, s ...float64) { func PolylineBresenham(img draw.Image, c image.Color, s ...float64) {
for i := 2; i < len(s); i += 2 { for i := 2; i < len(s); i += 2 {
Bresenham(img, c, int(s[i-2]+0.5), int(s[i-1]+0.5), int(s[i]+0.5), int(s[i+1]+0.5)) Bresenham(img, c, int(s[i-2]+0.5), int(s[i-1]+0.5), int(s[i]+0.5), int(s[i+1]+0.5))
} }
} }
func Bresenham(img draw.Image, color image.Color, x0, y0, x1, y1 int) { func Bresenham(img draw.Image, color image.Color, x0, y0, x1, y1 int) {
dx := abs(x1 - x0) dx := abs(x1 - x0)
dy := abs(y1 - y0) dy := abs(y1 - y0)
var sx, sy int var sx, sy int
if x0 < x1 { if x0 < x1 {
sx = 1 sx = 1
} else { } else {
sx = -1 sx = -1
} }
if y0 < y1 { if y0 < y1 {
sy = 1 sy = 1
} else { } else {
sy = -1 sy = -1
} }
err := dx - dy err := dx - dy
var e2 int var e2 int
for { for {
img.Set(x0, y0, color) img.Set(x0, y0, color)
if x0 == x1 && y0 == y1 { if x0 == x1 && y0 == y1 {
return return
} }
e2 = 2 * err e2 = 2 * err
if e2 > -dy { if e2 > -dy {
err = err - dy err = err - dy
x0 = x0 + sx x0 = x0 + sx
} }
if e2 < dx { if e2 < dx {
err = err + dx err = err + dx
y0 = y0 + sy y0 = y0 + sy
} }
} }
} }

View file

@ -1,29 +1,29 @@
// 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 (
"math" "math"
) )
const ( const (
POLYGON_CLIP_NONE = iota POLYGON_CLIP_NONE = iota
POLYGON_CLIP_LEFT POLYGON_CLIP_LEFT
POLYGON_CLIP_RIGHT POLYGON_CLIP_RIGHT
POLYGON_CLIP_TOP POLYGON_CLIP_TOP
POLYGON_CLIP_BOTTOM POLYGON_CLIP_BOTTOM
) )
type Polygon []float64 type Polygon []float64
type PolygonEdge struct { type PolygonEdge struct {
X, Slope float64 X, Slope float64
FirstLine, LastLine int FirstLine, LastLine int
Winding int16 Winding int16
} }
//! 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.
@ -31,159 +31,159 @@ type PolygonEdge struct {
* \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
endIndex := startIndex + (vertexCount * 2) endIndex := startIndex + (vertexCount * 2)
if endIndex > len(p) { if endIndex > len(p) {
endIndex = len(p) endIndex = len(p)
} }
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
} else if prevX >= clipBound[2] { } else if prevX >= clipBound[2] {
prevClipFlags |= POLYGON_CLIP_RIGHT prevClipFlags |= POLYGON_CLIP_RIGHT
} }
if prevY < clipBound[1] { if prevY < clipBound[1] {
prevClipFlags |= POLYGON_CLIP_TOP prevClipFlags |= POLYGON_CLIP_TOP
} else if prevY >= clipBound[3] { } else if prevY >= clipBound[3] {
prevClipFlags |= POLYGON_CLIP_BOTTOM prevClipFlags |= POLYGON_CLIP_BOTTOM
} }
edgeCount := 0 edgeCount := 0
var k, clipFlags, clipSum, clipUnion int var k, clipFlags, clipSum, clipUnion int
var xleft, yleft, xright, yright, oldY, maxX, minX float64 var xleft, yleft, xright, yright, oldY, maxX, minX float64
var swapWinding int16 var swapWinding int16
for n := startIndex; n < endIndex; n = n + 2 { for n := startIndex; n < endIndex; n = n + 2 {
k = (n + 2) % len(p) k = (n + 2) % len(p)
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
} else if prevX >= clipBound[2] { } else if prevX >= clipBound[2] {
clipFlags |= POLYGON_CLIP_RIGHT clipFlags |= POLYGON_CLIP_RIGHT
} }
if prevY < clipBound[1] { if prevY < clipBound[1] {
clipFlags |= POLYGON_CLIP_TOP clipFlags |= POLYGON_CLIP_TOP
} else if prevY >= clipBound[3] { } else if prevY >= clipBound[3] {
clipFlags |= POLYGON_CLIP_BOTTOM clipFlags |= POLYGON_CLIP_BOTTOM
} }
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
xright, yright = prevX, prevY xright, yright = prevX, prevY
swapWinding = -1 swapWinding = -1
} else { } else {
xleft, yleft = prevX, prevY xleft, yleft = prevX, prevY
xright, yright = x, y xright, yright = x, y
swapWinding = 1 swapWinding = 1
} }
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++
} }
} }
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++
} }
} }
if getEdge(xleft, yleft, xright, yright, &(edges[edgeCount]), clipBound) { if getEdge(xleft, yleft, xright, yright, &(edges[edgeCount]), clipBound) {
edges[edgeCount].Winding *= swapWinding edges[edgeCount].Winding *= swapWinding
edgeCount++ edgeCount++
} }
} }
} }
prevClipFlags = clipFlags prevClipFlags = clipFlags
prevX = x prevX = x
prevY = y prevY = y
} }
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
var winding int16 var winding int16
if y0 <= y1 { if y0 <= y1 {
startX = x0 startX = x0
startY = y0 startY = y0
endX = x1 endX = x1
endY = y1 endY = y1
winding = 1 winding = 1
} else { } else {
startX = x1 startX = x1
startY = y1 startY = y1
endX = x0 endX = x0
endY = y0 endY = y0
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
@ -191,83 +191,83 @@ func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bo
// 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(math.Floor(startY)) + 1 firstLine := int(math.Floor(startY)) + 1
lastLine := int(math.Floor(endY)) lastLine := int(math.Floor(endY))
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
} }
if lastLine >= maxClip { if lastLine >= maxClip {
lastLine = maxClip - 1 lastLine = maxClip - 1
} }
edge.Slope = (endX - startX) / (endY - startY) edge.Slope = (endX - startX) / (endY - startY)
edge.X = startX + (float64(firstLine)-startY)*edge.Slope edge.X = startX + (float64(firstLine)-startY)*edge.Slope
edge.Winding = winding edge.Winding = winding
edge.FirstLine = firstLine edge.FirstLine = firstLine
edge.LastLine = lastLine edge.LastLine = lastLine
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
var winding int16 var winding int16
if startY < endY { if startY < endY {
start = startY start = startY
end = endY end = endY
winding = 1 winding = 1
} else { } else {
start = endY start = endY
end = startY end = startY
winding = -1 winding = -1
} }
firstLine := int(math.Floor(start)) + 1 firstLine := int(math.Floor(start)) + 1
lastLine := int(math.Floor(end)) lastLine := int(math.Floor(end))
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
} }
if lastLine >= maxClip { if lastLine >= maxClip {
lastLine = maxClip - 1 lastLine = maxClip - 1
} }
edge.Slope = 0 edge.Slope = 0
edge.X = x edge.X = x
edge.Winding = winding edge.Winding = winding
edge.FirstLine = firstLine edge.FirstLine = firstLine
edge.LastLine = lastLine edge.LastLine = lastLine
return true return true
} }

View file

@ -49,23 +49,6 @@ func (p *Path) LineTo(x, y float64) {
p.points[len(p.points)-1] = y p.points[len(p.points)-1] = y
} }
func TestRasterizer8BitsSample(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("_testRasterizer8BitsSample.png", img)
}
func TestFreetype(t *testing.T) { func TestFreetype(t *testing.T) {
var p Path var p Path
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
@ -87,7 +70,8 @@ func TestFreetype(t *testing.T) {
savepng("_testFreetype.png", img) savepng("_testFreetype.png", img)
} }
func BenchmarkRasterizer8BitsSample(b *testing.B) { func TestRasterizer(t *testing.T) {
img := image.NewRGBA(200, 200)
var p Path var p Path
p.LineTo(10, 190) p.LineTo(10, 190)
c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190}
@ -95,11 +79,29 @@ func BenchmarkRasterizer8BitsSample(b *testing.B) {
poly := Polygon(p.points) poly := Polygon(p.points)
color := image.RGBAColor{0, 0, 0, 0xff} color := image.RGBAColor{0, 0, 0, 0xff}
tr := [6]float64{1, 0, 0, 1, 0, 0} tr := [6]float64{1, 0, 0, 1, 0, 0}
for i := 0; i < b.N; i++ { r := NewRasterizer8BitsSample(200, 200)
img := image.NewRGBA(200, 200) //PolylineBresenham(img, image.Black, poly...)
rasterizer := NewRasterizer8BitsSample(200, 200)
rasterizer.RenderEvenOdd(img, &color, &poly, tr)
} 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) { func BenchmarkFreetype(b *testing.B) {
@ -122,3 +124,34 @@ func BenchmarkFreetype(b *testing.B) {
rasterizer.Rasterize(painter) 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)
}
}