From eaa2454bb3b9d387d29f63c6a6eab7bb5af81f17 Mon Sep 17 00:00:00 2001 From: Laurent Le Goff Date: Fri, 27 May 2011 18:19:42 +0200 Subject: [PATCH] fill with winding rule --- draw2d/raster/coverage_table.go | 266 +++++++++---------- draw2d/raster/fillerAA.go | 146 +++++++++- draw2d/raster/line.go | 106 ++++---- draw2d/raster/polygon.go | 458 ++++++++++++++++---------------- draw2d/raster/raster_test.go | 79 ++++-- 5 files changed, 606 insertions(+), 449 deletions(-) diff --git a/draw2d/raster/coverage_table.go b/draw2d/raster/coverage_table.go index 49bdf51..df33d72 100644 --- a/draw2d/raster/coverage_table.go +++ b/draw2d/raster/coverage_table.go @@ -1,135 +1,135 @@ // Copyright 2011 The draw2d Authors. All rights reserved. // created: 27/05/2011 by Laurent Le Goff -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_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), -} - -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, -} - -var coverageTable = [256]uint8{ - pixelCoverage(0x00), pixelCoverage(0x01), pixelCoverage(0x02), pixelCoverage(0x03), - pixelCoverage(0x04), pixelCoverage(0x05), pixelCoverage(0x06), pixelCoverage(0x07), - pixelCoverage(0x08), pixelCoverage(0x09), pixelCoverage(0x0a), pixelCoverage(0x0b), - pixelCoverage(0x0c), pixelCoverage(0x0d), pixelCoverage(0x0e), pixelCoverage(0x0f), - pixelCoverage(0x10), pixelCoverage(0x11), pixelCoverage(0x12), pixelCoverage(0x13), - pixelCoverage(0x14), pixelCoverage(0x15), pixelCoverage(0x16), pixelCoverage(0x17), - pixelCoverage(0x18), pixelCoverage(0x19), pixelCoverage(0x1a), pixelCoverage(0x1b), - pixelCoverage(0x1c), pixelCoverage(0x1d), pixelCoverage(0x1e), pixelCoverage(0x1f), - pixelCoverage(0x20), pixelCoverage(0x21), pixelCoverage(0x22), pixelCoverage(0x23), - pixelCoverage(0x24), pixelCoverage(0x25), pixelCoverage(0x26), pixelCoverage(0x27), - pixelCoverage(0x28), pixelCoverage(0x29), pixelCoverage(0x2a), pixelCoverage(0x2b), - pixelCoverage(0x2c), pixelCoverage(0x2d), pixelCoverage(0x2e), pixelCoverage(0x2f), - pixelCoverage(0x30), pixelCoverage(0x31), pixelCoverage(0x32), pixelCoverage(0x33), - pixelCoverage(0x34), pixelCoverage(0x35), pixelCoverage(0x36), pixelCoverage(0x37), - pixelCoverage(0x38), pixelCoverage(0x39), pixelCoverage(0x3a), pixelCoverage(0x3b), - pixelCoverage(0x3c), pixelCoverage(0x3d), pixelCoverage(0x3e), pixelCoverage(0x3f), - pixelCoverage(0x40), pixelCoverage(0x41), pixelCoverage(0x42), pixelCoverage(0x43), - pixelCoverage(0x44), pixelCoverage(0x45), pixelCoverage(0x46), pixelCoverage(0x47), - pixelCoverage(0x48), pixelCoverage(0x49), pixelCoverage(0x4a), pixelCoverage(0x4b), - pixelCoverage(0x4c), pixelCoverage(0x4d), pixelCoverage(0x4e), pixelCoverage(0x4f), - pixelCoverage(0x50), pixelCoverage(0x51), pixelCoverage(0x52), pixelCoverage(0x53), - pixelCoverage(0x54), pixelCoverage(0x55), pixelCoverage(0x56), pixelCoverage(0x57), - pixelCoverage(0x58), pixelCoverage(0x59), pixelCoverage(0x5a), pixelCoverage(0x5b), - pixelCoverage(0x5c), pixelCoverage(0x5d), pixelCoverage(0x5e), pixelCoverage(0x5f), - pixelCoverage(0x60), pixelCoverage(0x61), pixelCoverage(0x62), pixelCoverage(0x63), - pixelCoverage(0x64), pixelCoverage(0x65), pixelCoverage(0x66), pixelCoverage(0x67), - pixelCoverage(0x68), pixelCoverage(0x69), pixelCoverage(0x6a), pixelCoverage(0x6b), - pixelCoverage(0x6c), pixelCoverage(0x6d), pixelCoverage(0x6e), pixelCoverage(0x6f), - pixelCoverage(0x70), pixelCoverage(0x71), pixelCoverage(0x72), pixelCoverage(0x73), - pixelCoverage(0x74), pixelCoverage(0x75), pixelCoverage(0x76), pixelCoverage(0x77), - pixelCoverage(0x78), pixelCoverage(0x79), pixelCoverage(0x7a), pixelCoverage(0x7b), - pixelCoverage(0x7c), pixelCoverage(0x7d), pixelCoverage(0x7e), pixelCoverage(0x7f), - pixelCoverage(0x80), pixelCoverage(0x81), pixelCoverage(0x82), pixelCoverage(0x83), - pixelCoverage(0x84), pixelCoverage(0x85), pixelCoverage(0x86), pixelCoverage(0x87), - pixelCoverage(0x88), pixelCoverage(0x89), pixelCoverage(0x8a), pixelCoverage(0x8b), - pixelCoverage(0x8c), pixelCoverage(0x8d), pixelCoverage(0x8e), pixelCoverage(0x8f), - pixelCoverage(0x90), pixelCoverage(0x91), pixelCoverage(0x92), pixelCoverage(0x93), - pixelCoverage(0x94), pixelCoverage(0x95), pixelCoverage(0x96), pixelCoverage(0x97), - pixelCoverage(0x98), pixelCoverage(0x99), pixelCoverage(0x9a), pixelCoverage(0x9b), - pixelCoverage(0x9c), pixelCoverage(0x9d), pixelCoverage(0x9e), pixelCoverage(0x9f), - pixelCoverage(0xa0), pixelCoverage(0xa1), pixelCoverage(0xa2), pixelCoverage(0xa3), - pixelCoverage(0xa4), pixelCoverage(0xa5), pixelCoverage(0xa6), pixelCoverage(0xa7), - pixelCoverage(0xa8), pixelCoverage(0xa9), pixelCoverage(0xaa), pixelCoverage(0xab), - pixelCoverage(0xac), pixelCoverage(0xad), pixelCoverage(0xae), pixelCoverage(0xaf), - pixelCoverage(0xb0), pixelCoverage(0xb1), pixelCoverage(0xb2), pixelCoverage(0xb3), - pixelCoverage(0xb4), pixelCoverage(0xb5), pixelCoverage(0xb6), pixelCoverage(0xb7), - pixelCoverage(0xb8), pixelCoverage(0xb9), pixelCoverage(0xba), pixelCoverage(0xbb), - pixelCoverage(0xbc), pixelCoverage(0xbd), pixelCoverage(0xbe), pixelCoverage(0xbf), - pixelCoverage(0xc0), pixelCoverage(0xc1), pixelCoverage(0xc2), pixelCoverage(0xc3), - pixelCoverage(0xc4), pixelCoverage(0xc5), pixelCoverage(0xc6), pixelCoverage(0xc7), - pixelCoverage(0xc8), pixelCoverage(0xc9), pixelCoverage(0xca), pixelCoverage(0xcb), - pixelCoverage(0xcc), pixelCoverage(0xcd), pixelCoverage(0xce), pixelCoverage(0xcf), - pixelCoverage(0xd0), pixelCoverage(0xd1), pixelCoverage(0xd2), pixelCoverage(0xd3), - pixelCoverage(0xd4), pixelCoverage(0xd5), pixelCoverage(0xd6), pixelCoverage(0xd7), - pixelCoverage(0xd8), pixelCoverage(0xd9), pixelCoverage(0xda), pixelCoverage(0xdb), - pixelCoverage(0xdc), pixelCoverage(0xdd), pixelCoverage(0xde), pixelCoverage(0xdf), - pixelCoverage(0xe0), pixelCoverage(0xe1), pixelCoverage(0xe2), pixelCoverage(0xe3), - pixelCoverage(0xe4), pixelCoverage(0xe5), pixelCoverage(0xe6), pixelCoverage(0xe7), - pixelCoverage(0xe8), pixelCoverage(0xe9), pixelCoverage(0xea), pixelCoverage(0xeb), - pixelCoverage(0xec), pixelCoverage(0xed), pixelCoverage(0xee), pixelCoverage(0xef), - pixelCoverage(0xf0), pixelCoverage(0xf1), pixelCoverage(0xf2), pixelCoverage(0xf3), - pixelCoverage(0xf4), pixelCoverage(0xf5), pixelCoverage(0xf6), pixelCoverage(0xf7), - pixelCoverage(0xf8), pixelCoverage(0xf9), pixelCoverage(0xfa), pixelCoverage(0xfb), - pixelCoverage(0xfc), pixelCoverage(0xfd), pixelCoverage(0xfe), pixelCoverage(0xff), -} - -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)) -} +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_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), +} + +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, +} + +var coverageTable = [256]uint8{ + pixelCoverage(0x00), pixelCoverage(0x01), pixelCoverage(0x02), pixelCoverage(0x03), + pixelCoverage(0x04), pixelCoverage(0x05), pixelCoverage(0x06), pixelCoverage(0x07), + pixelCoverage(0x08), pixelCoverage(0x09), pixelCoverage(0x0a), pixelCoverage(0x0b), + pixelCoverage(0x0c), pixelCoverage(0x0d), pixelCoverage(0x0e), pixelCoverage(0x0f), + pixelCoverage(0x10), pixelCoverage(0x11), pixelCoverage(0x12), pixelCoverage(0x13), + pixelCoverage(0x14), pixelCoverage(0x15), pixelCoverage(0x16), pixelCoverage(0x17), + pixelCoverage(0x18), pixelCoverage(0x19), pixelCoverage(0x1a), pixelCoverage(0x1b), + pixelCoverage(0x1c), pixelCoverage(0x1d), pixelCoverage(0x1e), pixelCoverage(0x1f), + pixelCoverage(0x20), pixelCoverage(0x21), pixelCoverage(0x22), pixelCoverage(0x23), + pixelCoverage(0x24), pixelCoverage(0x25), pixelCoverage(0x26), pixelCoverage(0x27), + pixelCoverage(0x28), pixelCoverage(0x29), pixelCoverage(0x2a), pixelCoverage(0x2b), + pixelCoverage(0x2c), pixelCoverage(0x2d), pixelCoverage(0x2e), pixelCoverage(0x2f), + pixelCoverage(0x30), pixelCoverage(0x31), pixelCoverage(0x32), pixelCoverage(0x33), + pixelCoverage(0x34), pixelCoverage(0x35), pixelCoverage(0x36), pixelCoverage(0x37), + pixelCoverage(0x38), pixelCoverage(0x39), pixelCoverage(0x3a), pixelCoverage(0x3b), + pixelCoverage(0x3c), pixelCoverage(0x3d), pixelCoverage(0x3e), pixelCoverage(0x3f), + pixelCoverage(0x40), pixelCoverage(0x41), pixelCoverage(0x42), pixelCoverage(0x43), + pixelCoverage(0x44), pixelCoverage(0x45), pixelCoverage(0x46), pixelCoverage(0x47), + pixelCoverage(0x48), pixelCoverage(0x49), pixelCoverage(0x4a), pixelCoverage(0x4b), + pixelCoverage(0x4c), pixelCoverage(0x4d), pixelCoverage(0x4e), pixelCoverage(0x4f), + pixelCoverage(0x50), pixelCoverage(0x51), pixelCoverage(0x52), pixelCoverage(0x53), + pixelCoverage(0x54), pixelCoverage(0x55), pixelCoverage(0x56), pixelCoverage(0x57), + pixelCoverage(0x58), pixelCoverage(0x59), pixelCoverage(0x5a), pixelCoverage(0x5b), + pixelCoverage(0x5c), pixelCoverage(0x5d), pixelCoverage(0x5e), pixelCoverage(0x5f), + pixelCoverage(0x60), pixelCoverage(0x61), pixelCoverage(0x62), pixelCoverage(0x63), + pixelCoverage(0x64), pixelCoverage(0x65), pixelCoverage(0x66), pixelCoverage(0x67), + pixelCoverage(0x68), pixelCoverage(0x69), pixelCoverage(0x6a), pixelCoverage(0x6b), + pixelCoverage(0x6c), pixelCoverage(0x6d), pixelCoverage(0x6e), pixelCoverage(0x6f), + pixelCoverage(0x70), pixelCoverage(0x71), pixelCoverage(0x72), pixelCoverage(0x73), + pixelCoverage(0x74), pixelCoverage(0x75), pixelCoverage(0x76), pixelCoverage(0x77), + pixelCoverage(0x78), pixelCoverage(0x79), pixelCoverage(0x7a), pixelCoverage(0x7b), + pixelCoverage(0x7c), pixelCoverage(0x7d), pixelCoverage(0x7e), pixelCoverage(0x7f), + pixelCoverage(0x80), pixelCoverage(0x81), pixelCoverage(0x82), pixelCoverage(0x83), + pixelCoverage(0x84), pixelCoverage(0x85), pixelCoverage(0x86), pixelCoverage(0x87), + pixelCoverage(0x88), pixelCoverage(0x89), pixelCoverage(0x8a), pixelCoverage(0x8b), + pixelCoverage(0x8c), pixelCoverage(0x8d), pixelCoverage(0x8e), pixelCoverage(0x8f), + pixelCoverage(0x90), pixelCoverage(0x91), pixelCoverage(0x92), pixelCoverage(0x93), + pixelCoverage(0x94), pixelCoverage(0x95), pixelCoverage(0x96), pixelCoverage(0x97), + pixelCoverage(0x98), pixelCoverage(0x99), pixelCoverage(0x9a), pixelCoverage(0x9b), + pixelCoverage(0x9c), pixelCoverage(0x9d), pixelCoverage(0x9e), pixelCoverage(0x9f), + pixelCoverage(0xa0), pixelCoverage(0xa1), pixelCoverage(0xa2), pixelCoverage(0xa3), + pixelCoverage(0xa4), pixelCoverage(0xa5), pixelCoverage(0xa6), pixelCoverage(0xa7), + pixelCoverage(0xa8), pixelCoverage(0xa9), pixelCoverage(0xaa), pixelCoverage(0xab), + pixelCoverage(0xac), pixelCoverage(0xad), pixelCoverage(0xae), pixelCoverage(0xaf), + pixelCoverage(0xb0), pixelCoverage(0xb1), pixelCoverage(0xb2), pixelCoverage(0xb3), + pixelCoverage(0xb4), pixelCoverage(0xb5), pixelCoverage(0xb6), pixelCoverage(0xb7), + pixelCoverage(0xb8), pixelCoverage(0xb9), pixelCoverage(0xba), pixelCoverage(0xbb), + pixelCoverage(0xbc), pixelCoverage(0xbd), pixelCoverage(0xbe), pixelCoverage(0xbf), + pixelCoverage(0xc0), pixelCoverage(0xc1), pixelCoverage(0xc2), pixelCoverage(0xc3), + pixelCoverage(0xc4), pixelCoverage(0xc5), pixelCoverage(0xc6), pixelCoverage(0xc7), + pixelCoverage(0xc8), pixelCoverage(0xc9), pixelCoverage(0xca), pixelCoverage(0xcb), + pixelCoverage(0xcc), pixelCoverage(0xcd), pixelCoverage(0xce), pixelCoverage(0xcf), + pixelCoverage(0xd0), pixelCoverage(0xd1), pixelCoverage(0xd2), pixelCoverage(0xd3), + pixelCoverage(0xd4), pixelCoverage(0xd5), pixelCoverage(0xd6), pixelCoverage(0xd7), + pixelCoverage(0xd8), pixelCoverage(0xd9), pixelCoverage(0xda), pixelCoverage(0xdb), + pixelCoverage(0xdc), pixelCoverage(0xdd), pixelCoverage(0xde), pixelCoverage(0xdf), + pixelCoverage(0xe0), pixelCoverage(0xe1), pixelCoverage(0xe2), pixelCoverage(0xe3), + pixelCoverage(0xe4), pixelCoverage(0xe5), pixelCoverage(0xe6), pixelCoverage(0xe7), + pixelCoverage(0xe8), pixelCoverage(0xe9), pixelCoverage(0xea), pixelCoverage(0xeb), + pixelCoverage(0xec), pixelCoverage(0xed), pixelCoverage(0xee), pixelCoverage(0xef), + pixelCoverage(0xf0), pixelCoverage(0xf1), pixelCoverage(0xf2), pixelCoverage(0xf3), + pixelCoverage(0xf4), pixelCoverage(0xf5), pixelCoverage(0xf6), pixelCoverage(0xf7), + pixelCoverage(0xf8), pixelCoverage(0xf9), pixelCoverage(0xfa), pixelCoverage(0xfb), + pixelCoverage(0xfc), pixelCoverage(0xfd), pixelCoverage(0xfe), pixelCoverage(0xff), +} + +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)) +} diff --git a/draw2d/raster/fillerAA.go b/draw2d/raster/fillerAA.go index bdbf125..6533f3f 100644 --- a/draw2d/raster/fillerAA.go +++ b/draw2d/raster/fillerAA.go @@ -8,11 +8,11 @@ import ( ) const ( - SUBPIXEL_SHIFT = 3 + SUBPIXEL_SHIFT = 4 SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT ) -var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8 +var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_16 type SUBPIXEL_DATA uint16 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) p := 0 l := len(*polygon) / 2 + var edges [32]PolygonEdge for p < l { - var edges [20]PolygonEdge - edgeCount := polygon.getEdges(p, 10, edges[:], transform, clipRect) + edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect) for k := 0; k < edgeCount; k++ { r.addEvenOddEdge(&(edges[k])) } - p += 10 + p += 16 } 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) { 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 + 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 } @@ -157,9 +159,131 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBACo 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]) + 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 //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) diff --git a/draw2d/raster/line.go b/draw2d/raster/line.go index 235ea01..8a9d33a 100644 --- a/draw2d/raster/line.go +++ b/draw2d/raster/line.go @@ -1,55 +1,55 @@ // Copyright 2011 The draw2d Authors. All rights reserved. // created: 27/05/2011 by Laurent Le Goff -package raster - -import ( - "exp/draw" - "image" -) - -func abs(i int) int { - if i < 0 { - return -i - } - return i -} - -func PolylineBresenham(img draw.Image, c image.Color, s ...float64) { - 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)) - } -} - -func Bresenham(img draw.Image, color image.Color, x0, y0, x1, y1 int) { - dx := abs(x1 - x0) - dy := abs(y1 - y0) - var sx, sy int - if x0 < x1 { - sx = 1 - } else { - sx = -1 - } - if y0 < y1 { - sy = 1 - } else { - sy = -1 - } - err := dx - dy - - var e2 int - for { - img.Set(x0, y0, color) - if x0 == x1 && y0 == y1 { - return - } - e2 = 2 * err - if e2 > -dy { - err = err - dy - x0 = x0 + sx - } - if e2 < dx { - err = err + dx - y0 = y0 + sy - } - } -} +package raster + +import ( + "exp/draw" + "image" +) + +func abs(i int) int { + if i < 0 { + return -i + } + return i +} + +func PolylineBresenham(img draw.Image, c image.Color, s ...float64) { + 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)) + } +} + +func Bresenham(img draw.Image, color image.Color, x0, y0, x1, y1 int) { + dx := abs(x1 - x0) + dy := abs(y1 - y0) + var sx, sy int + if x0 < x1 { + sx = 1 + } else { + sx = -1 + } + if y0 < y1 { + sy = 1 + } else { + sy = -1 + } + err := dx - dy + + var e2 int + for { + img.Set(x0, y0, color) + if x0 == x1 && y0 == y1 { + return + } + e2 = 2 * err + if e2 > -dy { + err = err - dy + x0 = x0 + sx + } + if e2 < dx { + err = err + dx + y0 = y0 + sy + } + } +} diff --git a/draw2d/raster/polygon.go b/draw2d/raster/polygon.go index 750dee7..4044d56 100644 --- a/draw2d/raster/polygon.go +++ b/draw2d/raster/polygon.go @@ -1,29 +1,29 @@ // Copyright 2011 The draw2d Authors. All rights reserved. // created: 27/05/2011 by Laurent Le Goff -package raster - -import ( - "math" -) - -const ( - POLYGON_CLIP_NONE = iota - POLYGON_CLIP_LEFT - POLYGON_CLIP_RIGHT - POLYGON_CLIP_TOP - POLYGON_CLIP_BOTTOM -) - -type Polygon []float64 - - -type PolygonEdge struct { - X, Slope float64 - FirstLine, LastLine int - Winding int16 -} - - +package raster + +import ( + "math" +) + +const ( + POLYGON_CLIP_NONE = iota + POLYGON_CLIP_LEFT + POLYGON_CLIP_RIGHT + POLYGON_CLIP_TOP + POLYGON_CLIP_BOTTOM +) + +type Polygon []float64 + + +type PolygonEdge struct { + X, Slope float64 + FirstLine, LastLine int + Winding int16 +} + + //! Calculates the edges of the polygon with transformation and clipping to edges array. /*! \param startIndex the index for the first vertex. * \param vertexCount the amount of vertices to convert. @@ -31,159 +31,159 @@ type PolygonEdge struct { * \param tr the transformation matrix for the polygon. * \param aClipRectangle the clip rectangle. * \return the amount of edges in the result. - */ -func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [6]float64, clipBound [4]float64) int { - startIndex = startIndex * 2 - endIndex := startIndex + (vertexCount * 2) - if endIndex > len(p) { - endIndex = len(p) - } - - x := p[startIndex] - y := p[startIndex+1] + */ +func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [6]float64, clipBound [4]float64) int { + startIndex = startIndex * 2 + endIndex := startIndex + (vertexCount * 2) + if endIndex > len(p) { + endIndex = len(p) + } + + x := p[startIndex] + y := p[startIndex+1] // inline transformation - prevX := x*tr[0] + y*tr[2] + tr[4] - prevY := x*tr[1] + y*tr[3] + tr[5] - + prevX := x*tr[0] + y*tr[2] + tr[4] + prevY := x*tr[1] + y*tr[3] + tr[5] + //! Calculates the clip flags for a point. - prevClipFlags := POLYGON_CLIP_NONE - if prevX < clipBound[0] { - prevClipFlags |= POLYGON_CLIP_LEFT - } else if prevX >= clipBound[2] { - prevClipFlags |= POLYGON_CLIP_RIGHT - } - - if prevY < clipBound[1] { - prevClipFlags |= POLYGON_CLIP_TOP - } else if prevY >= clipBound[3] { - prevClipFlags |= POLYGON_CLIP_BOTTOM - } - - edgeCount := 0 - var k, clipFlags, clipSum, clipUnion int - var xleft, yleft, xright, yright, oldY, maxX, minX float64 - var swapWinding int16 - for n := startIndex; n < endIndex; n = n + 2 { - k = (n + 2) % len(p) - x = p[k]*tr[0] + p[k+1]*tr[2] + tr[4] - y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5] - + prevClipFlags := POLYGON_CLIP_NONE + if prevX < clipBound[0] { + prevClipFlags |= POLYGON_CLIP_LEFT + } else if prevX >= clipBound[2] { + prevClipFlags |= POLYGON_CLIP_RIGHT + } + + if prevY < clipBound[1] { + prevClipFlags |= POLYGON_CLIP_TOP + } else if prevY >= clipBound[3] { + prevClipFlags |= POLYGON_CLIP_BOTTOM + } + + edgeCount := 0 + var k, clipFlags, clipSum, clipUnion int + var xleft, yleft, xright, yright, oldY, maxX, minX float64 + var swapWinding int16 + for n := startIndex; n < endIndex; n = n + 2 { + k = (n + 2) % len(p) + x = p[k]*tr[0] + p[k+1]*tr[2] + tr[4] + y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5] + //! Calculates the clip flags for a point. - clipFlags = POLYGON_CLIP_NONE - if prevX < clipBound[0] { - clipFlags |= POLYGON_CLIP_LEFT - } else if prevX >= clipBound[2] { - clipFlags |= POLYGON_CLIP_RIGHT - } - if prevY < clipBound[1] { - clipFlags |= POLYGON_CLIP_TOP - } else if prevY >= clipBound[3] { - clipFlags |= POLYGON_CLIP_BOTTOM - } - - clipSum = prevClipFlags | clipFlags - clipUnion = prevClipFlags & clipFlags - + clipFlags = POLYGON_CLIP_NONE + if prevX < clipBound[0] { + clipFlags |= POLYGON_CLIP_LEFT + } else if prevX >= clipBound[2] { + clipFlags |= POLYGON_CLIP_RIGHT + } + if prevY < clipBound[1] { + clipFlags |= POLYGON_CLIP_TOP + } else if prevY >= clipBound[3] { + clipFlags |= POLYGON_CLIP_BOTTOM + } + + clipSum = prevClipFlags | clipFlags + 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) { - edgeCount++ - } - } else if (clipUnion & POLYGON_CLIP_LEFT) != 0 { + if getVerticalEdge(prevY, y, clipBound[2], &(edges[edgeCount]), clipBound) { + edgeCount++ + } + } 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) { - edgeCount++ - } - } else if (clipSum & (POLYGON_CLIP_RIGHT | POLYGON_CLIP_LEFT)) == 0 { + if getVerticalEdge(prevY, y, clipBound[0], &(edges[edgeCount]), clipBound) { + edgeCount++ + } + } 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) { - edgeCount++ - } - } else { + if getEdge(prevX, prevY, x, y, &(edges[edgeCount]), clipBound) { + edgeCount++ + } + } else { // Clips to left or right or both. - - if x < prevX { - xleft, yleft = x, y - xright, yright = prevX, prevY - swapWinding = -1 - } else { - xleft, yleft = prevX, prevY - xright, yright = x, y - swapWinding = 1 - } - - slope := (yright - yleft) / (xright - xleft) - - if (clipSum & POLYGON_CLIP_RIGHT) != 0 { + + if x < prevX { + xleft, yleft = x, y + xright, yright = prevX, prevY + swapWinding = -1 + } else { + xleft, yleft = prevX, prevY + xright, yright = x, y + swapWinding = 1 + } + + slope := (yright - yleft) / (xright - xleft) + + if (clipSum & POLYGON_CLIP_RIGHT) != 0 { // calculate new position for the right vertex - oldY = yright - maxX = clipBound[2] - - yright = yleft + (maxX-xleft)*slope - xright = maxX - + oldY = yright + maxX = clipBound[2] + + yright = yleft + (maxX-xleft)*slope + xright = maxX + // add vertical edge for the overflowing part - if getVerticalEdge(yright, oldY, maxX, &(edges[edgeCount]), clipBound) { - edges[edgeCount].Winding *= swapWinding - edgeCount++ - } - } - - if (clipSum & POLYGON_CLIP_LEFT) != 0 { + if getVerticalEdge(yright, oldY, maxX, &(edges[edgeCount]), clipBound) { + edges[edgeCount].Winding *= swapWinding + edgeCount++ + } + } + + if (clipSum & POLYGON_CLIP_LEFT) != 0 { // calculate new position for the left vertex - oldY = yleft - minX = clipBound[0] - - yleft = yleft + (minX-xleft)*slope - xleft = minX - + oldY = yleft + minX = clipBound[0] + + yleft = yleft + (minX-xleft)*slope + xleft = minX + // add vertical edge for the overflowing part - if getVerticalEdge(oldY, yleft, minX, &(edges[edgeCount]), clipBound) { - edges[edgeCount].Winding *= swapWinding - edgeCount++ - } - } - - if getEdge(xleft, yleft, xright, yright, &(edges[edgeCount]), clipBound) { - edges[edgeCount].Winding *= swapWinding - edgeCount++ - } - } - } - - prevClipFlags = clipFlags - prevX = x - prevY = y - } - - return edgeCount -} - - + if getVerticalEdge(oldY, yleft, minX, &(edges[edgeCount]), clipBound) { + edges[edgeCount].Winding *= swapWinding + edgeCount++ + } + } + + if getEdge(xleft, yleft, xright, yright, &(edges[edgeCount]), clipBound) { + edges[edgeCount].Winding *= swapWinding + edgeCount++ + } + } + } + + prevClipFlags = clipFlags + prevX = x + prevY = y + } + + return edgeCount +} + + //! Creates a polygon edge between two vectors. /*! Clips the edge vertically to the clip rectangle. Returns true for edges that * should be rendered, false for others. - */ -func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bool { - var startX, startY, endX, endY float64 - var winding int16 - - if y0 <= y1 { - startX = x0 - startY = y0 - endX = x1 - endY = y1 - winding = 1 - } else { - startX = x1 - startY = y1 - endX = x0 - endY = y0 - winding = -1 - } - + */ +func getEdge(x0, y0, x1, y1 float64, edge *PolygonEdge, clipBound [4]float64) bool { + var startX, startY, endX, endY float64 + var winding int16 + + if y0 <= y1 { + startX = x0 + startY = y0 + endX = x1 + endY = y1 + winding = 1 + } else { + startX = x1 + startY = y1 + endX = x0 + endY = y0 + winding = -1 + } + // Essentially, firstLine is floor(startY + 1) and lastLine is floor(endY). // These are refactored to integer casts in order to avoid function // 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 // 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)) - - minClip := int(clipBound[1]) - maxClip := int(clipBound[3]) - + + firstLine := int(math.Floor(startY)) + 1 + lastLine := int(math.Floor(endY)) + + minClip := int(clipBound[1]) + maxClip := int(clipBound[3]) + // If start and end are on the same line, the edge doesn't cross // any lines and thus can be ignored. // 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 firstLine > lastLine || lastLine < minClip || firstLine >= maxClip { - return false - } - + if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip { + return false + } + // Adjust the start based on the target. - if firstLine < minClip { - firstLine = minClip - } - - if lastLine >= maxClip { - lastLine = maxClip - 1 - } - edge.Slope = (endX - startX) / (endY - startY) - edge.X = startX + (float64(firstLine)-startY)*edge.Slope - edge.Winding = winding - edge.FirstLine = firstLine - edge.LastLine = lastLine - - return true -} - - + if firstLine < minClip { + firstLine = minClip + } + + if lastLine >= maxClip { + lastLine = maxClip - 1 + } + edge.Slope = (endX - startX) / (endY - startY) + edge.X = startX + (float64(firstLine)-startY)*edge.Slope + edge.Winding = winding + edge.FirstLine = firstLine + edge.LastLine = lastLine + + return true +} + + //! Creates a vertical polygon edge between two y values. /*! Clips the edge vertically to the clip rectangle. Returns true for edges that * should be rendered, false for others. - */ -func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]float64) bool { - var start, end float64 - var winding int16 - if startY < endY { - start = startY - end = endY - winding = 1 - } else { - start = endY - end = startY - winding = -1 - } - - firstLine := int(math.Floor(start)) + 1 - lastLine := int(math.Floor(end)) - - minClip := int(clipBound[1]) - maxClip := int(clipBound[3]) - + */ +func getVerticalEdge(startY, endY, x float64, edge *PolygonEdge, clipBound [4]float64) bool { + var start, end float64 + var winding int16 + if startY < endY { + start = startY + end = endY + winding = 1 + } else { + start = endY + end = startY + winding = -1 + } + + firstLine := int(math.Floor(start)) + 1 + lastLine := int(math.Floor(end)) + + minClip := int(clipBound[1]) + maxClip := int(clipBound[3]) + // If start and end are on the same line, the edge doesn't cross // any lines and thus can be ignored. // 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 firstLine > lastLine || lastLine < minClip || firstLine >= maxClip { - return false - } - + if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip { + return false + } + // Adjust the start based on the clip rect. - if firstLine < minClip { - firstLine = minClip - } - if lastLine >= maxClip { - lastLine = maxClip - 1 - } - - edge.Slope = 0 - edge.X = x - edge.Winding = winding - edge.FirstLine = firstLine - edge.LastLine = lastLine - - return true -} + if firstLine < minClip { + firstLine = minClip + } + if lastLine >= maxClip { + lastLine = maxClip - 1 + } + + edge.Slope = 0 + edge.X = x + edge.Winding = winding + edge.FirstLine = firstLine + edge.LastLine = lastLine + + return true +} diff --git a/draw2d/raster/raster_test.go b/draw2d/raster/raster_test.go index 716088d..de7ea13 100644 --- a/draw2d/raster/raster_test.go +++ b/draw2d/raster/raster_test.go @@ -49,23 +49,6 @@ func (p *Path) LineTo(x, y float64) { 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) { var p Path c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} @@ -87,7 +70,8 @@ func TestFreetype(t *testing.T) { savepng("_testFreetype.png", img) } -func BenchmarkRasterizer8BitsSample(b *testing.B) { +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} @@ -95,11 +79,29 @@ func BenchmarkRasterizer8BitsSample(b *testing.B) { 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 := 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) + //PolylineBresenham(img, image.Black, poly...) + + + r.RenderNonZeroWinding(img, &color, &poly, tr) + savepng("_testRasterizerNonZeroWinding.png", img) } func BenchmarkFreetype(b *testing.B) { @@ -122,3 +124,34 @@ func BenchmarkFreetype(b *testing.B) { 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) + } +} +