// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vector

// This file contains a floating point math implementation of the vector
// graphics rasterizer.

import (
	
)

func floatingMax(,  float32) float32 {
	if  >  {
		return 
	}
	return 
}

func floatingMin(,  float32) float32 {
	if  <  {
		return 
	}
	return 
}

func floatingFloor( float32) int32 { return int32(math.Floor(float64())) }
func floatingCeil( float32) int32  { return int32(math.Ceil(float64())) }

func ( *Rasterizer) (,  float32) {
	,  := .penX, .penY
	.penX, .penY = , 
	 := float32(1)
	if  >  {
		, , , ,  = -1, , , , 
	}
	// Horizontal line segments yield no change in coverage. Almost horizontal
	// segments would yield some change, in ideal math, but the computation
	// further below, involving 1 / (by - ay), is unstable in floating point
	// math, so we treat the segment as if it was perfectly horizontal.
	if - <= 0.000001 {
		return
	}
	 := ( - ) / ( - )

	 := 
	 := floatingFloor()
	 := floatingCeil()
	if  > int32(.size.Y) {
		 = int32(.size.Y)
	}
	 := int32(.size.X)

	for ;  < ; ++ {
		 := floatingMin(float32(+1), ) - floatingMax(float32(), )

		// The "float32" in expressions like "float32(foo*bar)" here and below
		// look redundant, since foo and bar already have type float32, but are
		// explicit in order to disable the compiler's Fused Multiply Add (FMA)
		// instruction selection, which can improve performance but can result
		// in different rounding errors in floating point computations.
		//
		// This package aims to have bit-exact identical results across all
		// GOARCHes, and across pure Go code and assembly, so it disables FMA.
		//
		// See the discussion at
		// https://groups.google.com/d/topic/golang-dev/Sti0bl2xUXQ/discussion
		 :=  + float32(*)
		if  < 0 {
			 = 
			continue
		}
		 := .bufF32[*:]
		 := float32( * )
		,  := , 
		if  >  {
			,  = , 
		}
		 := floatingFloor()
		 := float32()
		 := floatingCeil()
		 := float32()

		if  <= +1 {
			 := float32(0.5*(+)) - 
			if  := clamp(+0, );  < uint(len()) {
				[] +=  - float32(*)
			}
			if  := clamp(+1, );  < uint(len()) {
				[] += float32( * )
			}
		} else {
			 := 1 / ( - )
			 :=  - 
			 := 1 - 
			 := float32(0.5 *  *  * )
			 :=  -  + 1
			 := float32(0.5 *  *  * )

			if  := clamp(, );  < uint(len()) {
				[] += float32( * )
			}

			if  == +2 {
				if  := clamp(+1, );  < uint(len()) {
					[] += float32( * (1 -  - ))
				}
			} else {
				 := float32( * (1.5 - ))
				if  := clamp(+1, );  < uint(len()) {
					[] += float32( * ( - ))
				}
				 := float32( * )
				for  :=  + 2;  < -1; ++ {
					if  := clamp(, );  < uint(len()) {
						[] += 
					}
				}
				 :=  + float32(*float32(--3))
				if  := clamp(-1, );  < uint(len()) {
					[] += float32( * (1 -  - ))
				}
			}

			if  := clamp(, );  < uint(len()) {
				[] += float32( * )
			}
		}

		 = 
	}
}

const (
	// almost256 scales a floating point value in the range [0, 1] to a uint8
	// value in the range [0x00, 0xff].
	//
	// 255 is too small. Floating point math accumulates rounding errors, so a
	// fully covered src value that would in ideal math be float32(1) might be
	// float32(1-ε), and uint8(255 * (1-ε)) would be 0xfe instead of 0xff. The
	// uint8 conversion rounds to zero, not to nearest.
	//
	// 256 is too big. If we multiplied by 256, below, then a fully covered src
	// value of float32(1) would translate to uint8(256 * 1), which can be 0x00
	// instead of the maximal value 0xff.
	//
	// math.Float32bits(almost256) is 0x437fffff.
	almost256 = 255.99998

	// almost65536 scales a floating point value in the range [0, 1] to a
	// uint16 value in the range [0x0000, 0xffff].
	//
	// math.Float32bits(almost65536) is 0x477fffff.
	almost65536 = almost256 * 256
)

func floatingAccumulateOpOver( []uint8,  []float32) {
	// Sanity check that len(dst) >= len(src).
	if len() < len() {
		return
	}

	 := float32(0)
	for ,  := range  {
		 += 
		 := 
		if  < 0 {
			 = -
		}
		if  > 1 {
			 = 1
		}
		// This algorithm comes from the standard library's image/draw package.
		 := uint32([]) * 0x101
		 := uint32(almost65536 * )
		 := *(0xffff-)/0xffff + 
		[] = uint8( >> 8)
	}
}

func floatingAccumulateOpSrc( []uint8,  []float32) {
	// Sanity check that len(dst) >= len(src).
	if len() < len() {
		return
	}

	 := float32(0)
	for ,  := range  {
		 += 
		 := 
		if  < 0 {
			 = -
		}
		if  > 1 {
			 = 1
		}
		[] = uint8(almost256 * )
	}
}

func floatingAccumulateMask( []uint32,  []float32) {
	// Sanity check that len(dst) >= len(src).
	if len() < len() {
		return
	}

	 := float32(0)
	for ,  := range  {
		 += 
		 := 
		if  < 0 {
			 = -
		}
		if  > 1 {
			 = 1
		}
		[] = uint32(almost65536 * )
	}
}