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 java.awt;
021:
022: import java.awt.geom.AffineTransform;
023: import java.awt.geom.Point2D;
024: import java.awt.geom.Rectangle2D;
025: import java.awt.image.BufferedImage;
026: import java.awt.image.ColorModel;
027: import java.awt.image.DataBuffer;
028: import java.awt.image.Raster;
029: import java.awt.image.WritableRaster;
030:
031: import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor;
032:
033: class TexturePaintContext implements PaintContext {
034:
035: /**
036: * The ColorModel object of destination raster
037: */
038: ColorModel cm;
039:
040: /**
041: * The BufferedImage object used as texture
042: */
043: BufferedImage img;
044:
045: /**
046: * The Rectangle2D bounds of texture piece to be painted
047: */
048: Rectangle2D anchor;
049:
050: /**
051: * The paint transformation
052: */
053: AffineTransform t;
054:
055: /**
056: * The AwtImageBackdoorAccessor object to communicate with image DataBuffer
057: */
058: AwtImageBackdoorAccessor access;
059:
060: /**
061: * The source DataBuffer object of texture image
062: */
063: DataBuffer srcBuf;
064:
065: /**
066: * The destination DataBuffer object of output rester
067: */
068: DataBuffer dstBuf;
069:
070: /**
071: * The source WritableRaster object of texture image
072: */
073: WritableRaster srcRaster;
074:
075: /**
076: * The destination WritableRaster object of texture image
077: */
078: WritableRaster dstRaster;
079:
080: /**
081: * The width of the texture image
082: */
083: int srcWidth;
084:
085: /**
086: * The height of the texture image
087: */
088: int srcHeight;
089:
090: /**
091: * The temporary pre-calculated temporary values
092: */
093: int sx, sy, hx, hy, vx, vy;
094: int m00, m01, m10, m11;
095: int imgW, imgH;
096: int px, py;
097:
098: /**
099: * The integer array of weight components for bilinear interpolation
100: */
101: int[] weight = new int[4];
102:
103: /**
104: * The temporary values
105: */
106: int[] value = new int[4];
107:
108: static class IntSimple extends TexturePaintContext {
109:
110: /**
111: * Constructs a new IntSimple.TexturePaintContext works with DataBufferInt rasters.
112: * This is simple paint context uses NEAREST NEIGHBOUR interpolation.
113: * @param img - the BufferedImage object used as texture
114: * @param anchor - the Rectangle2D bounds of texture piece to be painted
115: * @param t - the AffineTransform applied to texture painting
116: */
117: public IntSimple(BufferedImage img, Rectangle2D anchor,
118: AffineTransform t) {
119: super (img, anchor, t);
120: }
121:
122: @Override
123: public Raster getRaster(int dstX, int dstY, int dstWidth,
124: int dstHeight) {
125: prepare(dstX, dstY, dstWidth, dstHeight);
126: int[] src = access.getDataInt(srcBuf);
127: int[] dst = access.getDataInt(dstBuf);
128: int k = 0;
129: for (int j = 0; j < dstHeight; j++) {
130: for (int i = 0; i < dstWidth; i++) {
131: dst[k++] = src[(sx >> 8) + (sy >> 8) * srcWidth];
132: sx = check(sx + hx, imgW);
133: sy = check(sy + hy, imgH);
134: }
135: sx = check(sx + vx, imgW);
136: sy = check(sy + vy, imgH);
137: }
138: return dstRaster;
139: }
140:
141: }
142:
143: static class ByteSimple extends TexturePaintContext {
144:
145: /**
146: * Constructs a new ByteSimple.TexturePaintContext works with DataBufferByte rasters.
147: * This is simple paint context uses NEAREST NEIGHBOUR interpolation.
148: * @param img - the BufferedImage object used as texture
149: * @param anchor - the Rectangle2D bounds of texture piece to be painted
150: * @param t - the AffineTransform applied to texture painting
151: */
152: public ByteSimple(BufferedImage img, Rectangle2D anchor,
153: AffineTransform t) {
154: super (img, anchor, t);
155: }
156:
157: @Override
158: public Raster getRaster(int dstX, int dstY, int dstWidth,
159: int dstHeight) {
160: prepare(dstX, dstY, dstWidth, dstHeight);
161: byte[] src = access.getDataByte(srcBuf);
162: byte[] dst = access.getDataByte(dstBuf);
163: int k = 0;
164: for (int j = 0; j < dstHeight; j++) {
165: for (int i = 0; i < dstWidth; i++) {
166: dst[k++] = src[(sx >> 8) + (sy >> 8) * srcWidth];
167: sx = check(sx + hx, imgW);
168: sy = check(sy + hy, imgH);
169: }
170: sx = check(sx + vx, imgW);
171: sy = check(sy + vy, imgH);
172: }
173: return dstRaster;
174: }
175:
176: }
177:
178: static class ShortSimple extends TexturePaintContext {
179:
180: /**
181: * Constructs a new ShortSimple.TexturePaintContext works with DataBufferShort rasters.
182: * This is simple paint context uses NEAREST NEIGHBOUR interpolation.
183: * @param img - the BufferedImage object used as texture
184: * @param anchor - the Rectangle2D bounds of texture piece to be painted
185: * @param t - the AffineTransform applied to texture painting
186: */
187: public ShortSimple(BufferedImage img, Rectangle2D anchor,
188: AffineTransform t) {
189: super (img, anchor, t);
190: }
191:
192: @Override
193: public Raster getRaster(int dstX, int dstY, int dstWidth,
194: int dstHeight) {
195: prepare(dstX, dstY, dstWidth, dstHeight);
196: short[] src = access.getDataUShort(srcBuf);
197: short[] dst = access.getDataUShort(dstBuf);
198: int k = 0;
199: for (int j = 0; j < dstHeight; j++) {
200: for (int i = 0; i < dstWidth; i++) {
201: dst[k++] = src[(sx >> 8) + (sy >> 8) * srcWidth];
202: sx = check(sx + hx, imgW);
203: sy = check(sy + hy, imgH);
204: }
205: sx = check(sx + vx, imgW);
206: sy = check(sy + vy, imgH);
207: }
208: return dstRaster;
209: }
210: }
211:
212: static class CommonSimple extends TexturePaintContext {
213:
214: /**
215: * Constructs a new CommonSimple.TexturePaintContext works with any raster type.
216: * This is simple paint context uses NEAREST NEIGHBOUR interpolation.
217: * @param img - the BufferedImage object used as texture
218: * @param anchor - the Rectangle2D bounds of texture piece to be painted
219: * @param t - the AffineTransform applied to texture painting
220: */
221: public CommonSimple(BufferedImage img, Rectangle2D anchor,
222: AffineTransform t) {
223: super (img, anchor, t);
224: }
225:
226: @Override
227: public Raster getRaster(int dstX, int dstY, int dstWidth,
228: int dstHeight) {
229: prepare(dstX, dstY, dstWidth, dstHeight);
230: for (int j = 0; j < dstHeight; j++) {
231: for (int i = 0; i < dstWidth; i++) {
232: dstRaster.setDataElements(dstX + i, dstY + j,
233: srcRaster.getDataElements(sx >> 8, sy >> 8,
234: null));
235: sx = check(sx + hx, imgW);
236: sy = check(sy + hy, imgH);
237: }
238: sx = check(sx + vx, imgW);
239: sy = check(sy + vy, imgH);
240: }
241: return dstRaster;
242: }
243:
244: }
245:
246: static class IntBilinear extends TexturePaintContext {
247:
248: /**
249: * Constructs a new IntSimple.TexturePaintContext works with DataBufferInt rasters.
250: * This paint context uses BILINEAR interpolation.
251: * @param img - the BufferedImage object used as texture
252: * @param anchor - the Rectangle2D bounds of texture piece to be painted
253: * @param t - the AffineTransform applied to texture painting
254: */
255: public IntBilinear(BufferedImage img, Rectangle2D anchor,
256: AffineTransform t) {
257: super (img, anchor, t);
258: }
259:
260: @Override
261: public Raster getRaster(int dstX, int dstY, int dstWidth,
262: int dstHeight) {
263: prepare(dstX, dstY, dstWidth, dstHeight);
264: int[] src = access.getDataInt(srcBuf);
265: int[] dst = access.getDataInt(dstBuf);
266: int k = 0;
267: for (int j = 0; j < dstHeight; j++) {
268: for (int i = 0; i < dstWidth; i++) {
269: int wx1 = sx & 0xFF;
270: int wy1 = sy & 0xFF;
271: int wx0 = 0xFF - wx1;
272: int wy0 = 0xFF - wy1;
273:
274: weight[0] = wx0 * wy0;
275: weight[1] = wx1 * wy0;
276: weight[2] = wx0 * wy1;
277: weight[3] = wx1 * wy1;
278:
279: int x0 = sx >> 8;
280: int y0 = sy >> 8;
281: int x1 = check(x0 + 1, srcWidth);
282: int y1 = check(y0 + 1, srcHeight);
283:
284: y0 *= srcWidth;
285: y1 *= srcWidth;
286:
287: value[0] = src[x0 + y0];
288: value[1] = src[x1 + y0];
289: value[2] = src[x0 + y1];
290: value[3] = src[x1 + y1];
291:
292: int color = 0;
293: for (int n = 0; n < 32; n += 8) {
294: int comp = 0;
295: for (int m = 0; m < 4; m++) {
296: comp += ((value[m] >> n) & 0xFF)
297: * weight[m];
298: }
299: color |= (comp >> 16) << n;
300: }
301:
302: dst[k++] = color;
303:
304: sx = check(sx + hx, imgW);
305: sy = check(sy + hy, imgH);
306: }
307: sx = check(sx + vx, imgW);
308: sy = check(sy + vy, imgH);
309: }
310: return dstRaster;
311: }
312:
313: }
314:
315: static class ByteBilinear extends TexturePaintContext {
316:
317: /**
318: * Constructs a new ByteSimple.TexturePaintContext works with DataBufferByte rasters.
319: * This paint context uses BILINEAR interpolation.
320: * @param img - the BufferedImage object used as texture
321: * @param anchor - the Rectangle2D bounds of texture piece to be painted
322: * @param t - the AffineTransform applied to texture painting
323: */
324: public ByteBilinear(BufferedImage img, Rectangle2D anchor,
325: AffineTransform t) {
326: super (img, anchor, t);
327: }
328:
329: @Override
330: public Raster getRaster(int dstX, int dstY, int dstWidth,
331: int dstHeight) {
332: prepare(dstX, dstY, dstWidth, dstHeight);
333: byte[] src = access.getDataByte(srcBuf);
334: byte[] dst = access.getDataByte(dstBuf);
335: int k = 0;
336: for (int j = 0; j < dstHeight; j++) {
337: for (int i = 0; i < dstWidth; i++) {
338: int wx1 = sx & 0xFF;
339: int wy1 = sy & 0xFF;
340: int wx0 = 0xFF - wx1;
341: int wy0 = 0xFF - wy1;
342:
343: weight[0] = wx0 * wy0;
344: weight[1] = wx1 * wy0;
345: weight[2] = wx0 * wy1;
346: weight[3] = wx1 * wy1;
347:
348: int x0 = sx >> 8;
349: int y0 = sy >> 8;
350: int x1 = check(x0 + 1, srcWidth);
351: int y1 = check(y0 + 1, srcHeight);
352:
353: y0 *= dstWidth;
354: y1 *= dstWidth;
355:
356: value[0] = src[x0 + y0];
357: value[1] = src[x1 + y0];
358: value[2] = src[x0 + y1];
359: value[3] = src[x1 + y1];
360:
361: int comp = 0;
362: for (int m = 0; m < 4; m++) {
363: comp += value[m] * weight[m];
364: }
365: dst[k++] = (byte) (comp >> 16);
366:
367: sx = check(sx + hx, imgW);
368: sy = check(sy + hy, imgH);
369: }
370: sx = check(sx + vx, imgW);
371: sy = check(sy + vy, imgH);
372: }
373: return dstRaster;
374: }
375:
376: }
377:
378: static class ShortBilinear extends TexturePaintContext {
379:
380: /**
381: * Constructs a new ShortSimple.TexturePaintContext works with DataBufferShort rasters.
382: * This paint context uses BILINEAR interpolation.
383: * @param img - the BufferedImage object used as texture
384: * @param anchor - the Rectangle2D bounds of texture piece to be painted
385: * @param t - the AffineTransform applied to texture painting
386: */
387: public ShortBilinear(BufferedImage img, Rectangle2D anchor,
388: AffineTransform t) {
389: super (img, anchor, t);
390: }
391:
392: @Override
393: public Raster getRaster(int dstX, int dstY, int dstWidth,
394: int dstHeight) {
395: prepare(dstX, dstY, dstWidth, dstHeight);
396: short[] src = access.getDataUShort(srcBuf);
397: short[] dst = access.getDataUShort(dstBuf);
398: int k = 0;
399: for (int j = 0; j < dstHeight; j++) {
400: for (int i = 0; i < dstWidth; i++) {
401: int wx1 = sx & 0xFF;
402: int wy1 = sy & 0xFF;
403: int wx0 = 0xFF - wx1;
404: int wy0 = 0xFF - wy1;
405:
406: weight[0] = wx0 * wy0;
407: weight[1] = wx1 * wy0;
408: weight[2] = wx0 * wy1;
409: weight[3] = wx1 * wy1;
410:
411: int x0 = sx >> 8;
412: int y0 = sy >> 8;
413: int x1 = check(x0 + 1, srcWidth);
414: int y1 = check(y0 + 1, srcHeight);
415:
416: y0 *= dstWidth;
417: y1 *= dstWidth;
418:
419: value[0] = src[x0 + y0];
420: value[1] = src[x1 + y0];
421: value[2] = src[x0 + y1];
422: value[3] = src[x1 + y1];
423:
424: short color = 0;
425: for (int n = 0; n < 16; n += 8) {
426: int comp = 0;
427: for (int m = 0; m < 4; m++) {
428: comp += ((value[m] >> n) & 0xFF)
429: * weight[m];
430: }
431: color |= (comp >> 16) << n;
432: }
433: dst[k++] = color;
434:
435: sx = check(sx + hx, imgW);
436: sy = check(sy + hy, imgH);
437: }
438: sx = check(sx + vx, imgW);
439: sy = check(sy + vy, imgH);
440: }
441: return dstRaster;
442: }
443:
444: }
445:
446: static class CommonBilinear extends TexturePaintContext {
447:
448: /**
449: * Constructs a new CommonSimple.TexturePaintContext works with any raster type.
450: * This paint context uses BILINEAR interpolation.
451: * @param img - the BufferedImage object used as texture
452: * @param anchor - the Rectangle2D bounds of texture piece to be painted
453: * @param t - the AffineTransform applied to texture painting
454: */
455: public CommonBilinear(BufferedImage img, Rectangle2D anchor,
456: AffineTransform t) {
457: super (img, anchor, t);
458: }
459:
460: @Override
461: public Raster getRaster(int dstX, int dstY, int dstWidth,
462: int dstHeight) {
463: prepare(dstX, dstY, dstWidth, dstHeight);
464: for (int j = 0; j < dstHeight; j++) {
465: for (int i = 0; i < dstWidth; i++) {
466: int wx1 = sx & 0xFF;
467: int wy1 = sy & 0xFF;
468: int wx0 = 0xFF - wx1;
469: int wy0 = 0xFF - wy1;
470:
471: weight[0] = wx0 * wy0;
472: weight[1] = wx1 * wy0;
473: weight[2] = wx0 * wy1;
474: weight[3] = wx1 * wy1;
475:
476: int x0 = sx >> 8;
477: int y0 = sy >> 8;
478: int x1 = check(x0 + 1, srcWidth);
479: int y1 = check(y0 + 1, srcHeight);
480:
481: value[0] = cm.getRGB(srcRaster.getDataElements(x0,
482: y0, null));
483: value[1] = cm.getRGB(srcRaster.getDataElements(x1,
484: y0, null));
485: value[2] = cm.getRGB(srcRaster.getDataElements(x0,
486: y1, null));
487: value[3] = cm.getRGB(srcRaster.getDataElements(x1,
488: y1, null));
489:
490: int color = 0;
491: for (int n = 0; n < 32; n += 8) {
492: int comp = 0;
493: for (int m = 0; m < 4; m++) {
494: comp += ((value[m] >> n) & 0xFF)
495: * weight[m];
496: }
497: color |= (comp >> 16) << n;
498: }
499: dstRaster.setDataElements(dstX + i, dstY + j, cm
500: .getDataElements(color, null));
501:
502: sx = check(sx + hx, imgW);
503: sy = check(sy + hy, imgH);
504: }
505: sx = check(sx + vx, imgW);
506: sy = check(sy + vy, imgH);
507: }
508: return dstRaster;
509: }
510:
511: }
512:
513: public TexturePaintContext(BufferedImage img, Rectangle2D anchor,
514: AffineTransform t) {
515: this .cm = img.getColorModel();
516: this .img = img;
517: this .anchor = anchor;
518: this .t = t;
519:
520: srcWidth = img.getWidth();
521: srcHeight = img.getHeight();
522: imgW = srcWidth << 8;
523: imgH = srcHeight << 8;
524: double det = t.getDeterminant();
525: double multW = imgW / (anchor.getWidth() * det);
526: double multH = -imgH / (anchor.getHeight() * det);
527:
528: m11 = (int) (t.getScaleY() * multW);
529: m01 = (int) (t.getShearX() * multW);
530: m00 = (int) (t.getScaleX() * multH);
531: m10 = (int) (t.getShearY() * multH);
532: Point2D p = t.transform(new Point2D.Double(anchor.getX(),
533: anchor.getY()), null);
534: px = (int) p.getX();
535: py = (int) p.getY();
536:
537: hx = check2(m11, imgW);
538: hy = check2(m10, imgH);
539:
540: srcRaster = img.getRaster();
541: srcBuf = srcRaster.getDataBuffer();
542: access = AwtImageBackdoorAccessor.getInstance();
543: }
544:
545: /**
546: * Prepares pre-calculated values
547: */
548: void prepare(int dstX, int dstY, int dstWidth, int dstHeight) {
549: vx = check2(-m01 - m11 * dstWidth, imgW);
550: vy = check2(-m00 - m10 * dstWidth, imgH);
551: int dx = dstX - px;
552: int dy = dstY - py;
553: sx = check2(dx * m11 - dy * m01, imgW);
554: sy = check2(dx * m10 - dy * m00, imgH);
555: dstRaster = cm.createCompatibleWritableRaster(dstWidth,
556: dstHeight);
557: dstBuf = dstRaster.getDataBuffer();
558: }
559:
560: public void dispose() {
561: }
562:
563: public ColorModel getColorModel() {
564: return cm;
565: }
566:
567: /**
568: * Checks point overrun of texture anchor
569: */
570: int check(int value, int max) {
571: if (value >= max) {
572: return value - max;
573: }
574: return value;
575: }
576:
577: /**
578: * Checks point overrun of texture anchor
579: */
580: int check2(int value, int max) {
581: value = value % max;
582: return value < 0 ? max + value : value;
583: }
584:
585: public Raster getRaster(int dstX, int dstY, int dstWidth,
586: int dstHeight) {
587: return dstRaster;
588: }
589:
590: }
|