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 Oleg V. Khaschansky
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.opengl;
021:
022: import org.apache.harmony.awt.gl.render.Blitter;
023: import org.apache.harmony.awt.gl.*;
024: import org.apache.harmony.awt.nativebridge.NativeBridge;
025: import org.apache.harmony.awt.nativebridge.Int32Pointer;
026: import org.apache.harmony.misc.accessors.LockedArray;
027:
028: import java.awt.geom.AffineTransform;
029: import java.awt.*;
030: import java.awt.image.ColorModel;
031: import java.awt.image.BufferedImage;
032:
033: public class OGLBlitter implements Blitter {
034: private static final GL gl = GL.getInstance();
035:
036: private static final OGLBlitter inst = new OGLBlitter();
037:
038: private static final class OGLImageParams {
039: OGLImageParams(int format, int intFormat, int type,
040: int alignment, boolean requiresConversion) {
041: oglFormat = format;
042: oglIntFormat = intFormat;
043: oglType = type;
044: oglAlignment = alignment;
045: this .requiresConversion = requiresConversion;
046: }
047:
048: int oglFormat;
049: int oglIntFormat;
050: int oglType;
051: int oglAlignment;
052: boolean requiresConversion;
053: }
054:
055: static final class OGLTextureParams {
056: OGLTextureParams(int tName, int p2w, int p2h, int w, int h) {
057: textureName = tName;
058: this .p2w = p2w;
059: this .p2h = p2h;
060: width = w;
061: height = h;
062: }
063:
064: int textureName;
065:
066: // Actual texture width and height
067: int p2w;
068: int p2h;
069:
070: // Size of the used part of the texture
071: int width;
072: int height;
073:
074: final void deleteTexture() {
075: deleteTexture(textureName);
076: textureName = 0;
077: }
078:
079: static final void deleteTexture(int textureName) {
080: if (textureName != 0) {
081: Int32Pointer texPtr = NativeBridge.getInstance()
082: .createInt32Pointer(1, true);
083: texPtr.set(0, textureName);
084: gl.glDeleteTextures(1, texPtr);
085: texPtr.free();
086: }
087: }
088: };
089:
090: private static final OGLImageParams IMAGE_TYPE_MAPPING[] = new OGLImageParams[] {
091: new OGLImageParams(GLDefs.GL_BGRA, 4,
092: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, true), // TYPE_CUSTOM = 0
093: new OGLImageParams(GLDefs.GL_BGR, 3,
094: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_RGB = 1
095: new OGLImageParams(GLDefs.GL_BGRA, 4,
096: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_ARGB = 2
097: new OGLImageParams(GLDefs.GL_BGRA, 4,
098: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_ARGB_PRE = 3
099: new OGLImageParams(GLDefs.GL_RGB, 3,
100: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_BGR = 4
101: new OGLImageParams(GLDefs.GL_BGR, 3,
102: GLDefs.GL_UNSIGNED_BYTE, 1, false), // TYPE_3BYTE_BGR = 5
103: new OGLImageParams(GLDefs.GL_RGBA, 4,
104: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_4BYTE_ABGR = 6
105: new OGLImageParams(GLDefs.GL_RGBA, 4,
106: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_4BYTE_ABGR_PRE = 7
107: new OGLImageParams(GLDefs.GL_RGB, 3,
108: GLDefs.GL_UNSIGNED_SHORT_5_6_5, 2, false), // TYPE_USHORT_565_RGB = 8
109: new OGLImageParams(GLDefs.GL_BGR, 3,
110: GLDefs.GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, false), // TYPE_USHORT_555_RGB = 9
111: new OGLImageParams(GLDefs.GL_LUMINANCE, 1,
112: GLDefs.GL_UNSIGNED_BYTE, 1, false), // TYPE_BYTE_GRAY = 10
113: new OGLImageParams(GLDefs.GL_LUMINANCE, 1,
114: GLDefs.GL_UNSIGNED_SHORT, 2, false), // TYPE_USHORT_GRAY = 11
115: new OGLImageParams(GLDefs.GL_BGR, 3,
116: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, true), // TYPE_BYTE_BINARY = 12
117: new OGLImageParams(GLDefs.GL_BGRA, 4,
118: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, true) // TYPE_BYTE_INDEXED = 13
119: };
120:
121: public static OGLBlitter getInstance() {
122: return inst;
123: }
124:
125: public void blit(int srcX, int srcY, Surface srcSurf, int dstX,
126: int dstY, Surface dstSurf, int width, int height,
127: AffineTransform sysxform, AffineTransform xform,
128: Composite comp, Color bgcolor, MultiRectArea clip) {
129: int type = xform.getType();
130: switch (type) {
131: case AffineTransform.TYPE_TRANSLATION:
132: dstX += xform.getTranslateX();
133: dstY += xform.getTranslateY();
134: case AffineTransform.TYPE_IDENTITY:
135: blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width,
136: height, sysxform, comp, bgcolor, clip);
137: break;
138: default:
139: AffineTransform at = (AffineTransform) sysxform.clone();
140: at.concatenate(xform);
141: blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width,
142: height, at, comp, bgcolor, clip);
143: }
144: }
145:
146: public void blit(int srcX, int srcY, Surface srcSurf, int dstX,
147: int dstY, Surface dstSurf, int width, int height,
148: AffineTransform sysxform, Composite comp, Color bgcolor,
149: MultiRectArea clip) {
150: int type = sysxform.getType();
151: switch (type) {
152: case AffineTransform.TYPE_TRANSLATION:
153: dstX += sysxform.getTranslateX();
154: dstY += sysxform.getTranslateY();
155: case AffineTransform.TYPE_IDENTITY:
156: blitImpl(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width,
157: height, comp, bgcolor, clip, null);
158: break;
159: default:
160: blitImpl(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width,
161: height, comp, bgcolor, clip, sysxform);
162: }
163: }
164:
165: public void blit(int srcX, int srcY, Surface srcSurf, int dstX,
166: int dstY, Surface dstSurf, int width, int height,
167: Composite comp, Color bgcolor, MultiRectArea clip) {
168: blitImpl(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width,
169: height, comp, bgcolor, clip, null);
170: }
171:
172: private final void blitImpl(int srcX, int srcY, Surface srcSurf,
173: int dstX, int dstY, Surface dstSurf, int width, int height,
174: Composite comp, Color bgcolor, MultiRectArea clip,
175: AffineTransform xform) {
176: OGLSurface oglDstSurf = (OGLSurface) dstSurf;
177: OGLGraphics2D oglg = oglDstSurf.oglg;
178: oglg.makeCurrent();
179:
180: // Set the requested clip, saving current clip
181: MultiRectArea oldClip = (MultiRectArea) oglg.getClip();
182: boolean needRestoreClip = false;
183: if ((clip == null && oldClip != null) || !clip.equals(oldClip)) {
184: oglg.setTransformedClip(clip);
185: needRestoreClip = true;
186: } else {
187: oldClip = null;
188: }
189:
190: // Fill the background if needed
191: if (srcSurf.getColorModel().getTransparency() != Transparency.OPAQUE
192: && bgcolor != null) {
193: if (xform == null) {
194: oglg.fillRect(dstX, dstY, width, height);
195: } else {
196: Rectangle bounds = new Rectangle(srcX, srcY, width,
197: height);
198: Shape tBounds = xform.createTransformedShape(bounds);
199: AffineTransform dstT = AffineTransform
200: .getTranslateInstance(dstX, dstY);
201: tBounds = dstT.createTransformedShape(tBounds);
202: Color savedc = oglg.getColor();
203: oglg.setColor(bgcolor);
204: oglg.fill(tBounds);
205: oglg.setColor(savedc);
206: }
207: }
208:
209: if (srcX != 0 || srcY != 0) {
210: gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_PIXELS, srcX);
211: gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_ROWS, srcY);
212: }
213:
214: ColorModel srcCM = srcSurf.getColorModel();
215:
216: boolean needRestoreComposite = false;
217: boolean needPremultiply = false;
218: if (comp instanceof AlphaComposite) {
219: if (!oglg.getComposite().equals(comp)
220: || !srcCM.isAlphaPremultiplied()
221: || srcCM.hasAlpha() == oglg.opaqueColor) {
222: needPremultiply = OGLGraphics2D.enableAlphaComposite(
223: (AlphaComposite) comp, srcCM
224: .isAlphaPremultiplied(), srcCM
225: .hasAlpha());
226: needRestoreComposite = true;
227: }
228: } else {
229: // XXX - todo - custom composite
230: }
231:
232: boolean oglSrc = false; //srcSurf instanceof OGLSurface;
233:
234: if (xform == null && !oglSrc) {
235: // glCopyPixels works very slow on some NV GPU's.
236: /*
237: boolean copied = (srcSurf instanceof OGLSurface) &&
238: oglg.copyArea(
239: srcX, srcY,
240: width, height,
241: dstX, dstY,
242: ((OGLSurface) srcSurf).oglg
243: );
244:
245: if(!copied) {
246: */
247: blitImg2OGL(srcSurf, width, height, dstX, dstY,
248: needPremultiply);
249: //}
250: } else {
251: OGLTextureParams tp;
252: if (oglSrc) { // We have opengl source with or w/o transform
253: tp = blitOGL2OGLTexCached((OGLSurface) srcSurf,
254: oglDstSurf, srcX, srcY, dstX, dstY, width,
255: height);
256:
257: if (tp == null) { // Can't copy texture, use readPixels
258: oglSrc = false;
259: tp = blitImg2OGLTexCached(srcSurf, width, height,
260: needPremultiply);
261: }
262: } else { // Non opengl source
263: tp = blitImg2OGLTexCached(srcSurf, width, height,
264: needPremultiply);
265: }
266:
267: double xCoord = (double) width / tp.p2w;
268: double yCoord = (double) height / tp.p2h;
269:
270: double vertices[] = new double[8];
271: if (!oglSrc) {
272: vertices[0] = srcX;
273: vertices[1] = srcY;
274: vertices[2] = srcX + width;
275: vertices[3] = srcY;
276: vertices[4] = srcX + width;
277: vertices[5] = srcY + height;
278: vertices[6] = srcX;
279: vertices[7] = srcY + height;
280: } else {
281: vertices[6] = srcX;
282: vertices[7] = srcY;
283: vertices[4] = srcX + width;
284: vertices[5] = srcY;
285: vertices[2] = srcX + width;
286: vertices[3] = srcY + height;
287: vertices[0] = srcX;
288: vertices[1] = srcY + height;
289: }
290:
291: if (xform != null) {
292: xform.transform(vertices, 0, vertices, 0, 4);
293: }
294:
295: for (int i = 0; i < vertices.length; i++) {
296: vertices[i] += (i % 2 == 0) ? dstX : dstY;
297: }
298:
299: gl.glEnable(GLDefs.GL_TEXTURE_2D);
300: gl.glBegin(GLDefs.GL_QUADS);
301:
302: gl.glTexCoord2d(0.0, 0.0);
303: gl.glVertex2d(vertices[0], vertices[1]);
304: gl.glTexCoord2d(xCoord, 0.0);
305: gl.glVertex2d(vertices[2], vertices[3]);
306: gl.glTexCoord2d(xCoord, yCoord);
307: gl.glVertex2d(vertices[4], vertices[5]);
308: gl.glTexCoord2d(0.0, yCoord);
309: gl.glVertex2d(vertices[6], vertices[7]);
310:
311: gl.glEnd();
312: gl.glFlush();
313: gl.glDisable(GLDefs.GL_TEXTURE_2D);
314:
315: //tp.deleteTexture();
316: }
317:
318: if (needRestoreClip) {
319: oglg.setTransformedClip(oldClip);
320: }
321:
322: if (needRestoreComposite) {
323: oglg.checkComposite();
324: }
325: }
326:
327: private void blitImg2OGL(Surface srcSurf, int width, int height,
328: int dstX, int dstY, boolean needPremultiply) {
329: OGLImageParams imageParams = IMAGE_TYPE_MAPPING[srcSurf
330: .getSurfaceType()];
331: boolean requiresConversion = imageParams.requiresConversion;
332: if (requiresConversion || needPremultiply) {
333: imageParams = IMAGE_TYPE_MAPPING[BufferedImage.TYPE_INT_ARGB_PRE];
334: }
335:
336: gl.glPixelStorei(GLDefs.GL_UNPACK_ALIGNMENT,
337: imageParams.oglAlignment);
338:
339: ColorModel srcCM = srcSurf.getColorModel();
340:
341: // Obtain image data in opengl-compatible format and draw the image
342: if (requiresConversion || needPremultiply) {
343: // Set the raster position to the destination point
344: gl.glRasterPos2i(0, 0);
345: gl.glBitmap(0, 0, 0, 0, dstX, -dstY, 0);
346:
347: gl.glPixelZoom(1, -1);
348:
349: // needPremultiply should be always false for OGLSurface, type cast is safe
350: gl.glDrawPixels(width, height, imageParams.oglFormat,
351: imageParams.oglType, ((ImageSurface) srcSurf)
352: .getCachedData(srcCM.isAlphaPremultiplied()
353: || needPremultiply));
354: } else {
355: Object data;
356: if (srcSurf instanceof OGLSurface) {
357: data = ((OGLSurface) srcSurf).getBottomToTopData();
358:
359: // Set the raster position to the destination point
360: gl.glRasterPos2i(0, 0);
361: gl.glBitmap(0, 0, 0, 0, dstX, -dstY - height, 0);
362:
363: gl.glPixelZoom(1, 1);
364: } else {
365: data = srcSurf.getData();
366:
367: // Set the raster position to the destination point
368: gl.glRasterPos2i(0, 0);
369: gl.glBitmap(0, 0, 0, 0, dstX, -dstY, 0);
370:
371: gl.glPixelZoom(1, -1);
372: }
373:
374: LockedArray ldata = Utils.arraccess.lockArrayShort(data);
375: gl.glDrawPixels(width, height, imageParams.oglFormat,
376: imageParams.oglType, ldata.getAddress());
377: ldata.release();
378: }
379: }
380:
381: /**
382: * Calculates the next power of 2 from the size
383: * @param size - arbitrary positive integer
384: * @return next to the size power of 2
385: */
386: private final static int p2(int size) {
387: size--;
388: size |= size >> 1;
389: size |= size >> 2;
390: size |= size >> 4;
391: size |= size >> 8;
392: size |= size >> 16;
393: return ++size;
394: }
395:
396: private final OGLTextureParams blitImg2OGLTex(Surface srcSurf,
397: int width, int height, boolean needPremultiply,
398: OGLTextureParams tp) {
399: OGLImageParams imageParams = IMAGE_TYPE_MAPPING[srcSurf
400: .getSurfaceType()];
401: boolean requiresConversion = imageParams.requiresConversion;
402: if (requiresConversion || needPremultiply) {
403: imageParams = IMAGE_TYPE_MAPPING[BufferedImage.TYPE_INT_ARGB_PRE];
404: }
405:
406: gl.glPixelStorei(GLDefs.GL_UNPACK_ALIGNMENT,
407: imageParams.oglAlignment);
408:
409: ColorModel srcCM = srcSurf.getColorModel();
410:
411: int p2w = p2(width);
412: int p2h = p2(height);
413:
414: if (tp == null) {
415: Int32Pointer texPtr = NativeBridge.getInstance()
416: .createInt32Pointer(1, true);
417:
418: gl.glGenTextures(1, texPtr);
419: int texName = texPtr.get(0);
420: gl.glBindTexture(GLDefs.GL_TEXTURE_2D, texName);
421: texPtr.free();
422:
423: gl.glTexParameteri(GLDefs.GL_TEXTURE_2D,
424: GLDefs.GL_TEXTURE_MAG_FILTER, GLDefs.GL_NEAREST);
425: gl.glTexParameteri(GLDefs.GL_TEXTURE_2D,
426: GLDefs.GL_TEXTURE_MIN_FILTER, GLDefs.GL_NEAREST);
427:
428: tp = new OGLTextureParams(texName, p2w, p2h, width, height);
429: } else {
430: gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
431: tp.width = width;
432: tp.height = height;
433: tp.p2w = p2w;
434: tp.p2h = p2h;
435: }
436:
437: // XXX - todo - check for texture non p2 extension
438: gl.glTexImage2D(GLDefs.GL_TEXTURE_2D, 0,
439: imageParams.oglIntFormat, p2w, p2h, 0,
440: imageParams.oglFormat, imageParams.oglType, 0);
441:
442: // Obtain image data in opengl-compatible format and draw the image
443: if (requiresConversion || needPremultiply) {
444: // needPremultiply should be always false for OGLSurface, type cast is safe
445: gl.glTexSubImage2D(GLDefs.GL_TEXTURE_2D, 0, 0, 0,
446: //imageParams.oglIntFormat,
447: width,
448: height, // 0,
449: imageParams.oglFormat, imageParams.oglType,
450: ((ImageSurface) srcSurf).getCachedData(srcCM
451: .isAlphaPremultiplied()
452: || needPremultiply));
453: } else {
454: Object data = srcSurf.getData();
455: LockedArray ldata = Utils.arraccess.lockArrayShort(data);
456: gl.glTexSubImage2D(GLDefs.GL_TEXTURE_2D, 0, 0, 0,
457: //imageParams.oglIntFormat,
458: width, height, //0,
459: imageParams.oglFormat, imageParams.oglType, ldata
460: .getAddress());
461:
462: ldata.release();
463: }
464:
465: return tp;
466: }
467:
468: final OGLTextureParams blitImg2OGLTexCached(Surface srcSurf,
469: int width, int height, boolean needPremultiply) {
470: TextureCache tc = TextureCache.getInstance();
471: OGLTextureParams tp = tc.findTexture(srcSurf);
472:
473: if (tp != null) {
474: if (width > tp.width || height > tp.height
475: || !srcSurf.isCaheValid(tp)) {
476: tp = blitImg2OGLTex(srcSurf, width, height,
477: needPremultiply, tp);
478: srcSurf.addValidCache(tp);
479: } else {
480: gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
481: }
482: } else {
483: tp = blitImg2OGLTex(srcSurf, width, height,
484: needPremultiply, null);
485: tc.add(srcSurf, tp);
486: srcSurf.addValidCache(tp);
487: tc.cleanupTextures();
488: }
489:
490: gl.glTexEnvf(GLDefs.GL_TEXTURE_ENV, GLDefs.GL_TEXTURE_ENV_MODE,
491: GLDefs.GL_REPLACE);
492:
493: return tp;
494: }
495:
496: private final OGLTextureParams blitOGL2OGLTexCached(
497: OGLSurface srcSurf, OGLSurface dstSurf, int srcX, int srcY,
498: int dstX, int dstY, int width, int height) {
499: TextureCache tc = TextureCache.getInstance();
500: OGLTextureParams tp = tc.findTexture(srcSurf);
501:
502: if (tp != null) {
503: if (width > tp.width || height > tp.height
504: || !srcSurf.isCaheValid(tp)) {
505: tp = blitOGL2OGLTex(srcSurf, dstSurf, srcX, srcY, dstX,
506: dstY, width, height, tp);
507: srcSurf.addValidCache(tp);
508: } else {
509: gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
510: }
511: } else {
512: tp = blitOGL2OGLTex(srcSurf, dstSurf, srcX, srcY, dstX,
513: dstY, width, height, null);
514: tc.add(srcSurf, tp);
515: srcSurf.addValidCache(tp);
516: tc.cleanupTextures();
517: }
518:
519: gl.glTexEnvf(GLDefs.GL_TEXTURE_ENV, GLDefs.GL_TEXTURE_ENV_MODE,
520: GLDefs.GL_REPLACE);
521:
522: return tp;
523: }
524:
525: private final OGLTextureParams blitOGL2OGLTex(OGLSurface srcSurf,
526: OGLSurface dstSurf, int srcX, int srcY, int dstX, int dstY,
527: int width, int height, OGLTextureParams tp) {
528: OGLImageParams imageParams = IMAGE_TYPE_MAPPING[BufferedImage.TYPE_INT_ARGB_PRE];
529: gl.glPixelStorei(GLDefs.GL_UNPACK_ALIGNMENT,
530: imageParams.oglAlignment);
531:
532: int p2w = p2(width);
533: int p2h = p2(height);
534:
535: if (tp == null) {
536: Int32Pointer texPtr = NativeBridge.getInstance()
537: .createInt32Pointer(1, true);
538:
539: gl.glGenTextures(1, texPtr);
540: int texName = texPtr.get(0);
541: gl.glBindTexture(GLDefs.GL_TEXTURE_2D, texName);
542: texPtr.free();
543:
544: gl.glTexParameteri(GLDefs.GL_TEXTURE_2D,
545: GLDefs.GL_TEXTURE_MAG_FILTER, GLDefs.GL_NEAREST);
546: gl.glTexParameteri(GLDefs.GL_TEXTURE_2D,
547: GLDefs.GL_TEXTURE_MIN_FILTER, GLDefs.GL_NEAREST);
548:
549: tp = new OGLTextureParams(texName, p2w, p2h, width, height);
550: } else {
551: gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
552: tp.width = width;
553: tp.height = height;
554: tp.p2w = p2w;
555: tp.p2h = p2h;
556: }
557:
558: // XXX - todo - check for texture non p2 extension
559: gl.glTexImage2D(GLDefs.GL_TEXTURE_2D, 0,
560: imageParams.oglIntFormat, p2w, p2h, 0,
561: imageParams.oglFormat, imageParams.oglType, 0);
562:
563: // Obtain image data in opengl-compatible format and draw the image
564: boolean copied = dstSurf.oglg.copyArea(srcX, srcY, width,
565: height, dstX, dstY, (srcSurf).oglg, true);
566:
567: return copied ? tp : null;
568: }
569:
570: }
|