1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47:
48:
51: public final class ScanlineConverter
52: {
53:
54:
57: private static int FIXED_DIGITS = 6;
58:
59:
62: private static int ONE = Fixed.fixedValue(FIXED_DIGITS, 1);
63:
64:
67: private int numScanlines;
68:
69:
75: private Scanline[] scanlines;
76:
77:
82: private int upperBounds;
83:
84:
89: private int resolution;
90:
91:
94: private int yResolution;
95:
96:
100: private int halfStep;
101:
102:
106: private float[] coords;
107:
108:
111: private ActiveEdges activeEdges;
112:
113: private PolyEdge edgePool;
114: private PolyEdge edgePoolLast;
115:
116: private int minY;
117: private int maxY;
118: private int minX;
119: private int maxX;
120:
121:
124: private ScanlineCoverage scanlineCoverage;
125:
126:
129: ScanlineConverter()
130: {
131: scanlines = new Scanline[10];
132: coords = new float[6];
133: activeEdges = new ActiveEdges();
134: edgePool = new PolyEdge();
135: edgePoolLast = edgePool;
136: scanlineCoverage = new ScanlineCoverage();
137: }
138:
139:
147: public void renderShape(Pixelizer p, Shape shape, Shape clip,
148: AffineTransform trans, int res, int yRes,
149: RenderingHints hints)
150: {
151:
152:
153:
154:
155: clear();
156: setResolution(res, yRes);
157:
158: boolean haveClip = clip != null;
159:
160:
161: float flatness = Fixed.floatValue(FIXED_DIGITS, resolution / 2);
162: PathIterator path = shape.getPathIterator(trans, flatness);
163: addShape(path, false);
164: if (haveClip)
165: {
166: path= clip.getPathIterator(trans, flatness);
167: addShape(path, true);
168: }
169:
170: setUpperBounds(minY);
171:
172: PolyEdge edge = edgePool;
173: while (edge != edgePoolLast)
174: {
175: addEdge(edge);
176: edge = edge.poolNext;
177: }
178:
179: int y = upperBounds;
180: int index;
181: activeEdges.clear();
182:
183: Scanline scanline = null;
184: int lastRealY = Fixed.intValue(FIXED_DIGITS, y);
185: while (y <= maxY)
186: {
187:
188: index = scanlineIndex(y);
189:
190:
191: scanline = index < scanlines.length ? scanlines[index] : null;
192: if (scanline != null)
193: {
194: edge = scanline.getEdges();
195: while (edge != null)
196: {
197: activeEdges.add(edge);
198: edge = edge.scanlineNext;
199: }
200: }
201:
202:
203:
204: activeEdges.intersectSortAndPack(FIXED_DIGITS, y + halfStep);
205:
206:
207: int realY = Fixed.intValue(FIXED_DIGITS, y + resolution);
208: boolean push = lastRealY != realY;
209:
210: doScanline(p, y, push, haveClip);
211:
212:
213:
214:
215: y += resolution;
216: lastRealY = realY;
217:
218: }
219: }
220:
221:
224: private void clear()
225: {
226:
227: edgePoolLast = edgePool;
228:
229:
230: for (int i = scanlines.length - 1; i >= 0 ; i--)
231: {
232: Scanline sl = scanlines[i];
233: if (sl != null)
234: sl.clear();
235: }
236:
237:
238: scanlineCoverage.clear();
239:
240:
241: minY = Integer.MAX_VALUE;
242: maxY = Integer.MIN_VALUE;
243: minX = Integer.MAX_VALUE;
244: maxX = Integer.MIN_VALUE;
245: }
246:
247:
256: private void doScanline(Pixelizer p, int y, boolean push,
257: boolean haveClip)
258: {
259:
260: scanlineCoverage.rewind();
261:
262:
263:
264: boolean inClip = ! haveClip;
265: boolean inShape = false;
266: PolyEdge lastEdge = null;
267: int numEdges = activeEdges.getNumActiveEdges();
268: for (int i = 0; i < numEdges; i++)
269: {
270: PolyEdge edge = activeEdges.getActiveEdge(i);
271: if (inClip && inShape)
272: {
273: assert lastEdge != null;
274: int x0 = lastEdge.xIntersection;
275: int x1 = edge.xIntersection;
276: assert x0 <= x1;
277:
278: int pix0 = Fixed.intValue(FIXED_DIGITS, x0);
279: int pix1 = Fixed.intValue(FIXED_DIGITS, x1);
280: int frac0 = ONE - Fixed.trunc(FIXED_DIGITS, x0);
281: int frac1 = ONE - Fixed.trunc(FIXED_DIGITS, x1);
282:
283: frac0 = frac0 >> (FIXED_DIGITS - yResolution);
284: frac1 = frac1 >> (FIXED_DIGITS - yResolution);
285: scanlineCoverage.add(pix0, 1 * (1 << yResolution), frac0);
286: scanlineCoverage.add(pix1, -1 * (1 << yResolution), -frac1);
287: }
288: if (edge.isClip)
289: inClip = ! inClip;
290: else
291: inShape = ! inShape;
292:
293: lastEdge = edge;
294: }
295:
296:
297: if (push && ! scanlineCoverage.isEmpty())
298: {
299: p.renderScanline(Fixed.intValue(FIXED_DIGITS, y), scanlineCoverage);
300: scanlineCoverage.clear();
301: }
302: }
303:
304:
305:
311: private void setResolution(int res, int yRes)
312: {
313: int scanlinesPerPixel = 1 << res;
314: int one = Fixed.fixedValue(FIXED_DIGITS, 1);
315: resolution = one / (scanlinesPerPixel);
316: halfStep = resolution / 2;
317:
318: scanlineCoverage.setMaxCoverage(scanlinesPerPixel << yResolution);
319:
320: yResolution = yRes;
321: }
322:
323:
328: private void setUpperBounds(int y0)
329: {
330: upperBounds = fit(y0);
331: }
332:
333:
339: private void addShape(PathIterator path, boolean clip)
340: {
341: int startX = 0;
342: int startY = 0;
343: int lastX = 0;
344: int lastY = 0;
345: while (! path.isDone())
346: {
347: int type = path.currentSegment(coords);
348: switch (type)
349: {
350: case PathIterator.SEG_MOVETO:
351: startX = lastX = Fixed.fixedValue(FIXED_DIGITS, coords[0]);
352: startY = lastY = Fixed.fixedValue(FIXED_DIGITS, coords[1]);
353: minY = Math.min(startY, minY);
354: maxY = Math.max(startY, maxY);
355: minX = Math.min(startX, minX);
356: maxX = Math.max(startX, maxX);
357: break;
358: case PathIterator.SEG_LINETO:
359: int x = Fixed.fixedValue(FIXED_DIGITS, coords[0]);
360: int y = Fixed.fixedValue(FIXED_DIGITS, coords[1]);
361: edgePoolAdd(lastX, lastY, x, y, clip);
362: lastX = x;
363: lastY = y;
364: minY = Math.min(lastY, minY);
365: maxY = Math.max(lastY, maxY);
366: minX = Math.min(lastX, minX);
367: maxX = Math.max(lastX, maxX);
368: break;
369: case PathIterator.SEG_CLOSE:
370: edgePoolAdd(lastX, lastY, startX, startY, clip);
371: lastX = startX;
372: lastY = startY;
373: break;
374: case PathIterator.SEG_CUBICTO:
375: case PathIterator.SEG_QUADTO:
376: default:
377: assert false;
378: }
379: path.next();
380: }
381: }
382:
383:
386: private void addEdge(PolyEdge edge)
387: {
388:
389: int upper = Math.min(edge.y0, edge.y1);
390:
391: int index = scanlineIndex(upper);
392:
393: if (index >= scanlines.length)
394: {
395: int oldSize = scanlines.length;
396: int newSize = Math.max(oldSize + oldSize / 2 + 1, index + 10);
397: Scanline[] newScanlines = new Scanline[newSize];
398: System.arraycopy(scanlines, 0, newScanlines, 0, oldSize);
399: scanlines = newScanlines;
400: }
401:
402:
403: if (scanlines[index] == null)
404: {
405: scanlines[index] = new Scanline();
406: }
407: scanlines[index].addEdge(edge);
408: }
409:
410:
417: private int fit(int y)
418: {
419: int val1 = Fixed.div(FIXED_DIGITS, y, resolution);
420: int rounded = Fixed.round(FIXED_DIGITS, val1);
421: return Fixed.mul(FIXED_DIGITS, rounded, resolution);
422: }
423:
424:
431: private int scanlineIndex(int y)
432: {
433: int fitted = fit(y);
434:
435: return (fitted - upperBounds)/ resolution;
436: }
437:
438: private void edgePoolAdd(int x0, int y0, int x1, int y1, boolean clip)
439: {
440:
441: if (y0 != y1)
442: {
443: edgePoolLast.init(FIXED_DIGITS, x0, y0, x1, y1, clip);
444: if (edgePoolLast.poolNext == null)
445: {
446: edgePoolLast.poolNext = new PolyEdge();
447: }
448: edgePoolLast = edgePoolLast.poolNext;
449: }
450: }
451: }