//////////////////
// GradientLayerMesh
GradientLayerMesh::GradientLayerMesh(const Rect &rect,Vec2 axisStart,Vec2 axisEnd,const Gradient *gradient)
{
	ConvexPolygon rectPol = 
	{
		rect.GetCorner(0),
		rect.GetCorner(2),
		rect.GetCorner(3),
		rect.GetCorner(1),
	};
	
	std::vector<float> slicePositions;
	for(int i = 0;i < gradient->GetNumVertices();i++)
	{
		slicePositions.push_back(gradient->GetVertexPos(i));
	}
	
	Vec2 axis = axisEnd - axisStart;
	axis /= axis.GetSqrLen();
	float axisOffset = -Dot(axis,axisStart);
	
	std::vector<ParallelSlice> slices = rectPol.GetParallelSlices(
		axisStart,axisEnd,slicePositions.data(),(int)slicePositions.size());
	for(const ParallelSlice &slice : slices)
	{
		int seg = slice.GetSegment();
		if(seg == 0)
		{
			std::vector<Triangle2D> tris = slice.GetPolygon().Triangulate();
			for(const Triangle2D &tri : tris)
			{
				mVertices.push_back(tri.mVertices[0]);
				mVertices.push_back(tri.mVertices[1]);
				mVertices.push_back(tri.mVertices[2]);
				
				mColors.push_back(MakeVec4(1,0,0,1));
				mColors.push_back(MakeVec4(0,1,0,1));
				mColors.push_back(MakeVec4(0,0,1,1));
			}
		}
		else if(seg == gradient->GetNumVertices())
		{
			std::vector<Triangle2D> tris = slice.GetPolygon().Triangulate();
			for(const Triangle2D &tri : tris)
			{
				mVertices.push_back(tri.mVertices[0]);
				mVertices.push_back(tri.mVertices[1]);
				mVertices.push_back(tri.mVertices[2]);
				
				mColors.push_back(MakeVec4(1,0,0,1));
				mColors.push_back(MakeVec4(0,1,0,1));
				mColors.push_back(MakeVec4(0,0,1,1));
			}
		}
		else
		{
			std::vector<Triangle2D> tris = slice.GetPolygon().Triangulate();
			for(const Triangle2D &tri : tris)
			{
				for(int i = 0;i < 3;i++)
				{
					mVertices.push_back(tri.mVertices[i]);
				
					float t = Dot(axis,tri.mVertices[i]) + axisOffset;
					float segT = (t - slicePositions[seg - 1]) / (slicePositions[seg] - slicePositions[seg - 1]);
					
					Vec4 color = gradient->GetVertexColor(seg - 1) * (1 - segT) + gradient->GetVertexColor(seg) * segT;
					mColors.push_back(color);
				}
			}
		}
	}
}
std::vector<ParallelSlice> ConvexPolygon::GetParallelSlices(const Vec2 &min,const Vec2 &max,
	const float *slicePositions,int numSlicePositions) const
{
	int numVerts = GetNumVertices();
	const Vec2 *vertices = GetVertices();
	
	assert((max - min).GetSqrLen() > .001f);
	assert(std::is_sorted(slicePositions,slicePositions + numSlicePositions));
	
	Vec2 axis = max - min;
	axis /= axis.GetSqrLen();
	float axisOrigin = Dot(axis,min);
	
	std::vector<float> vertOnAxis(numVerts);
	for(int i = 0;i < numVerts;i++)
		vertOnAxis[i] = Dot(axis,vertices[i]) - axisOrigin;
	
	int minVert = (int)(std::min_element(vertOnAxis.begin(),vertOnAxis.end()) - vertOnAxis.begin());
	int maxVert = (int)(std::max_element(vertOnAxis.begin(),vertOnAxis.end()) - vertOnAxis.begin());
	
#ifndef NDEBUG
	for(int i = 0;i < numVerts;i++)
	{
		assert(vertOnAxis[i] >= vertOnAxis[minVert]);
		assert(vertOnAxis[i] <= vertOnAxis[maxVert]);
	}
#endif
	
	// Segments are indexed so that their index matches the index of the high slice.
	// minSeg and maxSeg describes the range [minSeg,maxSeg] of intervals which contain a part
	// of the polygon in their interior. minSeg is thus the index of the first slicePosition
	// that is strictly greater than minPos, and maxSeg the index of the first slicePosition
	// that is greater than or equal to maxPos
	int minSeg = numSlicePositions;
	int maxSeg = numSlicePositions;
	for(int i = 0;i < numSlicePositions;i++)
	{
		if(vertOnAxis[minVert] < slicePositions[i])
		{
			minSeg = i;
			break;
		}
	}
	
	for(int i = minSeg;i < numSlicePositions;i++)
	{
		if(vertOnAxis[maxVert] <= slicePositions[i])
		{
			maxSeg = i;
			break;
		}
	}
		
	assert(minSeg == 0 || vertOnAxis[minVert] >= slicePositions[minSeg - 1]); 
	assert(minSeg == numSlicePositions || vertOnAxis[minVert] < slicePositions[minSeg]);
	assert(maxSeg == 0 || vertOnAxis[maxVert]  > slicePositions[maxSeg - 1]); 
	assert(maxSeg == numSlicePositions || vertOnAxis[maxVert] <= slicePositions[maxSeg]);
				
	// index of the vertex at the beginning of the current counter clockwise/clockwise edge respectively.
	int ccwPrevVert = minVert;
	int cwPrevVert = minVert;
		
	// index of the vertex at the end of the current counter clockwise/clockwise edge respectively.
	int ccwVert = (minVert + 1) % numVerts;
	int cwVert = (minVert - 1 + numVerts) % numVerts;
	
	std::vector<ParallelSlice> ret;
	
	std::vector<Vec2> nextPol;
	nextPol.push_back(vertices[minVert]);
	
	for(int seg = minSeg;seg < maxSeg;seg++)
	{
		std::vector<Vec2> curPol;
		curPol.swap(nextPol);
		
		while(true)
		{
			float curPos = vertOnAxis[ccwVert];
			if(curPos < slicePositions[seg])
			{
				curPol.push_back(vertices[ccwVert]);
				
				ccwPrevVert = ccwVert;
				ccwVert = (ccwVert + 1) % numVerts;
			}
			else if(curPos > slicePositions[seg])
			{
				float prevPos = vertOnAxis[ccwPrevVert];
				
				float t = (slicePositions[seg] - prevPos) / (curPos - prevPos);
				Vec2 newVert = vertices[ccwPrevVert] + t * (vertices[ccwVert] - vertices[ccwPrevVert]);
				curPol.push_back(newVert);
				nextPol.push_back(newVert);
				break;
			}
			else //if(pos == slicePositions[seg])
			{
				curPol.push_back(vertices[ccwVert]);
				nextPol.push_back(vertices[ccwVert]);
				
				ccwPrevVert = ccwVert;
				ccwVert = (ccwVert + 1) % numVerts;
				break;
			}
		}
		
		int firstClockWise = (int)curPol.size();
		
		while(true)
		{
			float curPos = vertOnAxis[cwVert];
			if(curPos < slicePositions[seg])
			{
				curPol.push_back(vertices[cwVert]);
				
				cwPrevVert = cwVert;
				cwVert = (cwVert + numVerts - 1) % numVerts;
			}
			else if(curPos > slicePositions[seg])
			{
				float prevPos = vertOnAxis[cwPrevVert];
				
				float t = (slicePositions[seg] - prevPos) / (curPos - prevPos);
				Vec2 newVert = vertices[cwPrevVert] + t * (vertices[cwVert] - vertices[cwPrevVert]);
				curPol.push_back(newVert);
				nextPol.push_back(newVert);
				break;
			}
			else //if(pos == slicePositions[seg])
			{
				curPol.push_back(vertices[cwVert]);
				nextPol.push_back(vertices[cwVert]);

				cwPrevVert = cwVert;
				cwVert = (cwVert + numVerts - 1) % numVerts;
				break;
			}
		}
		
		std::reverse(curPol.begin() + firstClockWise,curPol.end());
		std::reverse(nextPol.begin(), nextPol.end());
		
		ret.push_back(ParallelSlice(ConvexPolygon(curPol),seg));
	}
	
	// special case for the last segment, where, among other things, we may not
	// have a value for slicePositions[seg] (may be outside its bounds).
	{
		std::vector<Vec2> lastPol = nextPol;
		while(ccwVert != cwVert)
		{
			lastPol.push_back(vertices[ccwVert]);
			ccwVert = (ccwVert + 1) % numVerts;
		}
		
		lastPol.push_back(vertices[cwVert]);
		
		ret.push_back(ParallelSlice(ConvexPolygon(lastPol),maxSeg));
	}
	
	return ret;
}