diff options
Diffstat (limited to 'src/javax/media/j3d/RasterRetained.java')
-rw-r--r-- | src/javax/media/j3d/RasterRetained.java | 691 |
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); + + } + +} |