From 82a7e1e58e4b9f77e70ce5be4bb64da3c2d8977a Mon Sep 17 00:00:00 2001 From: Laurent Le Goff Date: Thu, 27 Aug 2015 14:12:22 +0200 Subject: [PATCH] Remove raster experiment --- draw2dbase/curve_test.go | 10 +- {raster => draw2dbase}/line.go | 5 +- raster/coverage_table.go | 203 ------------ raster/fillerAA.go | 320 ------------------ raster/fillerV1/fillerAA.go | 306 ----------------- raster/fillerV2/fillerAA.go | 323 ------------------ raster/fixed_point.go | 17 - raster/polygon.go | 581 --------------------------------- raster/raster_test.go | 193 ----------- 9 files changed, 8 insertions(+), 1950 deletions(-) rename {raster => draw2dbase}/line.go (87%) delete mode 100644 raster/coverage_table.go delete mode 100644 raster/fillerAA.go delete mode 100644 raster/fillerV1/fillerAA.go delete mode 100644 raster/fillerV2/fillerAA.go delete mode 100644 raster/fixed_point.go delete mode 100644 raster/polygon.go delete mode 100644 raster/raster_test.go diff --git a/draw2dbase/curve_test.go b/draw2dbase/curve_test.go index d04b9fb..fa954df 100644 --- a/draw2dbase/curve_test.go +++ b/draw2dbase/curve_test.go @@ -10,8 +10,6 @@ import ( "log" "os" "testing" - - "github.com/llgcode/draw2d/raster" ) var ( @@ -77,8 +75,8 @@ func TestCubicCurve(t *testing.T) { p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1]) TraceCubic(&p, testsCubicFloat64[i:], flatteningThreshold) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) - raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...) - raster.PolylineBresenham(img, image.Black, p.Points...) + PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...) + PolylineBresenham(img, image.Black, p.Points...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.Points...) SaveToPngFile(fmt.Sprintf("../output/curve/_test%d.png", i/8), img) @@ -93,8 +91,8 @@ func TestQuadCurve(t *testing.T) { p.MoveTo(testsQuadFloat64[i], testsQuadFloat64[i+1]) TraceQuad(&p, testsQuadFloat64[i:], flatteningThreshold) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) - raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...) - raster.PolylineBresenham(img, image.Black, p.Points...) + PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...) + PolylineBresenham(img, image.Black, p.Points...) //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.Points...) SaveToPngFile(fmt.Sprintf("../output/curve/_testQuad%d.png", i), img) diff --git a/raster/line.go b/draw2dbase/line.go similarity index 87% rename from raster/line.go rename to draw2dbase/line.go index 6f6d886..a83bbc3 100644 --- a/raster/line.go +++ b/draw2dbase/line.go @@ -1,6 +1,7 @@ // Copyright 2011 The draw2d Authors. All rights reserved. // created: 27/05/2011 by Laurent Le Goff -package raster + +package draw2dbase import ( "image/color" @@ -14,12 +15,14 @@ func abs(i int) int { return i } +// PolylineBresenham draws a polyline to an image func PolylineBresenham(img draw.Image, c color.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)) } } +// Bresenham draws a line between (x0, y0) and (x1, y1) func Bresenham(img draw.Image, color color.Color, x0, y0, x1, y1 int) { dx := abs(x1 - x0) dy := abs(y1 - y0) diff --git a/raster/coverage_table.go b/raster/coverage_table.go deleted file mode 100644 index 429836f..0000000 --- a/raster/coverage_table.go +++ /dev/null @@ -1,203 +0,0 @@ -// 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.0 / 8, - 0.0 / 8, - 3.0 / 8, - 6.0 / 8, - 1.0 / 8, - 4.0 / 8, - 7.0 / 8, - 2.0 / 8, -} - -var SUBPIXEL_OFFSETS_SAMPLE_8_FIXED = [8]Fix{ - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[0] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[1] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[2] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[3] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[4] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[5] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[6] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_8[7] * FIXED_FLOAT_COEF), -} - -var SUBPIXEL_OFFSETS_SAMPLE_16 = [16]float64{ - 1.0 / 16, - 8.0 / 16, - 4.0 / 16, - 15.0 / 16, - 11.0 / 16, - 2.0 / 16, - 6.0 / 16, - 14.0 / 16, - 10.0 / 16, - 3.0 / 16, - 7.0 / 16, - 12.0 / 16, - 0.0 / 16, - 9.0 / 16, - 5.0 / 16, - 13.0 / 16, -} - -var SUBPIXEL_OFFSETS_SAMPLE_16_FIXED = [16]Fix{ - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[0] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[1] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[2] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[3] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[4] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[5] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[6] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[7] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[8] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[9] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[10] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[11] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[12] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[13] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[14] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_16[15] * FIXED_FLOAT_COEF), -} - -var SUBPIXEL_OFFSETS_SAMPLE_32 = [32]float64{ - 28.0 / 32, - 13.0 / 32, - 6.0 / 32, - 23.0 / 32, - 0.0 / 32, - 17.0 / 32, - 10.0 / 32, - 27.0 / 32, - 4.0 / 32, - 21.0 / 32, - 14.0 / 32, - 31.0 / 32, - 8.0 / 32, - 25.0 / 32, - 18.0 / 32, - 3.0 / 32, - 12.0 / 32, - 29.0 / 32, - 22.0 / 32, - 7.0 / 32, - 16.0 / 32, - 1.0 / 32, - 26.0 / 32, - 11.0 / 32, - 20.0 / 32, - 5.0 / 32, - 30.0 / 32, - 15.0 / 32, - 24.0 / 32, - 9.0 / 32, - 2.0 / 32, - 19.0 / 32, -} -var SUBPIXEL_OFFSETS_SAMPLE_32_FIXED = [32]Fix{ - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[0] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[1] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[2] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[3] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[4] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[5] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[6] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[7] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[8] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[9] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[10] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[11] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[12] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[13] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[14] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[15] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[16] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[17] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[18] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[19] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[20] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[21] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[22] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[23] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[24] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[25] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[26] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[27] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[28] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[29] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[30] * FIXED_FLOAT_COEF), - Fix(SUBPIXEL_OFFSETS_SAMPLE_32[31] * FIXED_FLOAT_COEF), -} - -var coverageTable = [256]uint8{ - 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/raster/fillerAA.go b/raster/fillerAA.go deleted file mode 100644 index dbff87f..0000000 --- a/raster/fillerAA.go +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright 2011 The draw2d Authors. All rights reserved. -// created: 27/05/2011 by Laurent Le Goff -package raster - -import ( - "image" - "image/color" - "unsafe" -) - -const ( - SUBPIXEL_SHIFT = 3 - SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT -) - -var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8_FIXED - -type SUBPIXEL_DATA uint8 -type NON_ZERO_MASK_DATA_UNIT uint8 - -type Rasterizer8BitsSample struct { - MaskBuffer []SUBPIXEL_DATA - WindingBuffer []NON_ZERO_MASK_DATA_UNIT - - Width int - BufferWidth int - Height int - ClipBound [4]float64 - RemappingMatrix [6]float64 -} - -/* width and height define the maximum output size for the filler. - * The filler will output to larger bitmaps as well, but the output will - * be cropped. - */ -func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample { - var r Rasterizer8BitsSample - // Scale the coordinates by SUBPIXEL_COUNT in vertical direction - // The sampling point for the sub-pixel is at the top right corner. This - // adjustment moves it to the pixel center. - r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT} - r.Width = width - r.Height = height - // The buffer used for filling needs to be one pixel wider than the bitmap. - // This is because the end flag that turns the fill of is the first pixel - // after the actually drawn edge. - r.BufferWidth = width + 1 - - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height) - r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT) - r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT) - return &r -} - -func clip(x, y, width, height, scale int) [4]float64 { - var clipBound [4]float64 - - offset := 0.99 / float64(scale) - - clipBound[0] = float64(x) + offset - clipBound[2] = float64(x+width) - offset - - clipBound[1] = float64(y * scale) - clipBound[3] = float64((y + height) * scale) - return clipBound -} - -func intersect(r1, r2 [4]float64) [4]float64 { - if r1[0] < r2[0] { - r1[0] = r2[0] - } - if r1[2] > r2[2] { - r1[2] = r2[2] - } - if r1[0] > r1[2] { - r1[0] = r1[2] - } - - if r1[1] < r2[1] { - r1[1] = r2[1] - } - if r1[3] > r2[3] { - r1[3] = r2[3] - } - if r1[1] > r1[3] { - r1[1] = r1[3] - } - return r1 -} - -func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { - // memset 0 the mask buffer - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) - - // inline matrix multiplication - transform := [6]float64{ - tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], - tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], - tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2], - tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1], - tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4], - tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5], - } - - clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT) - clipRect = intersect(clipRect, r.ClipBound) - p := 0 - l := len(*polygon) / 2 - var edges [32]PolygonEdge - for p < l { - edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect) - for k := 0; k < edgeCount; k++ { - r.addEvenOddEdge(&edges[k]) - } - p += 16 - } - - r.fillEvenOdd(img, color, clipRect) -} - -//! Adds an edge to be used with even-odd fill. -func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { - x := Fix(edge.X * FIXED_FLOAT_COEF) - slope := Fix(edge.Slope * FIXED_FLOAT_COEF) - slopeFix := Fix(0) - if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP { - slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<> FIXED_SHIFT) - mask = SUBPIXEL_DATA(1 << ySub) - yLine = y >> SUBPIXEL_SHIFT - r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask - x += slope - if y&SLOPE_FIX_MASK == 0 { - x += slopeFix - } - } -} - -//! Adds an edge to be used with non-zero winding fill. -func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { - x := Fix(edge.X * FIXED_FLOAT_COEF) - slope := Fix(edge.Slope * FIXED_FLOAT_COEF) - slopeFix := Fix(0) - if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP { - slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<> FIXED_SHIFT) - mask = SUBPIXEL_DATA(1 << ySub) - yLine = y >> SUBPIXEL_SHIFT - r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask - r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding - x += slope - if y&SLOPE_FIX_MASK == 0 { - x += slopeFix - } - } -} - -// Renders the mask to the canvas with even-odd fill. -func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { - var x, y uint32 - - minX := uint32(clipBound[0]) - maxX := uint32(clipBound[2]) - - minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT - maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT - - //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) - pixColor := (*uint32)(unsafe.Pointer(color)) - cs1 := *pixColor & 0xff00ff - cs2 := *pixColor >> 8 & 0xff00ff - - stride := uint32(img.Stride) - var mask SUBPIXEL_DATA - - for y = minY; y < maxY; y++ { - tp := img.Pix[y*stride:] - - mask = 0 - for x = minX; x <= maxX; x++ { - p := (*uint32)(unsafe.Pointer(&tp[x])) - mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x] - // 8bits - alpha := uint32(coverageTable[mask]) - // 16bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) - // 32bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) - - // alpha is in range of 0 to SUBPIXEL_COUNT - invAlpha := 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 *color.RGBA, polygon *Polygon, tr [6]float64) { - - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) - r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) - - // inline matrix multiplication - transform := [6]float64{ - tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], - tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], - tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2], - tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1], - tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4], - tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5], - } - - clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT) - clipRect = intersect(clipRect, r.ClipBound) - - p := 0 - l := len(*polygon) / 2 - var edges [32]PolygonEdge - for p < l { - edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect) - for k := 0; k < edgeCount; k++ { - r.addNonZeroEdge(&edges[k]) - } - p += 16 - } - - r.fillNonZero(img, color, clipRect) -} - -//! Renders the mask to the canvas with non-zero winding fill. -func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { - var x, y uint32 - - minX := uint32(clipBound[0]) - maxX := uint32(clipBound[2]) - - minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT - maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT - - //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) - pixColor := (*uint32)(unsafe.Pointer(color)) - cs1 := *pixColor & 0xff00ff - cs2 := *pixColor >> 8 & 0xff00ff - - stride := uint32(img.Stride) - var mask SUBPIXEL_DATA - var n uint32 - var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT - for n = 0; n < SUBPIXEL_COUNT; n++ { - values[n] = 0 - } - - for y = minY; y < maxY; y++ { - tp := img.Pix[y*stride:] - - mask = 0 - for x = minX; x <= maxX; x++ { - p := (*uint32)(unsafe.Pointer(&tp[x])) - temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x] - if temp != 0 { - var bit SUBPIXEL_DATA = 1 - for n = 0; n < SUBPIXEL_COUNT; n++ { - if temp&bit != 0 { - t := values[n] - values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n] - if (t == 0 || values[n] == 0) && t != values[n] { - mask ^= bit - } - } - bit <<= 1 - } - } - - // 8bits - alpha := uint32(coverageTable[mask]) - // 16bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) - // 32bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) - - // alpha is in range of 0 to SUBPIXEL_COUNT - invAlpha := uint32(SUBPIXEL_COUNT) - alpha - - ct1 := *p & 0xff00ff * invAlpha - ct2 := *p >> 8 & 0xff00ff * invAlpha - - ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff - ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00 - - *p = ct1 + ct2 - } - } -} diff --git a/raster/fillerV1/fillerAA.go b/raster/fillerV1/fillerAA.go deleted file mode 100644 index 976ac5f..0000000 --- a/raster/fillerV1/fillerAA.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2011 The draw2d Authors. All rights reserved. -// created: 27/05/2011 by Laurent Le Goff - -// +build ignore - -package raster - -import ( - "image" - "image/color" - "unsafe" -) - -const ( - SUBPIXEL_SHIFT = 3 - SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT -) - -var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_8 - -type SUBPIXEL_DATA uint16 -type NON_ZERO_MASK_DATA_UNIT uint8 - -type Rasterizer8BitsSample struct { - MaskBuffer []SUBPIXEL_DATA - WindingBuffer []NON_ZERO_MASK_DATA_UNIT - - Width int - BufferWidth int - Height int - ClipBound [4]float64 - RemappingMatrix [6]float64 -} - -/* width and height define the maximum output size for the filler. - * The filler will output to larger bitmaps as well, but the output will - * be cropped. - */ -func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample { - var r Rasterizer8BitsSample - // Scale the coordinates by SUBPIXEL_COUNT in vertical direction - // The sampling point for the sub-pixel is at the top right corner. This - // adjustment moves it to the pixel center. - r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT} - r.Width = width - r.Height = height - // The buffer used for filling needs to be one pixel wider than the bitmap. - // This is because the end flag that turns the fill of is the first pixel - // after the actually drawn edge. - r.BufferWidth = width + 1 - - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height) - r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT) - r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT) - return &r -} - -func clip(x, y, width, height, scale int) [4]float64 { - var clipBound [4]float64 - - offset := 0.99 / float64(scale) - - clipBound[0] = float64(x) + offset - clipBound[2] = float64(x+width) - offset - - clipBound[1] = float64(y * scale) - clipBound[3] = float64((y + height) * scale) - return clipBound -} - -func intersect(r1, r2 [4]float64) [4]float64 { - if r1[0] < r2[0] { - r1[0] = r2[0] - } - if r1[2] > r2[2] { - r1[2] = r2[2] - } - if r1[0] > r1[2] { - r1[0] = r1[2] - } - - if r1[1] < r2[1] { - r1[1] = r2[1] - } - if r1[3] > r2[3] { - r1[3] = r2[3] - } - if r1[1] > r1[3] { - r1[1] = r1[3] - } - return r1 -} - -func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { - // memset 0 the mask buffer - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) - - // inline matrix multiplication - transform := [6]float64{ - tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], - tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], - tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2], - tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1], - tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4], - tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5], - } - - clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT) - clipRect = intersect(clipRect, r.ClipBound) - p := 0 - l := len(*polygon) / 2 - var edges [32]PolygonEdge - for p < l { - edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect) - for k := 0; k < edgeCount; k++ { - r.addEvenOddEdge(&edges[k]) - } - p += 16 - } - - r.fillEvenOdd(img, color, clipRect) -} - -//! Adds an edge to be used with even-odd fill. -func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { - x := edge.X - slope := edge.Slope - var ySub, mask SUBPIXEL_DATA - var xp, yLine int - for y := edge.FirstLine; y <= edge.LastLine; y++ { - ySub = SUBPIXEL_DATA(y & (SUBPIXEL_COUNT - 1)) - xp = int(x + SUBPIXEL_OFFSETS[ySub]) - mask = SUBPIXEL_DATA(1 << ySub) - yLine = y >> SUBPIXEL_SHIFT - r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask - x += slope - } -} - -// Renders the mask to the canvas with even-odd fill. -func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { - var x, y uint32 - - minX := uint32(clipBound[0]) - maxX := uint32(clipBound[2]) - - minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT - maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT - - //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) - pixColor := (*uint32)(unsafe.Pointer(color)) - cs1 := *pixColor & 0xff00ff - cs2 := *pixColor >> 8 & 0xff00ff - - stride := uint32(img.Stride) - var mask SUBPIXEL_DATA - - for y = minY; y < maxY; y++ { - tp := img.Pix[y*stride:] - - mask = 0 - for x = minX; x <= maxX; x++ { - p := (*uint32)(unsafe.Pointer(&tp[x])) - mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x] - // 8bits - alpha := uint32(coverageTable[mask]) - // 16bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) - // 32bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) - - // alpha is in range of 0 to SUBPIXEL_COUNT - invAlpha := uint32(SUBPIXEL_COUNT) - alpha - - ct1 := *p & 0xff00ff * invAlpha - ct2 := *p >> 8 & 0xff00ff * invAlpha - - ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff - ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00 - - *p = ct1 + ct2 - } - } -} - -/* - * Renders the polygon with non-zero winding fill. - * param aTarget the target bitmap. - * param aPolygon the polygon to render. - * param aColor the color to be used for rendering. - * param aTransformation the transformation matrix. - */ -func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, 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 *color.RGBA, clipBound [4]float64) { - var x, y uint32 - - minX := uint32(clipBound[0]) - maxX := uint32(clipBound[2]) - - minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT - maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT - - //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) - pixColor := (*uint32)(unsafe.Pointer(color)) - cs1 := *pixColor & 0xff00ff - cs2 := *pixColor >> 8 & 0xff00ff - - stride := uint32(img.Stride) - var mask SUBPIXEL_DATA - var n uint32 - var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT - for n = 0; n < SUBPIXEL_COUNT; n++ { - values[n] = 0 - } - - for y = minY; y < maxY; y++ { - tp := img.Pix[y*stride:] - - mask = 0 - for x = minX; x <= maxX; x++ { - p := (*uint32)(unsafe.Pointer(&tp[x])) - temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x] - if temp != 0 { - var bit SUBPIXEL_DATA = 1 - for n = 0; n < SUBPIXEL_COUNT; n++ { - if temp&bit != 0 { - t := values[n] - values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n] - if (t == 0 || values[n] == 0) && t != values[n] { - mask ^= bit - } - } - bit <<= 1 - } - } - - // 8bits - alpha := uint32(coverageTable[mask]) - // 16bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) - // 32bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff] + coverageTable[(mask >> 16) & 0xff] + coverageTable[(mask >> 24) & 0xff]) - - // alpha is in range of 0 to SUBPIXEL_COUNT - invAlpha := uint32(SUBPIXEL_COUNT) - alpha - - ct1 := *p & 0xff00ff * invAlpha - ct2 := *p >> 8 & 0xff00ff * invAlpha - - ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff - ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00 - - *p = ct1 + ct2 - } - } -} diff --git a/raster/fillerV2/fillerAA.go b/raster/fillerV2/fillerAA.go deleted file mode 100644 index 2303747..0000000 --- a/raster/fillerV2/fillerAA.go +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2011 The draw2d Authors. All rights reserved. -// created: 27/05/2011 by Laurent Le Goff - -// +build ignore - -package raster - -import ( - "image" - "image/color" - "unsafe" -) - -const ( - SUBPIXEL_SHIFT = 5 - SUBPIXEL_COUNT = 1 << SUBPIXEL_SHIFT -) - -var SUBPIXEL_OFFSETS = SUBPIXEL_OFFSETS_SAMPLE_32_FIXED - -type SUBPIXEL_DATA uint32 -type NON_ZERO_MASK_DATA_UNIT uint8 - -type Rasterizer8BitsSample struct { - MaskBuffer []SUBPIXEL_DATA - WindingBuffer []NON_ZERO_MASK_DATA_UNIT - - Width int - BufferWidth int - Height int - ClipBound [4]float64 - RemappingMatrix [6]float64 -} - -/* width and height define the maximum output size for the filler. - * The filler will output to larger bitmaps as well, but the output will - * be cropped. - */ -func NewRasterizer8BitsSample(width, height int) *Rasterizer8BitsSample { - var r Rasterizer8BitsSample - // Scale the coordinates by SUBPIXEL_COUNT in vertical direction - // The sampling point for the sub-pixel is at the top right corner. This - // adjustment moves it to the pixel center. - r.RemappingMatrix = [6]float64{1, 0, 0, SUBPIXEL_COUNT, 0.5 / SUBPIXEL_COUNT, -0.5 * SUBPIXEL_COUNT} - r.Width = width - r.Height = height - // The buffer used for filling needs to be one pixel wider than the bitmap. - // This is because the end flag that turns the fill of is the first pixel - // after the actually drawn edge. - r.BufferWidth = width + 1 - - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*height) - r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*height*SUBPIXEL_COUNT) - r.ClipBound = clip(0, 0, width, height, SUBPIXEL_COUNT) - return &r -} - -func clip(x, y, width, height, scale int) [4]float64 { - var clipBound [4]float64 - - offset := 0.99 / float64(scale) - - clipBound[0] = float64(x) + offset - clipBound[2] = float64(x+width) - offset - - clipBound[1] = float64(y * scale) - clipBound[3] = float64((y + height) * scale) - return clipBound -} - -func intersect(r1, r2 [4]float64) [4]float64 { - if r1[0] < r2[0] { - r1[0] = r2[0] - } - if r1[2] > r2[2] { - r1[2] = r2[2] - } - if r1[0] > r1[2] { - r1[0] = r1[2] - } - - if r1[1] < r2[1] { - r1[1] = r2[1] - } - if r1[3] > r2[3] { - r1[3] = r2[3] - } - if r1[1] > r1[3] { - r1[1] = r1[3] - } - return r1 -} - -func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { - // memset 0 the mask buffer - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) - - // inline matrix multiplication - transform := [6]float64{ - tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], - tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], - tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2], - tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1], - tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4], - tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5], - } - - clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT) - clipRect = intersect(clipRect, r.ClipBound) - p := 0 - l := len(*polygon) / 2 - var edges [32]PolygonEdge - for p < l { - edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect) - for k := 0; k < edgeCount; k++ { - r.addEvenOddEdge(&edges[k]) - } - p += 16 - } - - r.fillEvenOdd(img, color, clipRect) -} - -//! Adds an edge to be used with even-odd fill. -func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { - x := Fix(edge.X * FIXED_FLOAT_COEF) - slope := Fix(edge.Slope * FIXED_FLOAT_COEF) - slopeFix := Fix(0) - if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP { - slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<> FIXED_SHIFT) - mask = SUBPIXEL_DATA(1 << ySub) - yLine = y >> SUBPIXEL_SHIFT - r.MaskBuffer[yLine*r.BufferWidth+xp] ^= mask - x += slope - if y&SLOPE_FIX_MASK == 0 { - x += slopeFix - } - } -} - -//! Adds an edge to be used with non-zero winding fill. -func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { - x := Fix(edge.X * FIXED_FLOAT_COEF) - slope := Fix(edge.Slope * FIXED_FLOAT_COEF) - slopeFix := Fix(0) - if edge.LastLine-edge.FirstLine >= SLOPE_FIX_STEP { - slopeFix = Fix(edge.Slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - slope<> FIXED_SHIFT) - mask = SUBPIXEL_DATA(1 << ySub) - yLine = y >> SUBPIXEL_SHIFT - r.MaskBuffer[yLine*r.BufferWidth+xp] |= mask - r.WindingBuffer[(yLine*r.BufferWidth+xp)*SUBPIXEL_COUNT+int(ySub)] += winding - x += slope - if y&SLOPE_FIX_MASK == 0 { - x += slopeFix - } - } -} - -// Renders the mask to the canvas with even-odd fill. -func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { - var x, y uint32 - - minX := uint32(clipBound[0]) - maxX := uint32(clipBound[2]) - - minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT - maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT - - //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) - pixColor := (*uint32)(unsafe.Pointer(color)) - cs1 := *pixColor & 0xff00ff - cs2 := *pixColor >> 8 & 0xff00ff - - stride := uint32(img.Stride) - var mask SUBPIXEL_DATA - - for y = minY; y < maxY; y++ { - tp := img.Pix[y*stride:] - - mask = 0 - for x = minX; x <= maxX; x++ { - p := (*uint32)(unsafe.Pointer(&tp[x])) - mask ^= r.MaskBuffer[y*uint32(r.BufferWidth)+x] - // 8bits - //alpha := uint32(coverageTable[mask]) - // 16bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) - // 32bits - alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff]) - - // alpha is in range of 0 to SUBPIXEL_COUNT - invAlpha := uint32(SUBPIXEL_COUNT) - alpha - - ct1 := *p & 0xff00ff * invAlpha - ct2 := *p >> 8 & 0xff00ff * invAlpha - - ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff - ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00 - - *p = ct1 + ct2 - } - } -} - -/* - * Renders the polygon with non-zero winding fill. - * param aTarget the target bitmap. - * param aPolygon the polygon to render. - * param aColor the color to be used for rendering. - * param aTransformation the transformation matrix. - */ -func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { - - r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) - r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) - - // inline matrix multiplication - transform := [6]float64{ - tr[0]*r.RemappingMatrix[0] + tr[1]*r.RemappingMatrix[2], - tr[1]*r.RemappingMatrix[3] + tr[0]*r.RemappingMatrix[1], - tr[2]*r.RemappingMatrix[0] + tr[3]*r.RemappingMatrix[2], - tr[3]*r.RemappingMatrix[3] + tr[2]*r.RemappingMatrix[1], - tr[4]*r.RemappingMatrix[0] + tr[5]*r.RemappingMatrix[2] + r.RemappingMatrix[4], - tr[5]*r.RemappingMatrix[3] + tr[4]*r.RemappingMatrix[1] + r.RemappingMatrix[5], - } - - clipRect := clip(img.Bounds().Min.X, img.Bounds().Min.Y, img.Bounds().Dx(), img.Bounds().Dy(), SUBPIXEL_COUNT) - clipRect = intersect(clipRect, r.ClipBound) - - p := 0 - l := len(*polygon) / 2 - var edges [32]PolygonEdge - for p < l { - edgeCount := polygon.getEdges(p, 16, edges[:], transform, clipRect) - for k := 0; k < edgeCount; k++ { - r.addNonZeroEdge(&edges[k]) - } - p += 16 - } - - r.fillNonZero(img, color, clipRect) -} - -//! Renders the mask to the canvas with non-zero winding fill. -func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { - var x, y uint32 - - minX := uint32(clipBound[0]) - maxX := uint32(clipBound[2]) - - minY := uint32(clipBound[1]) >> SUBPIXEL_SHIFT - maxY := uint32(clipBound[3]) >> SUBPIXEL_SHIFT - - //pixColor := (uint32(color.R) << 24) | (uint32(color.G) << 16) | (uint32(color.B) << 8) | uint32(color.A) - pixColor := (*uint32)(unsafe.Pointer(color)) - cs1 := *pixColor & 0xff00ff - cs2 := *pixColor >> 8 & 0xff00ff - - stride := uint32(img.Stride) - var mask SUBPIXEL_DATA - var n uint32 - var values [SUBPIXEL_COUNT]NON_ZERO_MASK_DATA_UNIT - for n = 0; n < SUBPIXEL_COUNT; n++ { - values[n] = 0 - } - - for y = minY; y < maxY; y++ { - tp := img.Pix[y*stride:] - - mask = 0 - for x = minX; x <= maxX; x++ { - p := (*uint32)(unsafe.Pointer(&tp[x])) - temp := r.MaskBuffer[y*uint32(r.BufferWidth)+x] - if temp != 0 { - var bit SUBPIXEL_DATA = 1 - for n = 0; n < SUBPIXEL_COUNT; n++ { - if temp&bit != 0 { - t := values[n] - values[n] += r.WindingBuffer[(y*uint32(r.BufferWidth)+x)*SUBPIXEL_COUNT+n] - if (t == 0 || values[n] == 0) && t != values[n] { - mask ^= bit - } - } - bit <<= 1 - } - } - - // 8bits - //alpha := uint32(coverageTable[mask]) - // 16bits - //alpha := uint32(coverageTable[mask & 0xff] + coverageTable[(mask >> 8) & 0xff]) - // 32bits - alpha := uint32(coverageTable[mask&0xff] + coverageTable[mask>>8&0xff] + coverageTable[mask>>16&0xff] + coverageTable[mask>>24&0xff]) - - // alpha is in range of 0 to SUBPIXEL_COUNT - invAlpha := uint32(SUBPIXEL_COUNT) - alpha - - ct1 := *p & 0xff00ff * invAlpha - ct2 := *p >> 8 & 0xff00ff * invAlpha - - ct1 = (ct1 + cs1*alpha) >> SUBPIXEL_SHIFT & 0xff00ff - ct2 = (ct2 + cs2*alpha) << (8 - SUBPIXEL_SHIFT) & 0xff00ff00 - - *p = ct1 + ct2 - } - } -} diff --git a/raster/fixed_point.go b/raster/fixed_point.go deleted file mode 100644 index 14b8419..0000000 --- a/raster/fixed_point.go +++ /dev/null @@ -1,17 +0,0 @@ -package raster - -type Fix int32 - -const ( - FIXED_SHIFT = 16 - FIXED_FLOAT_COEF = 1 << FIXED_SHIFT -) - -/*! Fixed point math inevitably introduces rounding error to the DDA. The error is - * fixed every now and then by a separate fix value. The defines below set these. - */ -const ( - SLOPE_FIX_SHIFT = 8 - SLOPE_FIX_STEP = 1 << SLOPE_FIX_SHIFT - SLOPE_FIX_MASK = SLOPE_FIX_STEP - 1 -) diff --git a/raster/polygon.go b/raster/polygon.go deleted file mode 100644 index c4755a4..0000000 --- a/raster/polygon.go +++ /dev/null @@ -1,581 +0,0 @@ -// Copyright 2011 The draw2d Authors. All rights reserved. -// created: 27/05/2011 by Laurent Le Goff -package raster - -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 -} - -//! A more optimized representation of a polygon edge. -type PolygonScanEdge struct { - FirstLine, LastLine int - Winding int16 - X Fix - Slope Fix - SlopeFix Fix - NextEdge *PolygonScanEdge -} - -//! Calculates the edges of the polygon with transformation and clipping to edges array. -/*! \param startIndex the index for the first vertex. - * \param vertexCount the amount of vertices to convert. - * \param edges the array for result edges. This should be able to contain 2*aVertexCount edges. - * \param 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] - // inline transformation - 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] - - //! 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 - - // 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 { - // 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 { - // 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 { - // No clipping in the horizontal direction - 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 { - // calculate new position for the right vertex - 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 { - // calculate new position for the left vertex - 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 -} - -//! 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 - } - - // 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 - // rounded towards zero. Since values smaller than zero get clipped away, - // 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(startY + 1) - lastLine := int(endY+1) - 1 - - 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 - } - - // 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 -} - -//! 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(start + 1) - lastLine := int(end+1) - 1 - - 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 - } - - // 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 -} - -type VertexData struct { - X, Y float64 - ClipFlags int - Line int -} - -//! Calculates the edges of the polygon with transformation and clipping to edges array. -/*! Note that this may return upto three times the amount of edges that the polygon has vertices, - * in the unlucky case where both left and right side get clipped for all edges. - * \param edges the array for result edges. This should be able to contain 2*aVertexCount edges. - * \param aTransformation the transformation matrix for the polygon. - * \param aClipRectangle the clip rectangle. - * \return the amount of edges in the result. - */ -func (p Polygon) getScanEdges(edges []PolygonScanEdge, tr [6]float64, clipBound [4]float64) int { - var n int - vertexData := make([]VertexData, len(p)/2+1) - for n = 0; n < len(vertexData)-1; n = n + 1 { - k := n * 2 - vertexData[n].X = p[k]*tr[0] + p[k+1]*tr[2] + tr[4] - vertexData[n].Y = p[k]*tr[1] + p[k+1]*tr[3] + tr[5] - // Calculate clip flags for all vertices. - vertexData[n].ClipFlags = POLYGON_CLIP_NONE - if vertexData[n].X < clipBound[0] { - vertexData[n].ClipFlags |= POLYGON_CLIP_LEFT - } else if vertexData[n].X >= clipBound[2] { - vertexData[n].ClipFlags |= POLYGON_CLIP_RIGHT - } - if vertexData[n].Y < clipBound[1] { - vertexData[n].ClipFlags |= POLYGON_CLIP_TOP - } else if vertexData[n].Y >= clipBound[3] { - vertexData[n].ClipFlags |= POLYGON_CLIP_BOTTOM - } - - // Calculate line of the vertex. If the vertex is clipped by top or bottom, the line - // is determined by the clip rectangle. - if vertexData[n].ClipFlags&POLYGON_CLIP_TOP != 0 { - vertexData[n].Line = int(clipBound[1]) - } else if vertexData[n].ClipFlags&POLYGON_CLIP_BOTTOM != 0 { - vertexData[n].Line = int(clipBound[3] - 1) - } else { - vertexData[n].Line = int(vertexData[n].Y+1) - 1 - } - } - - // Copy the data from 0 to the last entry to make the data to loop. - vertexData[len(vertexData)-1] = vertexData[0] - - // Transform the first vertex; store. - // Process mVertexCount - 1 times, next is n+1 - // copy the first vertex to - // Process 1 time, next is n - - edgeCount := 0 - for n = 0; n < len(vertexData)-1; n++ { - clipSum := vertexData[n].ClipFlags | vertexData[n+1].ClipFlags - clipUnion := vertexData[n].ClipFlags & vertexData[n+1].ClipFlags - - if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 && - vertexData[n].Line != vertexData[n+1].Line { - var startIndex, endIndex int - var winding int16 - if vertexData[n].Y < vertexData[n+1].Y { - startIndex = n - endIndex = n + 1 - winding = 1 - } else { - startIndex = n + 1 - endIndex = n - winding = -1 - } - - firstLine := vertexData[startIndex].Line + 1 - lastLine := vertexData[endIndex].Line - - if clipUnion&POLYGON_CLIP_RIGHT != 0 { - // Both clip to right, edge is a vertical line on the right side - edges[edgeCount].FirstLine = firstLine - edges[edgeCount].LastLine = lastLine - edges[edgeCount].Winding = winding - edges[edgeCount].X = Fix(clipBound[2] * FIXED_FLOAT_COEF) - edges[edgeCount].Slope = 0 - edges[edgeCount].SlopeFix = 0 - - edgeCount++ - } else if clipUnion&POLYGON_CLIP_LEFT != 0 { - // Both clip to left, edge is a vertical line on the left side - edges[edgeCount].FirstLine = firstLine - edges[edgeCount].LastLine = lastLine - edges[edgeCount].Winding = winding - edges[edgeCount].X = Fix(clipBound[0] * FIXED_FLOAT_COEF) - edges[edgeCount].Slope = 0 - edges[edgeCount].SlopeFix = 0 - - edgeCount++ - } else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 { - // No clipping in the horizontal direction - slope := (vertexData[endIndex].X - - vertexData[startIndex].X) / - (vertexData[endIndex].Y - - vertexData[startIndex].Y) - - // If there is vertical clip (for the top) it will be processed here. The calculation - // should be done for all non-clipping edges as well to determine the accurate position - // where the edge crosses the first scanline. - startx := vertexData[startIndex].X + - (float64(firstLine)-vertexData[startIndex].Y)*slope - - edges[edgeCount].FirstLine = firstLine - edges[edgeCount].LastLine = lastLine - edges[edgeCount].Winding = winding - edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF) - edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF) - - if lastLine-firstLine >= SLOPE_FIX_STEP { - edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - - edges[edgeCount].Slope< clipBound[3] { - clipVertices[p].ClipFlags = POLYGON_CLIP_BOTTOM - clipVertices[p].Line = int(clipBound[3] - 1) - } else { - clipVertices[p].ClipFlags = 0 - clipVertices[p].Line = int(clipVertices[p].Y+1) - 1 - } - } else { - clipVertices[p].ClipFlags = 0 - clipVertices[p].Line = int(clipVertices[p].Y+1) - 1 - } - } - } - - // Now there are three or four vertices, in the top-to-bottom order of start, clip0, clip1, - // end. What kind of edges are required for connecting these can be determined from the - // clip flags. - // -if clip vertex has horizontal clip flags, it doesn't exist. No edge is generated. - // -if start vertex or end vertex has horizontal clip flag, the edge to/from the clip vertex is vertical - // -if the line of two vertices is the same, the edge is not generated, since the edge doesn't - // cross any scanlines. - - // The alternative patterns are: - // start - clip0 - clip1 - end - // start - clip0 - end - // start - clip1 - end - - var topClipIndex, bottomClipIndex int - if (clipVertices[0].ClipFlags|clipVertices[1].ClipFlags)& - (POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) == 0 { - // Both sides are clipped, the order is start-clip0-clip1-end - topClipIndex = 0 - bottomClipIndex = 1 - - // Add the edge from clip0 to clip1 - // Check that the line is different for the vertices. - if clipVertices[0].Line != clipVertices[1].Line { - firstClipLine := clipVertices[0].Line + 1 - - startx := vertexData[startIndex].X + - (float64(firstClipLine)-vertexData[startIndex].Y)*slope - - edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF) - edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF) - edges[edgeCount].FirstLine = firstClipLine - edges[edgeCount].LastLine = clipVertices[1].Line - edges[edgeCount].Winding = winding - - if edges[edgeCount].LastLine-edges[edgeCount].FirstLine >= SLOPE_FIX_STEP { - edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - - edges[edgeCount].Slope<= SLOPE_FIX_STEP { - edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - - edges[edgeCount].Slope<= SLOPE_FIX_STEP { - edges[edgeCount].SlopeFix = Fix(slope*SLOPE_FIX_STEP*FIXED_FLOAT_COEF) - - edges[edgeCount].Slope< cap(p.points) { - points := make([]float64, len(p.points)+2, len(p.points)+32) - copy(points, p.points) - p.points = points - } else { - p.points = p.points[0 : len(p.points)+2] - } - p.points[len(p.points)-2] = x - p.points[len(p.points)-1] = y -} - -func TestFreetype(t *testing.T) { - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - poly := Polygon(p.points) - color := color.RGBA{0, 0, 0, 0xff} - - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - rasterizer := raster.NewRasterizer(200, 200) - rasterizer.UseNonZeroWinding = false - rasterizer.Start(raster.Point{ - X: raster.Fix32(10 * 256), - Y: raster.Fix32(190 * 256)}) - for j := 0; j < len(poly); j = j + 2 { - rasterizer.Add1(raster.Point{ - X: raster.Fix32(poly[j] * 256), - Y: raster.Fix32(poly[j+1] * 256)}) - } - painter := raster.NewRGBAPainter(img) - painter.SetColor(color) - rasterizer.Rasterize(painter) - - draw2dimg.SaveToPngFile("../output/raster/TestFreetype.png", img) -} - -func TestFreetypeNonZeroWinding(t *testing.T) { - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - poly := Polygon(p.points) - color := color.RGBA{0, 0, 0, 0xff} - - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - rasterizer := raster.NewRasterizer(200, 200) - rasterizer.UseNonZeroWinding = true - rasterizer.Start(raster.Point{ - X: raster.Fix32(10 * 256), - Y: raster.Fix32(190 * 256)}) - for j := 0; j < len(poly); j = j + 2 { - rasterizer.Add1(raster.Point{ - X: raster.Fix32(poly[j] * 256), - Y: raster.Fix32(poly[j+1] * 256)}) - } - painter := raster.NewRGBAPainter(img) - painter.SetColor(color) - rasterizer.Rasterize(painter) - - draw2dimg.SaveToPngFile("../output/raster/TestFreetypeNonZeroWinding.png", img) -} - -func TestRasterizer(t *testing.T) { - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - - poly := Polygon(p.points) - color := color.RGBA{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) - draw2dimg.SaveToPngFile("../output/raster/TestRasterizer.png", img) -} - -func TestRasterizerNonZeroWinding(t *testing.T) { - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - - poly := Polygon(p.points) - color := color.RGBA{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) - draw2dimg.SaveToPngFile("../output/raster/TestRasterizerNonZeroWinding.png", img) -} - -func BenchmarkFreetype(b *testing.B) { - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - - poly := Polygon(p.points) - color := color.RGBA{0, 0, 0, 0xff} - - for i := 0; i < b.N; i++ { - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - rasterizer := raster.NewRasterizer(200, 200) - rasterizer.UseNonZeroWinding = false - rasterizer.Start(raster.Point{ - X: raster.Fix32(10 * 256), - Y: raster.Fix32(190 * 256)}) - for j := 0; j < len(poly); j = j + 2 { - rasterizer.Add1(raster.Point{ - X: raster.Fix32(poly[j] * 256), - Y: raster.Fix32(poly[j+1] * 256)}) - } - painter := raster.NewRGBAPainter(img) - painter.SetColor(color) - rasterizer.Rasterize(painter) - } -} - -func BenchmarkFreetypeNonZeroWinding(b *testing.B) { - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - - poly := Polygon(p.points) - color := color.RGBA{0, 0, 0, 0xff} - - for i := 0; i < b.N; i++ { - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - rasterizer := raster.NewRasterizer(200, 200) - rasterizer.UseNonZeroWinding = true - rasterizer.Start(raster.Point{ - X: raster.Fix32(10 * 256), - Y: raster.Fix32(190 * 256)}) - for j := 0; j < len(poly); j = j + 2 { - rasterizer.Add1(raster.Point{ - X: raster.Fix32(poly[j] * 256), - Y: raster.Fix32(poly[j+1] * 256)}) - } - painter := raster.NewRGBAPainter(img) - painter.SetColor(color) - rasterizer.Rasterize(painter) - } -} - -func BenchmarkRasterizerNonZeroWinding(b *testing.B) { - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - - poly := Polygon(p.points) - color := color.RGBA{0, 0, 0, 0xff} - tr := [6]float64{1, 0, 0, 1, 0, 0} - for i := 0; i < b.N; i++ { - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - rasterizer := NewRasterizer8BitsSample(200, 200) - rasterizer.RenderNonZeroWinding(img, &color, &poly, tr) - } -} - -func BenchmarkRasterizer(b *testing.B) { - var p Path - p.LineTo(10, 190) - draw2dbase.TraceCubic(&p, []float64{10, 190, 10, 10, 190, 10, 190, 190}, 0.5) - - poly := Polygon(p.points) - color := color.RGBA{0, 0, 0, 0xff} - tr := [6]float64{1, 0, 0, 1, 0, 0} - for i := 0; i < b.N; i++ { - img := image.NewRGBA(image.Rect(0, 0, 200, 200)) - rasterizer := NewRasterizer8BitsSample(200, 200) - rasterizer.RenderEvenOdd(img, &color, &poly, tr) - } -}