fill with winding rule
This commit is contained in:
parent
25f7be3323
commit
eaa2454bb3
5 changed files with 606 additions and 449 deletions
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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])
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue