001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Denis M. Kishenko
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.render;
021:
022: import org.apache.harmony.awt.gl.MultiRectArea;
023:
024: public class JavaLineRasterizer {
025:
026: /**
027: * LineDasher class provides dashing for particular dash style
028: */
029: public static class LineDasher {
030:
031: int index;
032: float pos;
033: float phase;
034: float dash[];
035: float inv[];
036: boolean visible;
037:
038: public LineDasher() {
039: }
040:
041: public LineDasher(float dash[], float phase) {
042: this .dash = dash;
043: this .phase = phase;
044:
045: inv = new float[dash.length];
046: int j = dash.length;
047: for (float element : dash) {
048: inv[--j] = element;
049: }
050: index = 0;
051: while (phase > dash[index]) {
052: phase -= dash[index];
053: index = (index + 1) % dash.length;
054: }
055: visible = index % 2 == 0;
056: }
057:
058: void move(float step) { // main dasher
059: pos += step;
060: step += phase;
061: while (step >= dash[index]) {
062: step -= dash[index];
063: index = (index + 1) % dash.length;
064: visible = !visible;
065: }
066: phase = step;
067: }
068:
069: float nextDash() {
070: phase = 0.0f;
071: index = (index + 1) % dash.length;
072: visible = !visible;
073: return dash[index];
074: }
075:
076: LineDasher createDiagonal(double k, float length, boolean invert) {
077: LineDasher local = new LineDasher();
078: local.dash = new float[dash.length];
079: if (invert) { // inverted dasher
080: move(length);
081: local.phase = (float) ((dash[index] - phase) * k);
082: local.visible = visible;
083: local.index = inv.length - index - 1;
084: for (int i = 0; i < inv.length; i++) {
085: local.dash[i] = (float) (inv[i] * k);
086: }
087: } else {
088: local.phase = (float) (phase * k);
089: local.visible = visible;
090: local.index = index;
091: for (int i = 0; i < dash.length; i++) {
092: local.dash[i] = (float) (dash[i] * k);
093: }
094: move(length);
095: }
096: return local;
097: }
098:
099: LineDasher createOrtogonal(float length, boolean invert) {
100: LineDasher local = new LineDasher();
101: local.dash = new float[dash.length];
102: if (invert) { // inverted dasher
103: move(length);
104: local.phase = dash[index] - phase;
105: local.visible = visible;
106: local.index = inv.length - index - 1;
107: local.dash = inv;
108: } else {
109: local.phase = phase;
110: local.visible = visible;
111: local.index = index;
112: local.dash = dash;
113: move(length);
114: }
115: return local;
116: }
117:
118: LineDasher createChild(float start) {
119: LineDasher child = new LineDasher();
120: child.phase = phase;
121: child.visible = visible;
122: child.index = index;
123: child.dash = dash;
124: child.move(start);
125: return child;
126: }
127:
128: }
129:
130: /**
131: * Line class provides rasterization for different line types
132: */
133: abstract static class Line {
134:
135: int x1, y1, x2, y2;
136: int x, y;
137: MultiRectArea dst;
138:
139: Line(int x1, int y1, int x2, int y2, MultiRectArea dst) {
140: this .x1 = x1;
141: this .y1 = y1;
142: this .x2 = x2;
143: this .y2 = y2;
144: this .dst = dst;
145: }
146:
147: static abstract class Diag extends Line {
148: int dx, dy, adx, ady, sx, sy;
149: int eBase, ePos, eNeg;
150: int xcount;
151: int e;
152:
153: Diag(int x1, int y1, int x2, int y2, MultiRectArea dst) {
154: super (x1, y1, x2, y2, dst);
155: dx = x2 - x1;
156: dy = y2 - y1;
157: sy = 1;
158: if (dx > 0) {
159: adx = dx;
160: sx = 1;
161: } else {
162: adx = -dx;
163: sx = -1;
164: }
165: ady = dy;
166: }
167:
168: float getLength() {
169: return (float) Math.sqrt(dx * dx + dy * dy);
170: }
171:
172: static class Hor extends Diag {
173:
174: Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
175: super (x1, y1, x2, y2, dst);
176: eBase = ady + ady - adx;
177: ePos = 2 * (ady - adx);
178: eNeg = ady + ady;
179: xcount = adx;
180: }
181:
182: @Override
183: void rasterize() {
184: e = eBase;
185: x = x1;
186: y = y1;
187: rasterize(xcount);
188: }
189:
190: @Override
191: void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
192: e = eBase
193: + 2
194: * (ady * Math.abs(nx1 - x1) - adx
195: * Math.abs(ny1 - y1));
196: x = nx1;
197: y = ny1;
198: rasterize(dx > 0 ? nx2 - nx1 : nx1 - nx2);
199: }
200:
201: @Override
202: void rasterize(int count) {
203: int px = x;
204: while (count-- > 0) {
205: if (e >= 0) {
206: if (sx > 0) {
207: dst.addRect(px, y, x, y);
208: } else {
209: dst.addRect(x, y, px, y);
210: }
211: x += sx;
212: y += sy;
213: e += ePos;
214: px = x;
215: } else {
216: e += eNeg;
217: x += sx;
218: }
219: }
220: if (sx > 0) {
221: dst.addRect(px, y, x, y);
222: } else {
223: dst.addRect(x, y, px, y);
224: }
225: }
226:
227: @Override
228: void skip(int count) {
229: while (count-- > 0) {
230: x += sx;
231: if (e >= 0) {
232: y += sy;
233: e += ePos;
234: } else {
235: e += eNeg;
236: }
237: }
238: }
239:
240: }
241:
242: static class Ver extends Diag {
243:
244: Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
245: super (x1, y1, x2, y2, dst);
246: eBase = adx + adx - ady;
247: ePos = 2 * (adx - ady);
248: eNeg = adx + adx;
249: xcount = ady;
250: }
251:
252: @Override
253: void rasterize() {
254: e = eBase;
255: x = x1;
256: y = y1;
257: rasterize(xcount);
258: }
259:
260: @Override
261: void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
262: e = eBase
263: + 2
264: * (adx * Math.abs(ny1 - y1) - ady
265: * Math.abs(nx1 - x1));
266: x = nx1;
267: y = ny1;
268: rasterize(ny2 - ny1);
269: }
270:
271: @Override
272: void rasterize(int count) {
273: int py = y;
274: while (count-- > 0) {
275: if (e >= 0) {
276: dst.addRect(x, py, x, y);
277: x += sx;
278: y += sy;
279: e += ePos;
280: py = y;
281: } else {
282: y += sy;
283: e += eNeg;
284: }
285: }
286: dst.addRect(x, py, x, y);
287: }
288:
289: @Override
290: void skip(int count) {
291: while (count-- > 0) {
292: y += sy;
293: if (e >= 0) {
294: x += sx;
295: e += ePos;
296: } else {
297: e += eNeg;
298: }
299: }
300: }
301:
302: }
303:
304: static class HorDashed extends Hor {
305:
306: LineDasher local;
307:
308: HorDashed(int x1, int y1, int x2, int y2,
309: MultiRectArea dst, LineDasher dasher,
310: boolean invert) {
311: super (x1, y1, x2, y2, dst);
312: float length = getLength();
313: local = dasher.createDiagonal(xcount / length,
314: length, invert);
315: }
316:
317: @Override
318: void rasterize() {
319: e = eBase;
320: x = x1;
321: y = y1;
322: rasterizeDash(xcount, local);
323: }
324:
325: @Override
326: void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
327: e = eBase
328: + 2
329: * (ady * Math.abs(nx1 - x1) - adx
330: * Math.abs(ny1 - y1));
331: x = nx1;
332: y = ny1;
333: rasterizeDash(Math.abs(nx2 - nx1), local
334: .createChild(Math.abs(nx1 - x1)));
335: }
336:
337: }
338:
339: static class VerDashed extends Ver {
340:
341: LineDasher local;
342:
343: VerDashed(int x1, int y1, int x2, int y2,
344: MultiRectArea dst, LineDasher dasher,
345: boolean invert) {
346: super (x1, y1, x2, y2, dst);
347: float length = getLength();
348: local = dasher.createDiagonal(xcount / length,
349: length, invert);
350: }
351:
352: @Override
353: void rasterize() {
354: e = eBase;
355: x = x1;
356: y = y1;
357: rasterizeDash(xcount, local);
358: }
359:
360: @Override
361: void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) {
362: e = eBase
363: + 2
364: * (adx * Math.abs(ny1 - y1) - ady
365: * Math.abs(nx1 - x1));
366: x = nx1;
367: y = ny1;
368: rasterizeDash(ny2 - ny1, local
369: .createChild(ny1 - y1));
370: }
371:
372: }
373:
374: @Override
375: void rasterize(int[] clip, int index) {
376: int cx1 = clip[index + 0];
377: int cy1 = clip[index + 1];
378: int cx2 = clip[index + 2] + 1;
379: int cy2 = clip[index + 3] + 1;
380:
381: int code1 = (x1 < cx1 ? 1 : 0) | (x1 >= cx2 ? 2 : 0)
382: | (y1 < cy1 ? 8 : 0) | (y1 >= cy2 ? 4 : 0);
383: int code2 = (x2 < cx1 ? 1 : 0) | (x2 >= cx2 ? 2 : 0)
384: | (y2 < cy1 ? 8 : 0) | (y2 >= cy2 ? 4 : 0);
385:
386: // Outside
387: if ((code1 & code2) != 0) {
388: return;
389: }
390:
391: // Inside
392: if (code1 == 0 && code2 == 0) {
393: rasterize();
394: return;
395: }
396:
397: // Clip
398: int nx1 = x1;
399: int ny1 = y1;
400: int nx2 = x2;
401: int ny2 = y2;
402: // need to clip
403: cx1 -= x1;
404: cx2 -= x1;
405: cy1 -= y1;
406: cy2 -= y1;
407: // int d;
408: int newx1 = 0, newy1 = 0, newx2 = 0, newy2 = 0;
409: if (code1 != 0) {
410: newx1 = Integer.MAX_VALUE;
411: if ((code1 & 8) != 0) {
412: // clip point 1 with top clip bound
413: newy1 = cy1;
414: newx1 = clipY(dx, dy, newy1, true);
415:
416: } else if ((code1 & 4) != 0) {
417: // clip point 1 with bottom clip bound
418: newy1 = cy2 - 1;
419: newx1 = clipY(dx, dy, newy1, false);
420: }
421: if ((code1 & 1) != 0
422: && (cx1 > newx1 || newx1 == Integer.MAX_VALUE)) {
423: // clip point 1 with left clip bound
424: newx1 = cx1;
425: newy1 = clipX(dx, dy, newx1, false);
426: } else if ((code1 & 2) != 0
427: && (newx1 >= cx2 || newx1 == Integer.MAX_VALUE)) {
428: // clip point 1 with right clip bound
429: newx1 = cx2 - 1;
430: newy1 = clipX(dx, dy, newx1, false);
431: }
432: if (newx1 < cx1 || newx1 >= cx2 || newy1 < cy1
433: || newy1 >= cy2) {
434: return;
435: }
436: // d = 2 * (ady * Math.abs(newx1) - adx * Math.abs(newy1)) + 2 * ady - adx;
437: } else {
438: // d = (ady << 1) - adx;
439: }
440:
441: if (code2 != 0) {
442: newx2 = Integer.MAX_VALUE;
443: if ((code2 & 8) != 0) {
444: // clip point 2 with top clip bound
445: newy2 = cy1;
446: newx2 = clipY(dx, dy, newy2, true);
447: } else if ((code2 & 4) != 0) {
448: // clip point 2 with bottom clip bound
449: newy2 = cy2 - 1;
450: newx2 = clipY(dx, dy, newy2, false);
451: }
452: if ((code2 & 1) != 0
453: && (cx1 > newx2 || newx2 == Integer.MAX_VALUE)) {
454: // clip point 2 with left clip bound
455: newx2 = cx1;
456: newy2 = clipX(dx, dy, newx2, false);
457: } else if ((code2 & 2) != 0
458: && (newx2 >= cx2 || newx2 == Integer.MAX_VALUE)) {
459: // clip point 2 with right clip bound
460: newx2 = cx2 - 1;
461: newy2 = clipX(dx, dy, newx2, false);
462: }
463: if (newx2 < cx1 || newx2 >= cx2 || newy2 < cy1
464: || newy2 >= cy2) {
465: return;
466: }
467: nx2 = x1 + newx2;
468: ny2 = y1 + newy2;
469: }
470: nx1 = x1 + newx1;
471: ny1 = y1 + newy1;
472:
473: rasterizeClipped(nx1, ny1, nx2, ny2);
474: }
475:
476: abstract void rasterizeClipped(int nx1, int ny1, int nx2,
477: int ny2);
478:
479: }
480:
481: static abstract class Ortog extends Line {
482:
483: Ortog(int x1, int y1, int x2, int y2, MultiRectArea dst) {
484: super (x1, y1, x2, y2, dst);
485: }
486:
487: static class Hor extends Ortog {
488:
489: int dx;
490:
491: Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) {
492: super (x1, y1, x2, y2, dst);
493: dx = x2 - x1;
494: }
495:
496: @Override
497: void rasterize() {
498: if (dx > 0) {
499: dst.addRect(x1, y1, x2, y2);
500: } else {
501: dst.addRect(x2, y2, x1, y1);
502: }
503: }
504:
505: @Override
506: void rasterize(int step) {
507: int px = x;
508: if (dx > 0) {
509: x += step;
510: dst.addRect(px, y1, x - 1, y2);
511: } else {
512: x -= step;
513: dst.addRect(x + 1, y2, px, y1);
514: }
515: }
516:
517: @Override
518: void skip(int step) {
519: if (dx > 0) {
520: x += step;
521: } else {
522: x -= step;
523: }
524: }
525:
526: void rasterizeClipped(int nx1, int nx2) {
527: if (nx1 < nx2) {
528: dst.addRect(nx1, y1, nx2, y1);
529: } else {
530: dst.addRect(nx2, y1, nx1, y1);
531: }
532: }
533:
534: @Override
535: void rasterize(int[] clip, int index) {
536: if (y1 >= clip[index + 1] && y1 <= clip[index + 3]) {
537: int cx1 = clip[index + 0];
538: int cx2 = clip[index + 2];
539: if (x1 <= cx2 && x2 >= cx1) {
540: int nx1, nx2;
541: if (dx > 0) {
542: nx1 = Math.max(x1, cx1);
543: nx2 = Math.min(x2, cx2);
544: } else {
545: nx2 = Math.max(x2, cx1);
546: nx1 = Math.min(x1, cx2);
547: }
548: rasterizeClipped(nx1, nx2);
549: }
550: }
551: }
552:
553: }
554:
555: static class Ver extends Ortog {
556:
557: int dy;
558:
559: Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) {
560: super (x1, y1, x2, y2, dst);
561: dy = y2 - y1;
562: }
563:
564: @Override
565: void rasterize() {
566: dst.addRect(x1, y1, x2, y2);
567: }
568:
569: @Override
570: void rasterize(int step) {
571: int py = y;
572: y += step;
573: dst.addRect(x1, py, x2, y - 1);
574: }
575:
576: @Override
577: void skip(int step) {
578: y += step;
579: }
580:
581: void rasterizeClipped(int ny1, int ny2) {
582: dst.addRect(x1, ny1, x1, ny2);
583: }
584:
585: @Override
586: void rasterize(int[] clip, int index) {
587: if (x1 >= clip[index] && x1 <= clip[index + 2]) {
588: int cy1 = clip[index + 1];
589: int cy2 = clip[index + 3];
590: if (y1 <= cy2 && y2 >= cy1) {
591: rasterizeClipped(Math.max(y1, cy1), Math
592: .min(y2, cy2));
593: }
594: }
595: }
596:
597: }
598:
599: static class HorDashed extends Hor {
600:
601: LineDasher local;
602:
603: HorDashed(int x1, int y1, int x2, int y2,
604: MultiRectArea dst, LineDasher dasher) {
605: super (x1, y1, x2, y2, dst);
606: dx = x2 - x1;
607: local = dasher.createOrtogonal(Math.abs(dx), false);
608: }
609:
610: @Override
611: void rasterize() {
612: x = x1;
613: y = y1;
614: rasterizeDash(Math.abs(dx), local);
615: }
616:
617: @Override
618: void rasterizeClipped(int nx1, int nx2) {
619: x = nx1;
620: y = y1;
621: rasterizeDash(Math.abs(nx2 - nx1), local
622: .createChild(Math.abs(nx1 - x1)));
623: }
624:
625: }
626:
627: static class VerDashed extends Ver {
628:
629: LineDasher local;
630:
631: VerDashed(int x1, int y1, int x2, int y2,
632: MultiRectArea dst, LineDasher dasher,
633: boolean invert) {
634: super (x1, y1, x2, y2, dst);
635: dy = y2 - y1;
636: local = dasher.createOrtogonal(dy, invert);
637: }
638:
639: @Override
640: void rasterize() {
641: x = x1;
642: y = y1;
643: rasterizeDash(dy, local);
644: }
645:
646: @Override
647: void rasterizeClipped(int ny1, int ny2) {
648: x = x1;
649: y = ny1;
650: rasterizeDash(ny2 - ny1, local.createChild(ny1));
651: }
652:
653: }
654:
655: }
656:
657: abstract void rasterize();
658:
659: abstract void rasterize(int[] clip, int index);
660:
661: abstract void rasterize(int count);
662:
663: abstract void skip(int count);
664:
665: void rasterizeDash(int count, LineDasher dasher) {
666: float delta = dasher.dash[dasher.index] - dasher.phase;
667: int step = (int) delta;
668: delta -= step;
669: while (count > step) {
670: if (dasher.visible) {
671: rasterize(step);
672: } else {
673: skip(step);
674: }
675: count -= step;
676: delta += dasher.nextDash();
677: step = (int) delta;
678: delta -= step;
679: }
680: if (count > 0 && dasher.visible) {
681: rasterize(count);
682: dasher.move(count);
683: }
684: }
685:
686: }
687:
688: /**
689: * Common clipping method
690: */
691: static int clip(int dX1, int dX2, int cX, boolean top) {
692: int adX1 = dX1 < 0 ? -dX1 : dX1;
693: int adX2 = dX2 < 0 ? -dX2 : dX2;
694: if (adX1 <= adX2) {
695: // obtuse intersection angle
696: return ((dX1 << 1) * cX + (dX1 > 0 ? dX2 : -dX2))
697: / (dX2 << 1);
698: }
699: int k;
700: if (top) {
701: k = -dX1
702: + (dX2 < 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
703: } else {
704: k = dX1
705: + (dX2 > 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1));
706: }
707:
708: k += dX1 > 0 == dX2 > 0 ? -1 : 1;
709: return ((dX1 << 1) * cX + k) / (dX2 << 1);
710: }
711:
712: /**
713: * Clipping along X axis
714: */
715: static int clipX(int dx, int dy, int cy, boolean top) {
716: return clip(dy, dx, cy, top);
717: }
718:
719: /**
720: * Clipping along Y axis
721: */
722: static int clipY(int dx, int dy, int cx, boolean top) {
723: return clip(dx, dy, cx, top);
724: }
725:
726: /**
727: * Rasterizes line using clippind and dashing style
728: * @param x1 - the x coordinate of the first control point
729: * @param y1 - the y coordinate of the first control point
730: * @param x2 - the x coordinate of the second control point
731: * @param y2 - the y coordinate of the second control point
732: * @param clip - the MultiRectArea object of clipping area
733: * @param dasher - the dasher style
734: * @param invert - the invert indicator, always false
735: * @return a MultiRectArea of rasterizer line
736: */
737: public static MultiRectArea rasterize(int x1, int y1, int x2,
738: int y2, MultiRectArea clip, LineDasher dasher,
739: boolean invert) {
740:
741: MultiRectArea dst = new MultiRectArea(false);
742: int dx = x2 - x1;
743: int dy = y2 - y1;
744:
745: // Point
746: if (dx == 0 && dy == 0) {
747: if ((clip == null || clip.contains(x1, y1))
748: && (dasher == null || dasher.visible)) {
749: dst = new MultiRectArea(x1, y1, x1, y1);
750: }
751: return dst;
752: }
753:
754: if (dy < 0) {
755: return rasterize(x2, y2, x1, y1, clip, dasher, true);
756: }
757:
758: Line line;
759: if (dasher == null) {
760: if (dx == 0) {
761: line = new Line.Ortog.Ver(x1, y1, x2, y2, dst);
762: } else if (dy == 0) {
763: line = new Line.Ortog.Hor(x1, y1, x2, y2, dst);
764: } else {
765: if (dy < Math.abs(dx)) {
766: line = new Line.Diag.Hor(x1, y1, x2, y2, dst);
767: } else {
768: line = new Line.Diag.Ver(x1, y1, x2, y2, dst);
769: }
770: }
771: } else {
772: if (dx == 0) {
773: line = new Line.Ortog.VerDashed(x1, y1, x2, y2, dst,
774: dasher, invert);
775: } else if (dy == 0) {
776: line = new Line.Ortog.HorDashed(x1, y1, x2, y2, dst,
777: dasher);
778: } else {
779: if (dy < Math.abs(dx)) {
780: line = new Line.Diag.HorDashed(x1, y1, x2, y2, dst,
781: dasher, invert);
782: } else {
783: line = new Line.Diag.VerDashed(x1, y1, x2, y2, dst,
784: dasher, invert);
785: }
786: }
787: }
788:
789: if (clip == null || clip.isEmpty()) {
790: line.rasterize();
791: } else {
792: for (int i = 1; i < clip.rect[0]; i += 4) {
793: line.rasterize(clip.rect, i);
794: }
795: }
796:
797: return dst;
798: }
799:
800: }
|