aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/RasterRetained.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/media/j3d/RasterRetained.java')
-rw-r--r--src/javax/media/j3d/RasterRetained.java691
1 files changed, 691 insertions, 0 deletions
diff --git a/src/javax/media/j3d/RasterRetained.java b/src/javax/media/j3d/RasterRetained.java
new file mode 100644
index 0000000..dd8245e
--- /dev/null
+++ b/src/javax/media/j3d/RasterRetained.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package javax.media.j3d;
+
+import java.awt.Dimension;
+import java.awt.Point;
+import java.util.ArrayList;
+
+import javax.vecmath.Point2d;
+import javax.vecmath.Point2i;
+import javax.vecmath.Point3d;
+import javax.vecmath.Point3f;
+import javax.vecmath.Point4d;
+
+/**
+ * A Retained Raster.
+ */
+
+class RasterRetained extends GeometryRetained {
+
+ /**
+ * Raster type
+ */
+ int type = Raster.RASTER_COLOR;
+
+ private int clipMode = Raster.CLIP_POSITION;
+ private Point3f position = new Point3f();
+ private int xSrcOffset = 0;
+ private int ySrcOffset = 0;
+ private int width = 0;
+ private int height = 0;
+ private int xDstOffset = 0;
+ private int yDstOffset = 0;
+ ImageComponent2DRetained image = null;
+ Texture2DRetained texture = null;
+ DepthComponentRetained depthComponent = null;
+
+ RasterRetained() {
+ this.geoType = GEO_TYPE_RASTER;
+ }
+
+ /**
+ * Set the Raster position
+ * @param position new raster position
+ */
+ final void setPosition(Point3f pos) {
+ geomLock.getLock();
+ position.x = pos.x;
+ position.y = pos.y;
+ position.z = pos.z;
+ geomLock.unLock();
+ sendChangedMessage(J3dThread.UPDATE_GEOMETRY, null, null);
+ }
+
+ /**
+ * Retrieves the Raster's position
+ * @param position the variable to receive the position vector
+ */
+ final void getPosition(Point3f pos) {
+ pos.x = position.x;
+ pos.y = position.y;
+ pos.z = position.z;
+ }
+
+ /**
+ * Sets the type of this raster object to one of: RASTER_COLOR,
+ * RASTER_DEPTH, or RASTER_COLOR_DEPTH.
+ * @param type the new type of this raster
+ */
+ final void setType(int type) {
+ geomLock.getLock();
+ this.type = type;
+ geomLock.unLock();
+ }
+
+
+ /**
+ * Retrieves the current type of this raster object, one of: RASTER_COLOR,
+ * RASTER_DEPTH, or RASTER_COLOR_DEPTH.
+ * @return type the type of this raster
+ */
+ final int getType() {
+ return type;
+ }
+
+ /**
+ * Sets the clipping mode of this raster object.
+ * @param clipMode the new clipping mode of this raster,
+ * one of: CLIP_POSITION or CLIP_IMAGE. The default mode
+ * is CLIP_POSITION.
+ */
+ final void setClipMode(int clipMode) {
+
+ geomLock.getLock();
+ this.clipMode = clipMode;
+ geomLock.unLock();
+ computeBoundingBox();
+ if(source.isLive()) {
+ //update the Shape3Ds that refer to this Raster
+ int un = userLists.size();
+ Shape3DRetained ms, shape;
+ int sn;
+ for(int i = 0; i < un; i++) {
+ ArrayList<Shape3DRetained> shapeList = userLists.get(i);
+ sn = shapeList.size();
+ for(int j = 0; j < sn; j++) {
+ ms = shapeList.get(j);
+ shape = (Shape3DRetained)ms.sourceNode;
+ shape.setBoundsAutoCompute(false);
+ shape.setBounds(geoBounds);
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Retrieves the current clipping mode of this raster object.
+ * @return clipMode the clipping mode of this raster,
+ * one of: CLIP_POSITION or CLIP_IMAGE.
+ */
+ final int getClipMode() {
+ return clipMode;
+ }
+
+ /**
+ * Sets the offset within the source array of pixels at which
+ * to start copying.
+ * @param xSrcOffset the x offset within the source array of pixels
+ * at which to start copying
+ * @param ySrcOffset the y offset within the source array of pixels
+ * at which to start copying
+ */
+ final void setSrcOffset(int xSrcOffset, int ySrcOffset) {
+ geomLock.getLock();
+ this.xSrcOffset = xSrcOffset;
+ this.ySrcOffset = ySrcOffset;
+ geomLock.unLock();
+ }
+
+ /**
+ * Retrieves the current source pixel offset.
+ * @param srcOffset the object that will receive the source offset
+ */
+ final void getSrcOffset(Point srcOffset) {
+ srcOffset.setLocation(xSrcOffset, ySrcOffset);
+ }
+
+ /**
+ * Sets the number of pixels to be copied from the pixel array.
+ * @param width the number of columns in the array of pixels to copy
+ * @param height the number of rows in the array of pixels to copy
+ */
+ final void setSize(int width, int height) {
+ geomLock.getLock();
+ this.width = width;
+ this.height = height;
+ geomLock.unLock();
+ }
+
+ /**
+ * Gets the size of the array of pixels to be copied.
+ * @param size the new size
+ */
+ final void getSize(Dimension size) {
+ size.setSize(width, height);
+ }
+
+ /**
+ * Sets the destination pixel offset of the upper-left
+ * corner of the rendered image relative to the transformed position.
+ * @param xDstOffset the x coordinate of the new offset
+ * @param yDstOffset the y coordinate of the new offset
+ */
+ final void setDstOffset(int xDstOffset, int yDstOffset) {
+ geomLock.getLock();
+ this.xDstOffset = xDstOffset;
+ this.yDstOffset = yDstOffset;
+ geomLock.unLock();
+ }
+
+ /**
+ * Retrieves the current destination pixel offset.
+ * @param dstOffset the object that will receive the destination offset
+ */
+ final void getDstOffset(Point dstOffset) {
+ dstOffset.setLocation(xDstOffset, yDstOffset);
+ }
+
+
+ /**
+ * Initializes the raster image to the specified image.
+ * @param image new ImageCompoent2D object used as the raster image
+ */
+ final void initImage(ImageComponent2D img) {
+
+ int texFormat;
+
+ if(img == null) {
+ image = null;
+ texture = null;
+ return;
+ }
+
+ image = (ImageComponent2DRetained) img.retained;
+ image.setEnforceNonPowerOfTwoSupport(true);
+ switch(image.getNumberOfComponents()) {
+ case 1:
+ texFormat = Texture.INTENSITY;
+ break;
+ case 2:
+ texFormat = Texture.LUMINANCE_ALPHA;
+ break;
+ case 3:
+ texFormat = Texture.RGB;
+ break;
+ case 4:
+ texFormat = Texture.RGBA;
+ break;
+ default:
+ assert false;
+ return;
+ }
+
+ Texture2D tex2D = new Texture2D(Texture.BASE_LEVEL, texFormat,
+ img.getWidth(), img.getHeight());
+ texture = (Texture2DRetained) tex2D.retained;
+ texture.setUseAsRaster(true);
+ // Fix to issue 372 : ImageComponent.set(BufferedImage) ignored when used by Raster
+ image.addUser(texture);
+ texture.initImage(0,img);
+
+ }
+
+ /**
+ * Sets the pixel array used to copy pixels to/from a Canvas3D.
+ * This is used when the type is RASTER_COLOR or RASTER_COLOR_DEPTH.
+ * @param image the ImageComponent2D object containing the
+ * color data
+ */
+ final void setImage(ImageComponent2D img) {
+
+ if((img != null) &&
+ (img.getImageClass() == ImageComponent.ImageClass.NIO_IMAGE_BUFFER)) {
+ throw new IllegalArgumentException(J3dI18N.getString("Background14"));
+ }
+
+ TextureRetained oldTex = this.texture;
+ if (source.isLive()) {
+ if (this.texture != null) {
+ this.texture.clearLive(refCount);
+ }
+ }
+
+ // Issue 370: only hold the geomLock while calling initImage
+ // (cannot hold it while sending a message).
+ geomLock.getLock();
+ initImage(img);
+ geomLock.unLock();
+
+ if (source.isLive()) {
+ if (texture != null) {
+ texture.setLive(inBackgroundGroup, refCount);
+ }
+
+ sendChangedMessage((J3dThread.UPDATE_RENDER|J3dThread.UPDATE_RENDERING_ATTRIBUTES),
+ oldTex, this.texture);
+ }
+ }
+
+ /**
+ * Retrieves the current pixel array object.
+ * @return image the ImageComponent2D object containing the
+ * color data
+ */
+ final ImageComponent2D getImage() {
+ return (image == null ? null : (ImageComponent2D)image.source);
+ }
+
+ /**
+ * Sets the depth image used to copy pixels to/from a Canvas3D.
+ * This is used when the type is RASTER_DEPTH or RASTER_COLOR_DEPTH.
+ * @param depthImage the DepthComponent object containing the
+ * depth (z-buffer) data
+ */
+ final void setDepthComponent(DepthComponent depthComponent) {
+ geomLock.getLock();
+ if (this.source.isLive()) {
+ if (this.depthComponent != null) {
+ this.depthComponent.clearLive(refCount);
+ }
+ if (depthComponent != null) {
+ ((DepthComponentRetained)depthComponent.retained).setLive(inBackgroundGroup, refCount);
+ }
+ }
+
+ if (depthComponent == null) {
+ this.depthComponent = null;
+ } else {
+ this.depthComponent =
+ (DepthComponentRetained)depthComponent.retained;
+ }
+ geomLock.unLock();
+ }
+
+ /**
+ * Retrieves the current depth image object.
+ * @return depthImage DepthComponent containing the
+ * depth (z-buffer) data
+ */
+ final DepthComponent getDepthComponent() {
+ return (depthComponent == null ? null :
+ (DepthComponent)depthComponent.source);
+ }
+
+ @Override
+ void setLive(boolean inBackgroundGroup, int refCount) {
+ super.doSetLive(inBackgroundGroup, refCount);
+ if (texture != null) {
+ texture.setLive(inBackgroundGroup, refCount);
+ }
+ if (depthComponent != null) {
+ depthComponent.setLive(inBackgroundGroup, refCount);
+ }
+ isEditable = source.getCapability(Raster.ALLOW_OFFSET_WRITE) ||
+ source.getCapability(Raster.ALLOW_POSITION_WRITE) ||
+ ((type & Raster.RASTER_COLOR) != 0 &&
+ source.getCapability(Raster.ALLOW_IMAGE_WRITE)) ||
+ ((type & Raster.RASTER_DEPTH) != 0 &&
+ source.getCapability(
+ Raster.ALLOW_DEPTH_COMPONENT_WRITE)) ||
+ source.getCapability( Raster.ALLOW_SIZE_WRITE);
+
+ super.markAsLive();
+ }
+
+ @Override
+ void clearLive(int refCount) {
+ super.clearLive(refCount);
+ if (texture != null)
+ texture.clearLive(refCount);
+ if (depthComponent != null)
+ depthComponent.clearLive(refCount);
+ }
+ /*
+ // Simply pass along to the NodeComponents
+ void compile(CompileState compState) {
+ setCompiled();
+
+ if (image != null)
+ image.compile(compState);
+
+ if (depthComponent != null)
+ depthComponent.compile(compState);
+ }
+ */
+
+ @Override
+ void computeBoundingBox() {
+ if(clipMode == Raster.CLIP_IMAGE) {
+ // Disable view frustum culling by setting the raster's bounds to
+ // infinity.
+ Point3d minBounds = new Point3d(Double.NEGATIVE_INFINITY,
+ Double.NEGATIVE_INFINITY,
+ Double.NEGATIVE_INFINITY);
+ Point3d maxBounds = new Point3d(Double.POSITIVE_INFINITY,
+ Double.POSITIVE_INFINITY,
+ Double.POSITIVE_INFINITY);
+ geoBounds.setUpper(maxBounds);
+ geoBounds.setLower(minBounds);
+ } else {
+ Point3d center = new Point3d();
+ center.x = position.x;
+ center.y = position.y;
+ center.z = position.z;
+ geoBounds.setUpper(center);
+ geoBounds.setLower(center);
+ }
+ }
+
+ @Override
+ void update() {
+ computeBoundingBox();
+ }
+
+ private void sendChangedMessage(int threads, Object arg1, Object arg2) {
+
+ synchronized(liveStateLock) {
+ if (source.isLive()) {
+ synchronized (universeList) {
+ int numMessages = universeList.size();
+ J3dMessage[] m = new J3dMessage[numMessages];
+ for (int i=0; i<numMessages; i++) {
+ m[i] = new J3dMessage();
+ m[i].type = J3dMessage.GEOMETRY_CHANGED;
+ m[i].threads = threads;
+ m[i].args[0] = Shape3DRetained.getGeomAtomsArray(userLists.get(i));
+ m[i].args[1] = this;
+ Object[] obj = new Object[2];
+ obj[0] = arg1;
+ obj[1] = arg2;
+ m[i].args[2] = obj;
+ m[i].args[3] = new Integer(changedFrequent);
+ m[i].universe = universeList.get(i);
+ }
+ VirtualUniverse.mc.processMessage(m);
+ }
+ }
+ }
+ }
+
+
+ @Override
+ void execute(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale,
+ boolean updateAlpha, float alpha,
+ int screen, boolean ignoreVertexColors) {
+
+ // Compute the offset position of the raster
+ // This has to be done at render time because we need access
+ // to the Canvas3D info
+
+ // Check if adjusted position needs to be computed
+ Point3d adjPos = new Point3d(); // Position of the Raster after adjusting for dstOffset
+ adjPos.set(position);
+
+ Point2d winCoord = new Point2d(); // Position of Raster in window coordinates
+ Transform3D localToImagePlate = new Transform3D(); // Local to Image plate transform
+
+ Point3d clipCoord = computeWinCoord(cv, ra, winCoord, adjPos, localToImagePlate);
+
+ // Test raster for out of bounds in Z.
+ if (clipCoord == null) {
+ return;
+ }
+
+ if(clipMode == Raster.CLIP_POSITION) {
+ // Do trivial reject test on Raster position.
+ if(!isRasterClipPositionInside(clipCoord)) {
+ return;
+ }
+ }
+
+ // Add the destination offset to the Raster position in window coordinates
+ winCoord.x += xDstOffset;
+ winCoord.y += yDstOffset;
+
+ // System.err.println("Step 2 : adjPos " + adjPos + " winCoord " + winCoord);
+
+
+ if((type == Raster.RASTER_COLOR) || (type == Raster.RASTER_COLOR_DEPTH)) {
+ float devCoordZ = (float) (clipCoord.z * 0.5 - 0.5);
+ // Do textfill stuffs
+ if (texture != null) {
+ // setup Texture pipe.
+ cv.updateTextureForRaster(texture);
+
+ cv.textureFill(this, winCoord, devCoordZ, alpha);
+
+ // Restore texture pipe.
+ cv.restoreTextureBin();
+ }
+
+ }
+
+ if((type == Raster.RASTER_DEPTH) || (type == Raster.RASTER_COLOR_DEPTH)) {
+
+ Point2i srcOffset = new Point2i(xSrcOffset, ySrcOffset);
+
+ if (clipMode == Raster.CLIP_IMAGE) {
+ clipImage(cv, ra, winCoord, srcOffset);
+ }
+
+ computeObjCoord(cv, winCoord, adjPos, localToImagePlate);
+
+ cv.executeRasterDepth(cv.ctx,
+ (float) adjPos.x,
+ (float) adjPos.y,
+ (float) adjPos.z,
+ srcOffset.x,
+ srcOffset.y,
+ width,
+ height,
+ depthComponent.width,
+ depthComponent.height,
+ depthComponent.type,
+ ((DepthComponentIntRetained) depthComponent).depthData);
+
+ }
+ }
+
+
+ /**
+ * Clips the image against the window. This method simulates
+ * clipping the image by determining the subimage that will be
+ * drawn and adjusting the xOffset and yOffset accordingly. Only
+ * clipping against the left and top edges needs to be handled,
+ * clipping against the right and bottom edges will be handled by
+ * the underlying graphics library automatically.
+ */
+ private void clipImage(Canvas3D canvas, RenderAtom ra, Point2d winCoord, Point2i srcOffset) {
+
+ if ((winCoord.x > 0) && (winCoord.y > 0)) {
+ return;
+ }
+
+ // Check if the Raster point will be culled
+ // Note that w use 1 instead of 0, because when hardware
+ // tranform the coordinate back to winCoord it may get
+ // a small negative value due to numerically inaccurancy.
+ // This clip the Raster away and cause flickering
+ // (see bug 4732965)
+ if(winCoord.x < 1) {
+ // Negate the window position and use this as the offset
+ srcOffset.x = (int)-winCoord.x+1;
+ winCoord.x = 1;
+ }
+
+ if(winCoord.y < 1) {
+ // Negate the window position and use this as the offset
+ srcOffset.y = (int)-winCoord.y+1;
+ winCoord.y = 1;
+ }
+
+ //check if user-specified subimage is smaller than the clipped image
+ if (srcOffset.x < xSrcOffset)
+ srcOffset.x = xSrcOffset;
+ if(srcOffset.y < ySrcOffset)
+ srcOffset.y = ySrcOffset;
+
+ }
+
+
+ private boolean isRasterClipPositionInside(Point3d clipCoord) {
+ return (clipCoord.x >= -1.0) && (clipCoord.x <= 1.0) &&
+ (clipCoord.y >= -1.0) && (clipCoord.y <= 1.0);
+ }
+
+ private void computeObjCoord(Canvas3D canvas, Point2d winCoord, Point3d objCoord,
+ Transform3D localToImagePlate) {
+ // Back transform this pt. from window to object coordinates
+ // Assumes this method is ALWAYS called after computeWinCoord has been
+ // called. computeWinCoord calculates the Vworld to Image Plate Xform.
+ // This method simply uses it without recomputing it.
+
+ canvas.getPixelLocationInImagePlate(winCoord.x, winCoord.y, objCoord.z,
+ objCoord);
+ // Get image plate to object coord transform
+ // inv(P x M)
+ localToImagePlate.invert();
+ localToImagePlate.transform(objCoord);
+ }
+
+ private Point3d computeWinCoord(Canvas3D canvas, RenderAtom ra,
+ Point2d winCoord, Point3d objCoord,
+ Transform3D localToImagePlate) {
+ // Get local to Vworld transform
+ RenderMolecule rm = ra.renderMolecule;
+
+ if (rm == null) {
+ // removeRenderAtom() may set ra.renderMolecule to null
+ // in RenderBin before this renderer thread run.
+ return null;
+ }
+
+ // MT safe issue: We can't reference ra.renderMolecule below since
+ // RenderBin thread may set it to null anytime. Use rm instead.
+
+ Transform3D lvw = rm.localToVworld[rm.localToVworldIndex[
+ NodeRetained.LAST_LOCAL_TO_VWORLD]];
+
+
+ Point3d clipCoord3 = new Point3d();
+ clipCoord3.set(objCoord);
+ Point4d clipCoord4 = new Point4d();
+
+ // Transform point from local coord. to clipping coord.
+ lvw.transform(clipCoord3);
+ canvas.vworldToEc.transform(clipCoord3);
+ canvas.projTrans.transform(clipCoord3, clipCoord4);
+
+ // clip check in Z
+ if((clipCoord4.w <= 0.0) ||
+ (clipCoord4.z > clipCoord4.w) || (-clipCoord4.z > clipCoord4.w)) {
+
+ return null;
+ }
+ double invW = 1.0 / clipCoord4.w;
+
+ clipCoord3.x = clipCoord4.x * invW;
+ clipCoord3.y = clipCoord4.y * invW;
+ clipCoord3.z = clipCoord4.z * invW;
+
+ // Get Vworld to image plate Xform
+ canvas.getLastVworldToImagePlate(localToImagePlate);
+
+ // v' = vwip x lvw x v
+ // where v' = transformed vertex,
+ // lvw = local to Vworld Xform
+ // vwip = Vworld to Image plate Xform
+ // v = vertex
+
+ // Compute composite local to image plate Xform
+ localToImagePlate.mul(lvw);
+
+ // Transform the Raster's position from object to world coordinates
+ localToImagePlate.transform(objCoord);
+
+
+ // Get the window coordinates of this point
+ canvas.getPixelLocationFromImagePlate(objCoord, winCoord);
+
+ return clipCoord3;
+ }
+
+ @Override
+ int getClassType() {
+ return RASTER_TYPE;
+ }
+
+ // notifies the Raster mirror object that the image data in a referenced
+ // ImageComponent object is changed.
+ // Currently we are not making use of this information.
+
+ void notifyImageComponentImageChanged(ImageComponentRetained image,
+ ImageComponentUpdateInfo value) {
+ }
+
+ @Override
+ boolean intersect(PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt,
+ GeometryRetained geom, int geomIndex) {
+ return false;
+ }
+
+ @Override
+ boolean intersect(Bounds targetBound) {
+ return false;
+ }
+
+ @Override
+ boolean intersect(Point3d[] pnts) {
+ return false;
+ }
+ @Override
+ boolean intersect(Transform3D thisToOtherVworld, GeometryRetained
+ geom) {
+ return false;
+ }
+ @Override
+ boolean intersect(Transform3D thisLocalToVworld,
+ Transform3D otherLocalToVworld,
+ GeometryRetained geom) {
+ return false;
+ }
+
+ @Override
+ boolean intersect(Transform3D thisLocalToVworld, Bounds targetBound) {
+ return false;
+ }
+ @Override
+ void handleFrequencyChange(int bit) {
+ if (bit == Raster.ALLOW_IMAGE_WRITE)
+ setFrequencyChangeMask(bit, 0x1);
+
+ }
+
+}