2015-04-16 09:51:13 +00:00
|
|
|
// Copyright 2011 The draw2d Authors. All rights reserved.
|
|
|
|
// created: 27/05/2011 by Laurent Le Goff
|
2011-05-27 16:19:42 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
//! A more optimized representation of a polygon edge.
|
2011-06-01 07:38:45 +00:00
|
|
|
type PolygonScanEdge struct {
|
|
|
|
FirstLine, LastLine int
|
|
|
|
Winding int16
|
|
|
|
X Fix
|
|
|
|
Slope Fix
|
|
|
|
SlopeFix Fix
|
|
|
|
NextEdge *PolygonScanEdge
|
|
|
|
}
|
2011-05-27 16:19:42 +00:00
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
//! 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.
|
2011-05-27 16:19:42 +00:00
|
|
|
*/
|
|
|
|
func (p Polygon) getEdges(startIndex, vertexCount int, edges []PolygonEdge, tr [6]float64, clipBound [4]float64) int {
|
|
|
|
startIndex = startIndex * 2
|
2011-06-01 07:38:45 +00:00
|
|
|
endIndex := startIndex + vertexCount*2
|
2011-05-27 16:19:42 +00:00
|
|
|
if endIndex > len(p) {
|
|
|
|
endIndex = len(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
x := p[startIndex]
|
|
|
|
y := p[startIndex+1]
|
2015-04-16 09:51:13 +00:00
|
|
|
// inline transformation
|
2011-05-27 16:19:42 +00:00
|
|
|
prevX := x*tr[0] + y*tr[2] + tr[4]
|
|
|
|
prevY := x*tr[1] + y*tr[3] + tr[5]
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
//! Calculates the clip flags for a point.
|
2011-05-27 16:19:42 +00:00
|
|
|
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]
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
//! Calculates the clip flags for a point.
|
2011-05-27 16:19:42 +00:00
|
|
|
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
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Skip all edges that are either completely outside at the top or at the bottom.
|
2011-06-01 07:38:45 +00:00
|
|
|
if clipUnion&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) == 0 {
|
|
|
|
if clipUnion&POLYGON_CLIP_RIGHT != 0 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Both clip to right, edge is a vertical line on the right side
|
2011-06-01 07:38:45 +00:00
|
|
|
if getVerticalEdge(prevY, y, clipBound[2], &edges[edgeCount], clipBound) {
|
2011-05-27 16:19:42 +00:00
|
|
|
edgeCount++
|
|
|
|
}
|
2011-06-01 07:38:45 +00:00
|
|
|
} else if clipUnion&POLYGON_CLIP_LEFT != 0 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Both clip to left, edge is a vertical line on the left side
|
2011-06-01 07:38:45 +00:00
|
|
|
if getVerticalEdge(prevY, y, clipBound[0], &edges[edgeCount], clipBound) {
|
2011-05-27 16:19:42 +00:00
|
|
|
edgeCount++
|
|
|
|
}
|
2011-06-01 07:38:45 +00:00
|
|
|
} else if clipSum&(POLYGON_CLIP_RIGHT|POLYGON_CLIP_LEFT) == 0 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// No clipping in the horizontal direction
|
2011-06-01 07:38:45 +00:00
|
|
|
if getEdge(prevX, prevY, x, y, &edges[edgeCount], clipBound) {
|
2011-05-27 16:19:42 +00:00
|
|
|
edgeCount++
|
|
|
|
}
|
|
|
|
} else {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Clips to left or right or both.
|
2011-05-27 16:19:42 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2011-06-01 07:38:45 +00:00
|
|
|
if clipSum&POLYGON_CLIP_RIGHT != 0 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// calculate new position for the right vertex
|
2011-05-27 16:19:42 +00:00
|
|
|
oldY = yright
|
|
|
|
maxX = clipBound[2]
|
|
|
|
|
|
|
|
yright = yleft + (maxX-xleft)*slope
|
|
|
|
xright = maxX
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// add vertical edge for the overflowing part
|
2011-06-01 07:38:45 +00:00
|
|
|
if getVerticalEdge(yright, oldY, maxX, &edges[edgeCount], clipBound) {
|
2011-05-27 16:19:42 +00:00
|
|
|
edges[edgeCount].Winding *= swapWinding
|
|
|
|
edgeCount++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-01 07:38:45 +00:00
|
|
|
if clipSum&POLYGON_CLIP_LEFT != 0 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// calculate new position for the left vertex
|
2011-05-27 16:19:42 +00:00
|
|
|
oldY = yleft
|
|
|
|
minX = clipBound[0]
|
|
|
|
|
|
|
|
yleft = yleft + (minX-xleft)*slope
|
|
|
|
xleft = minX
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// add vertical edge for the overflowing part
|
2011-06-01 07:38:45 +00:00
|
|
|
if getVerticalEdge(oldY, yleft, minX, &edges[edgeCount], clipBound) {
|
2011-05-27 16:19:42 +00:00
|
|
|
edges[edgeCount].Winding *= swapWinding
|
|
|
|
edgeCount++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-01 07:38:45 +00:00
|
|
|
if getEdge(xleft, yleft, xright, yright, &edges[edgeCount], clipBound) {
|
2011-05-27 16:19:42 +00:00
|
|
|
edges[edgeCount].Winding *= swapWinding
|
|
|
|
edgeCount++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prevClipFlags = clipFlags
|
|
|
|
prevX = x
|
|
|
|
prevY = y
|
|
|
|
}
|
|
|
|
|
|
|
|
return edgeCount
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
//! 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.
|
2011-05-27 16:19:42 +00:00
|
|
|
*/
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// 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.
|
2011-05-27 16:19:42 +00:00
|
|
|
|
2011-06-01 07:38:45 +00:00
|
|
|
firstLine := int(startY + 1)
|
|
|
|
lastLine := int(endY+1) - 1
|
2011-05-27 16:19:42 +00:00
|
|
|
|
|
|
|
minClip := int(clipBound[1])
|
|
|
|
maxClip := int(clipBound[3])
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// 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.
|
2011-05-27 16:19:42 +00:00
|
|
|
if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Adjust the start based on the target.
|
2011-05-27 16:19:42 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
//! 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.
|
2011-05-27 16:19:42 +00:00
|
|
|
*/
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2011-06-01 07:38:45 +00:00
|
|
|
firstLine := int(start + 1)
|
|
|
|
lastLine := int(end+1) - 1
|
2011-05-27 16:19:42 +00:00
|
|
|
|
|
|
|
minClip := int(clipBound[1])
|
|
|
|
maxClip := int(clipBound[3])
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// 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.
|
2011-05-27 16:19:42 +00:00
|
|
|
if firstLine > lastLine || lastLine < minClip || firstLine >= maxClip {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Adjust the start based on the clip rect.
|
2011-05-27 16:19:42 +00:00
|
|
|
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
|
|
|
|
}
|
2011-06-01 07:38:45 +00:00
|
|
|
|
|
|
|
type VertexData struct {
|
|
|
|
X, Y float64
|
|
|
|
ClipFlags int
|
|
|
|
Line int
|
|
|
|
}
|
2012-03-29 14:52:12 +00:00
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
//! 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.
|
2011-06-01 07:38:45 +00:00
|
|
|
*/
|
|
|
|
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]
|
2015-04-16 09:51:13 +00:00
|
|
|
// Calculate clip flags for all vertices.
|
2011-06-01 07:38:45 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Calculate line of the vertex. If the vertex is clipped by top or bottom, the line
|
|
|
|
// is determined by the clip rectangle.
|
2011-06-01 07:38:45 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Copy the data from 0 to the last entry to make the data to loop.
|
2011-06-01 07:38:45 +00:00
|
|
|
vertexData[len(vertexData)-1] = vertexData[0]
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Transform the first vertex; store.
|
|
|
|
// Process mVertexCount - 1 times, next is n+1
|
|
|
|
// copy the first vertex to
|
|
|
|
// Process 1 time, next is n
|
2011-06-01 07:38:45 +00:00
|
|
|
|
|
|
|
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 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Both clip to right, edge is a vertical line on the right side
|
2011-06-01 07:38:45 +00:00
|
|
|
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 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Both clip to left, edge is a vertical line on the left side
|
2011-06-01 07:38:45 +00:00
|
|
|
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 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// No clipping in the horizontal direction
|
2011-06-01 07:38:45 +00:00
|
|
|
slope := (vertexData[endIndex].X -
|
|
|
|
vertexData[startIndex].X) /
|
|
|
|
(vertexData[endIndex].Y -
|
|
|
|
vertexData[startIndex].Y)
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// 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.
|
2011-06-01 07:38:45 +00:00
|
|
|
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<<SLOPE_FIX_SHIFT
|
|
|
|
} else {
|
|
|
|
edges[edgeCount].SlopeFix = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
edgeCount++
|
|
|
|
} else {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Clips to left or right or both.
|
2011-06-01 07:38:45 +00:00
|
|
|
slope := (vertexData[endIndex].X -
|
|
|
|
vertexData[startIndex].X) /
|
|
|
|
(vertexData[endIndex].Y -
|
|
|
|
vertexData[startIndex].Y)
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// The edge may clip to both left and right.
|
|
|
|
// The clip results in one or two new vertices, and one to three segments.
|
|
|
|
// The rounding for scanlines may produce a result where any of the segments is
|
|
|
|
// ignored.
|
2011-06-01 07:38:45 +00:00
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// The start is always above the end. Calculate the clip positions to clipVertices.
|
|
|
|
// It is possible that only one of the vertices exist. This will be detected from the
|
|
|
|
// clip flags of the vertex later, so they are initialized here.
|
2011-06-01 07:38:45 +00:00
|
|
|
var clipVertices [2]VertexData
|
|
|
|
|
|
|
|
if vertexData[startIndex].X <
|
|
|
|
vertexData[endIndex].X {
|
|
|
|
clipVertices[0].X = clipBound[0]
|
|
|
|
clipVertices[1].X = clipBound[2]
|
|
|
|
clipVertices[0].ClipFlags = POLYGON_CLIP_LEFT
|
|
|
|
clipVertices[1].ClipFlags = POLYGON_CLIP_RIGHT
|
|
|
|
} else {
|
|
|
|
clipVertices[0].X = clipBound[2]
|
|
|
|
clipVertices[1].X = clipBound[0]
|
|
|
|
clipVertices[0].ClipFlags = POLYGON_CLIP_RIGHT
|
|
|
|
clipVertices[1].ClipFlags = POLYGON_CLIP_LEFT
|
|
|
|
}
|
|
|
|
|
|
|
|
var p int
|
|
|
|
for p = 0; p < 2; p++ {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Check if either of the vertices crosses the edge marked for the clip vertex
|
2011-06-01 07:38:45 +00:00
|
|
|
if clipSum&clipVertices[p].ClipFlags != 0 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// The the vertex is required, calculate it.
|
2011-06-01 07:38:45 +00:00
|
|
|
clipVertices[p].Y = vertexData[startIndex].Y +
|
|
|
|
(clipVertices[p].X-
|
|
|
|
vertexData[startIndex].X)/slope
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// If there is clipping in the vertical direction, the new vertex may be clipped.
|
2011-06-01 07:38:45 +00:00
|
|
|
if clipSum&(POLYGON_CLIP_TOP|POLYGON_CLIP_BOTTOM) != 0 {
|
|
|
|
if clipVertices[p].Y < clipBound[1] {
|
|
|
|
clipVertices[p].ClipFlags = POLYGON_CLIP_TOP
|
|
|
|
clipVertices[p].Line = int(clipBound[1])
|
|
|
|
} else if clipVertices[p].Y > 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// 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.
|
2011-06-01 07:38:45 +00:00
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// The alternative patterns are:
|
|
|
|
// start - clip0 - clip1 - end
|
|
|
|
// start - clip0 - end
|
|
|
|
// start - clip1 - end
|
2011-06-01 07:38:45 +00:00
|
|
|
|
|
|
|
var topClipIndex, bottomClipIndex int
|
|
|
|
if (clipVertices[0].ClipFlags|clipVertices[1].ClipFlags)&
|
|
|
|
(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) == 0 {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Both sides are clipped, the order is start-clip0-clip1-end
|
2011-06-01 07:38:45 +00:00
|
|
|
topClipIndex = 0
|
|
|
|
bottomClipIndex = 1
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Add the edge from clip0 to clip1
|
|
|
|
// Check that the line is different for the vertices.
|
2011-06-01 07:38:45 +00:00
|
|
|
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_SHIFT
|
|
|
|
} else {
|
|
|
|
edges[edgeCount].SlopeFix = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
edgeCount++
|
|
|
|
}
|
|
|
|
} else {
|
2015-04-16 09:51:13 +00:00
|
|
|
// Clip at either side, check which side. The clip flag is on for the vertex
|
|
|
|
// that doesn't exist, i.e. has not been clipped to be inside the rect.
|
2011-06-01 07:38:45 +00:00
|
|
|
if clipVertices[0].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
|
|
|
|
topClipIndex = 1
|
|
|
|
bottomClipIndex = 1
|
|
|
|
} else {
|
|
|
|
topClipIndex = 0
|
|
|
|
bottomClipIndex = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Generate the edges from start - clip top and clip bottom - end
|
|
|
|
// Clip top and clip bottom may be the same vertex if there is only one
|
|
|
|
// clipped vertex.
|
2011-06-01 07:38:45 +00:00
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Check that the line is different for the vertices.
|
2011-06-01 07:38:45 +00:00
|
|
|
if vertexData[startIndex].Line != clipVertices[topClipIndex].Line {
|
|
|
|
edges[edgeCount].FirstLine = firstLine
|
|
|
|
edges[edgeCount].LastLine = clipVertices[topClipIndex].Line
|
|
|
|
edges[edgeCount].Winding = winding
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// If startIndex is clipped, the edge is a vertical one.
|
2011-06-01 07:38:45 +00:00
|
|
|
if vertexData[startIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
|
|
|
|
edges[edgeCount].X = Fix(clipVertices[topClipIndex].X * FIXED_FLOAT_COEF)
|
|
|
|
edges[edgeCount].Slope = 0
|
|
|
|
edges[edgeCount].SlopeFix = 0
|
|
|
|
} else {
|
|
|
|
startx := vertexData[startIndex].X +
|
|
|
|
(float64(firstLine)-vertexData[startIndex].Y)*slope
|
|
|
|
|
|
|
|
edges[edgeCount].X = Fix(startx * FIXED_FLOAT_COEF)
|
|
|
|
edges[edgeCount].Slope = Fix(slope * FIXED_FLOAT_COEF)
|
|
|
|
|
|
|
|
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_SHIFT
|
|
|
|
} else {
|
|
|
|
edges[edgeCount].SlopeFix = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
edgeCount++
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// Check that the line is different for the vertices.
|
2011-06-01 07:38:45 +00:00
|
|
|
if clipVertices[bottomClipIndex].Line != vertexData[endIndex].Line {
|
|
|
|
firstClipLine := clipVertices[bottomClipIndex].Line + 1
|
|
|
|
|
|
|
|
edges[edgeCount].FirstLine = firstClipLine
|
|
|
|
edges[edgeCount].LastLine = lastLine
|
|
|
|
edges[edgeCount].Winding = winding
|
|
|
|
|
2015-04-16 09:51:13 +00:00
|
|
|
// If endIndex is clipped, the edge is a vertical one.
|
2011-06-01 07:38:45 +00:00
|
|
|
if vertexData[endIndex].ClipFlags&(POLYGON_CLIP_LEFT|POLYGON_CLIP_RIGHT) != 0 {
|
|
|
|
edges[edgeCount].X = Fix(clipVertices[bottomClipIndex].X * FIXED_FLOAT_COEF)
|
|
|
|
edges[edgeCount].Slope = 0
|
|
|
|
edges[edgeCount].SlopeFix = 0
|
|
|
|
} else {
|
|
|
|
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)
|
|
|
|
|
|
|
|
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_SHIFT
|
|
|
|
} else {
|
|
|
|
edges[edgeCount].SlopeFix = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
edgeCount++
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return edgeCount
|
|
|
|
}
|