/* This file is part of the source code for 3D-XplorMath-J, Version 1.0 (January 2008).
* Copyright (c) 2008 The 3D-XplorMath Consortium (http://3d-xplormath.org).
* This source code is released under a BSD License, which allows redistribution
* in source and binary form, with or without modification, provided copyright
* and license information are included, and with no warranty or guarantee of
* any kind. For details, see http://3d-xplormath.org/j/source/BSDLicense.txt
*/
package vmm.core3D.render;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import vmm.core.Prefs;
import vmm.core.Transform;
import vmm.core.View;
import vmm.core.render.ImageRenderer2D;
import vmm.core3D.Grid3D;
import vmm.core3D.StereoComposite;
import vmm.core3D.Transform3D;
import vmm.core3D.View3D;
import vmm.core3D.Vector3D;
import vmm.core3D.View3DLit;
public class ImageRenderer3D extends ImageRenderer2D implements Renderer3D {
protected View3D view3D;
protected View3DLit view3DLit; // copy of view3D, or null if view3D is not an instance of view3DLit
protected Transform3D transform3D;
protected BufferedImage image2; // right-eye image for stereo viewing
protected StereoComposite stereoComposite;
protected Graphics2D leftEyeGraphics, rightEyeGraphics;
protected Graphics2D leftEyeUntransformedGraphics, rightEyeUntransformedGraphics;
protected Graphics2D saveGraphicsDuringStereo, saveUntransformedGraphicsDuringStereo;
protected Rectangle leftEyeRect, rightEyeRect;
protected int currentWidth, currentHeight;
protected int viewStyle;
private Vector3D viewDirection;
private double clipZ;
private double eyeSeparationMultiplier;
public void startRender(View view, Transform transform, int width, int height) {
if (! (view instanceof View3D) || ! (transform instanceof Transform3D) ) {
view3D = null; // These will cause an error if any attempt is made to use 3D drawing methods.
view3DLit = null;
transform3D = null;
viewStyle = View3D.MONOCULAR_VIEW;
super.startRender(view,transform,width,height);
return;
}
view3D = (View3D)view;
view3DLit = (view instanceof View3DLit)? (View3DLit)view : null;
this.transform = transform;
transform3D = (Transform3D)transform;
viewStyle = view3D.getViewStyle();
if (viewStyle != View3D.RED_GREEN_STEREO_VIEW && stereoComposite != null) {
stereoComposite.releaseMemory();
stereoComposite = null;
}
int type = (view3DLit != null && view3DLit.getBlackAndWhite())? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_INT_RGB;
switch (viewStyle) {
case View3D.MONOCULAR_VIEW:
image2 = null;
if (image == null || image.getWidth() != width || image.getHeight() != height || image.getType() != type) {
image = null;
image = new BufferedImage(width,height,type);
}
break;
case View3D.STEREOGRAPH_VIEW:
case View3D.CROSS_EYE_STEREO_VIEW:
Rectangle[] rects = view3D.getSterographViewRectangles();
leftEyeRect = rects[0];
rightEyeRect = rects[1];
int w = leftEyeRect.width;
int h = leftEyeRect.height;
if (image == null || image2 == null || image.getWidth() != w || image.getHeight() != h
|| image2.getWidth() != w || image2.getHeight() != h || image.getType() != type || image2.getType() != type) {
image = image2 = null;
image = new BufferedImage(w,h,type);
image2 = new BufferedImage(w,h,type);
}
break;
case View3D.RED_GREEN_STEREO_VIEW:
image = image2 = null;
if (stereoComposite == null)
stereoComposite = new StereoComposite();
if (stereoComposite.getWidth() != width || stereoComposite.getHeight() != height)
stereoComposite.setSize(width,height);
image = stereoComposite.getLeftEyeImage();
image2 = stereoComposite.getRightEyeImage();
break;
}
setupRenderInfo(width,height,true);
currentWidth = width;
currentHeight = height;
}
private void setupRenderInfo(int width, int height, boolean clear) {
viewDirection = transform3D.getViewDirection();
viewDirection.negate(); // since the view direction returned above points from the viewpoint towards the origen, and I want the reverse for clipping
clipZ = transform3D.getFocalLength() - transform3D.getClipDistance();
eyeSeparationMultiplier = Prefs.getDouble("eyeSeparationMultiplier", 1);
foregroundColor = viewStyle == View3D.RED_GREEN_STEREO_VIEW? Color.WHITE : view3D.getForeground();
backgroundColor = viewStyle == View3D.RED_GREEN_STEREO_VIEW? Color.BLACK: view3D.getBackground();
antialiased = view3D.getAntialiased();
currentColor = foregroundColor;
if (viewStyle == View3D.MONOCULAR_VIEW) {
currentGraphics = image.createGraphics();
currentGraphics.setBackground(backgroundColor);
if (clear)
currentGraphics.clearRect(0, 0, width, height);
currentGraphics.setColor(currentColor);
if (antialiased)
currentGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
transform.setUpDrawInfo(currentGraphics, 0, 0, width, height, view3D.getPreserveAspect(), view3D.getApplyGraphics2DTransform());
}
else {
leftEyeGraphics = image.createGraphics();
rightEyeGraphics = image2.createGraphics();
leftEyeGraphics.setColor(currentColor);
leftEyeGraphics.setBackground(backgroundColor);
if (clear)
leftEyeGraphics.clearRect(0,0,image.getWidth(),image.getHeight());
rightEyeGraphics.setColor(currentColor);
rightEyeGraphics.setBackground(backgroundColor);
if (clear)
rightEyeGraphics.clearRect(0,0,image.getWidth(),image.getHeight());
if (antialiased) {
leftEyeGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
rightEyeGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
}
transform3D.setUpDrawInfo(rightEyeGraphics,0,0,image2.getWidth(),image2.getHeight(),
view3D.getPreserveAspect(),view3D.getApplyGraphics2DTransform());
rightEyeUntransformedGraphics = transform3D.getUntransformedGraphics();
transform3D.setUpDrawInfo(leftEyeGraphics,0,0,image.getWidth(),image.getHeight(),
view3D.getPreserveAspect(),view3D.getApplyGraphics2DTransform());
leftEyeUntransformedGraphics = transform3D.getUntransformedGraphics();
currentGraphics = leftEyeGraphics; // should not be used -- there should be no 2D drawing in stereo mode ??
}
}
public boolean restartRender(View view, Transform transform, int width, int height) {
if (! (view instanceof View3D) )
return super.restartRender(view,transform,width,height);
if (((View3D)view).getViewStyle() != viewStyle || width != currentWidth || height != currentHeight)
return false;
view3D = (View3D)view;
view3DLit = (view instanceof View3DLit)? (View3DLit)view : null;
transform3D = (Transform3D)transform;
this.transform = transform;
setupRenderInfo(width,height,false);
return true;
}
public void endRender() {
if (view3D == null) {
super.endRender();
return;
}
if (viewStyle == View3D.RED_GREEN_STEREO_VIEW)
stereoComposite.compose();
transform3D.finishDrawing();
currentGraphics.dispose();
currentGraphics = null;
if (viewStyle != View3D.MONOCULAR_VIEW) {
rightEyeGraphics.dispose();
if (rightEyeUntransformedGraphics != rightEyeGraphics)
rightEyeUntransformedGraphics.dispose();
leftEyeGraphics = rightEyeGraphics = leftEyeUntransformedGraphics = rightEyeUntransformedGraphics = null;
}
transform = null;
view3D = null;
view3DLit = null;
transform3D = null;
}
public void dispose() {
if (view3D == null) {
super.dispose();
return;
}
image = image2 = null;
if (stereoComposite != null) {
stereoComposite.releaseMemory();
stereoComposite = null;
}
currentWidth = currentHeight = 0;
}
public void draw(Graphics2D g) {
//System.out.println("Draw " + Math.random());
if (viewStyle == View3D.MONOCULAR_VIEW)
g.drawImage(image,0,0,null);
else if (viewStyle == View3D.RED_GREEN_STEREO_VIEW)
g.drawImage(stereoComposite.getImage(),0,0,null);
else {
Color saveColor = g.getColor();
g.setColor(Color.WHITE);
g.fillRect(0,0,currentWidth,currentHeight);
g.drawImage(image,leftEyeRect.x,leftEyeRect.y,null);
g.drawImage(image2,rightEyeRect.x,rightEyeRect.y,null);
g.setColor(Color.GRAY);
g.drawRect(leftEyeRect.x-1, leftEyeRect.y-1, leftEyeRect.width+1, leftEyeRect.width+1);
g.drawRect(rightEyeRect.x-1, rightEyeRect.y-1, rightEyeRect.width+1, rightEyeRect.width+1);
g.setColor(saveColor);
}
}
public BufferedImage getImage(boolean alwaysCopy) {
if (image == null)
return null;
if (!alwaysCopy) {
if (viewStyle == View3D.MONOCULAR_VIEW)
return image;
if (viewStyle == View3D.RED_GREEN_STEREO_VIEW)
return stereoComposite.getImage();
}
int type;
if (viewStyle == View3D.RED_GREEN_STEREO_VIEW)
type = BufferedImage.TYPE_INT_RGB;
else
type = image.getType();
BufferedImage copy = new BufferedImage(currentWidth, currentHeight, type);
Graphics2D g = copy.createGraphics();
draw(g);
g.dispose();
return copy;
}
public void drawPixel(Vector3D v) {
Point2D pt = new Point2D.Double();
if (clip(v))
return;
int rgb = viewStyle == View3D.RED_GREEN_STEREO_VIEW? 0xFFFFFF : currentColor.getRGB();
if (viewStyle == View3D.MONOCULAR_VIEW) {
transform3D.objectToXYWindowCoords(v,pt);
transform3D.windowToViewport(pt);
try {
image.setRGB((int)pt.getX(),(int)pt.getY(),rgb);
}
catch (Exception e) {
}
}
else {
setUpForLeftEye();
transform3D.objectToXYWindowCoords(v,pt);
transform3D.windowToViewport(pt);
try {
image.setRGB((int)pt.getX(),(int)pt.getY(),rgb);
}
catch (Exception e) {
}
setUpForRightEye();
transform3D.objectToXYWindowCoords(v,pt);
transform3D.windowToViewport(pt);
try {
image2.setRGB((int)pt.getX(),(int)pt.getY(),rgb);
}
catch (Exception e) {
}
finishStereoView();
}
}
public void drawDot(Vector3D pt, double diameter) {
double h = diameter*transform3D.getPixelWidth();
double w = diameter*transform3D.getPixelHeight();
Point2D pt2D = new Point2D.Double();
if (viewStyle == View3D.MONOCULAR_VIEW) {
transform3D.objectToDrawingCoords(pt, pt2D);
currentGraphics.fill(new Ellipse2D.Double(pt2D.getX()-h/2,pt2D.getY()-w/2,h,w));
}
else {
setUpForLeftEye();
transform3D.objectToDrawingCoords(pt, pt2D);
currentGraphics.fill(new Ellipse2D.Double(pt2D.getX()-h/2,pt2D.getY()-w/2,h,w));
setUpForRightEye();
transform3D.objectToDrawingCoords(pt, pt2D);
currentGraphics.fill(new Ellipse2D.Double(pt2D.getX()-h/2,pt2D.getY()-w/2,h,w));
finishStereoView();
}
}
public void drawPixels(Vector3D[] vlist) {
Point2D pt = new Point2D.Double();
int rgb = viewStyle == View3D.RED_GREEN_STEREO_VIEW? 0xFFFFFF : currentColor.getRGB();
if (viewStyle == View3D.MONOCULAR_VIEW) {
for (int i = 0; i < vlist.length; i++)
if (vlist[i] != null && !clip(vlist[i])) {
transform3D.objectToXYWindowCoords(vlist[i],pt);
transform3D.windowToViewport(pt);
try {
image.setRGB((int)pt.getX(),(int)pt.getY(),rgb);
}
catch (Exception e) {
}
}
}
else {
setUpForLeftEye();
for (int i = 0; i < vlist.length; i++)
if (vlist[i] != null && !clip(vlist[i])) {
transform3D.objectToXYWindowCoords(vlist[i],pt);
transform3D.windowToViewport(pt);
try {
image.setRGB((int)pt.getX(),(int)pt.getY(),rgb);
}
catch (Exception e) {
}
}
setUpForRightEye();
for (int i = 0; i < vlist.length; i++)
if (vlist[i] != null && !clip(vlist[i])) {
transform3D.objectToXYWindowCoords(vlist[i],pt);
transform3D.windowToViewport(pt);
try {
image2.setRGB((int)pt.getX(),(int)pt.getY(),rgb);
}
catch (Exception e) {
}
}
finishStereoView();
}
}
public void drawLine(Vector3D v1, Vector3D v2) {
Point2D p1, p2;
if (clip(v1) || clip(v2))
return;
if (viewStyle == View3D.MONOCULAR_VIEW) {
p1 = transform3D.objectToDrawingCoords(v1);
p2 = transform3D.objectToDrawingCoords(v2);
currentGraphics.draw(new Line2D.Float(p1,p2));
}
else {
setUpForLeftEye();
p1 = transform3D.objectToDrawingCoords(v1);
p2 = transform3D.objectToDrawingCoords(v2);
currentGraphics.draw(new Line2D.Float(p1,p2));
setUpForRightEye();
p1 = transform3D.objectToDrawingCoords(v1);
p2 = transform3D.objectToDrawingCoords(v2);
currentGraphics.draw(new Line2D.Float(p1,p2));
finishStereoView();
}
}
public void drawString(String str, Vector3D basepoint) {
if (clip(basepoint))
return;
if (viewStyle == View3D.MONOCULAR_VIEW) {
Point2D p = transform3D.objectToXYWindowCoords(basepoint);
super.drawString(str,p.getX(),p.getY()); // NOTE: Don't call drawString(str,Point2D) -- leads to infinite recursion
}
else {
setUpForLeftEye();
Point2D p = transform3D.objectToXYWindowCoords(basepoint);
super.drawString(str,p.getX(),p.getY());
setUpForRightEye();
p = transform3D.objectToXYWindowCoords(basepoint);
super.drawString(str,p.getX(),p.getY());
finishStereoView();
}
}
public void drawCurve(Vector3D[] points, int startIndex, int endIndex) {
if (points == null)
return;
if (startIndex >= points.length)
startIndex = points.length - 1;
if (startIndex < 0)
startIndex = 0;
if (endIndex >= points.length)
endIndex = points.length - 1;
if (endIndex < 0)
endIndex = 0;
if (endIndex <= startIndex)
return;
Point2D[] projectedPoints = new Point2D[endIndex - startIndex + 1];
if (viewStyle == View3D.MONOCULAR_VIEW) {
for (int i = 0; i < projectedPoints.length; i++){
if (points[i - startIndex] == null || clip(points[i - startIndex]))
projectedPoints[i] = null;
else
projectedPoints[i] = transform3D.objectToXYWindowCoords(points[i - startIndex]);
}
super.drawCurve(projectedPoints,0,projectedPoints.length-1);
}
else {
setUpForLeftEye();
for (int i = 0; i < projectedPoints.length; i++){
if (points[i - startIndex] == null || clip(points[i - startIndex]))
projectedPoints[i] = null;
else
projectedPoints[i] = transform3D.objectToXYWindowCoords(points[i - startIndex]);
}
super.drawCurve(projectedPoints,0,projectedPoints.length-1);
setUpForRightEye();
for (int i = 0; i < projectedPoints.length; i++){
if (points[i - startIndex] == null || clip(points[i - startIndex]))
projectedPoints[i] = null;
else
projectedPoints[i] = transform3D.objectToXYWindowCoords(points[i - startIndex]);
}
super.drawCurve(projectedPoints,0,projectedPoints.length-1);
finishStereoView();
}
}
public void drawCollaredCurve(Vector3D[] points, int startIndex,
int endIndex, boolean reversed) {
if (points == null)
return;
if (!reversed && viewStyle != View3D.MONOCULAR_VIEW) {
drawCurve(points,startIndex,endIndex);
return;
}
if (startIndex >= points.length)
startIndex = points.length - 1;
if (startIndex < 0)
startIndex = 0;
if (endIndex >= points.length)
endIndex = points.length - 1;
if (endIndex < 0)
endIndex = 0;
if (endIndex <= startIndex)
return;
if (viewStyle == View3D.MONOCULAR_VIEW)
drawCollaredCurveDirect(points,startIndex,endIndex,reversed);
else {
setUpForLeftEye();
drawCollaredCurveDirect(points,startIndex,endIndex,reversed);
setUpForRightEye();
drawCollaredCurveDirect(points,startIndex,endIndex,reversed);
finishStereoView();
}
}
public void drawWireframeSurface(Grid3D surfaceData) {
if (viewStyle == View3D.MONOCULAR_VIEW) {
surfaceData.applyTransform(transform3D, view3D);
surfaceData.drawCurves(view3D, currentGraphics);
}
else {
setUpForLeftEye();
surfaceData.applyTransform(transform3D, view3D);
surfaceData.drawCurves(view3D, currentGraphics);
setUpForRightEye();
surfaceData.applyTransform(transform3D, view3D);
surfaceData.drawCurves(view3D, currentGraphics);
finishStereoView();
}
}
public void drawSurface(Grid3D surfaceData, double startPercent, double endPercent) {
if (view3DLit == null ||
((View3DLit)view3D).getRenderingStyle() == View3DLit.WIREFRAME_RENDERING ||
(view3D.getFastDrawing() && !view3DLit.getDragAsSurface())) {
drawWireframeSurface(surfaceData);
}
else if (((View3DLit)view3D).getRenderingStyle() == View3DLit.PATCH_RENDERING) {
if (view3D.getViewStyle() == View3D.MONOCULAR_VIEW) {
if (view3D.getAntialiased())
currentGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
surfaceData.applyTransform(transform3D, view3D);
if (view3D.getFastDrawing())
surfaceData.drawMajorPatches(view3DLit, currentGraphics);
else
surfaceData.drawSubPatches(view3DLit, currentGraphics, startPercent, endPercent);
if (view3D.getAntialiased())
currentGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
}
else {
setUpForLeftEye();
if (view3D.getAntialiased())
currentGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
surfaceData.applyTransform(transform3D, view3D);
if (view3D.getFastDrawing())
surfaceData.drawMajorPatches(view3DLit, currentGraphics);
else
surfaceData.drawSubPatches(view3DLit, currentGraphics, startPercent, endPercent);
if (view3D.getAntialiased())
currentGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
setUpForRightEye();
if (view3D.getAntialiased())
currentGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
surfaceData.applyTransform(transform3D, view3D);
if (view3D.getFastDrawing())
surfaceData.drawMajorPatches(view3DLit, currentGraphics);
else
surfaceData.drawSubPatches(view3DLit, currentGraphics, startPercent, endPercent);
if (view3D.getAntialiased())
currentGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
finishStereoView();
}
}
}
public void fillPolygon(Vector3D[] vertices, Color outlineColor) {
if (view3D.getViewStyle() == View3D.MONOCULAR_VIEW) {
Color saveColor = currentGraphics.getColor();
GeneralPath path = new GeneralPath();
Point2D pt = transform3D.objectToDrawingCoords(vertices[0]);
path.moveTo( (float)pt.getX(), (float)pt.getY() );
for (int i = 1; i < vertices.length; i++) {
pt = transform3D.objectToDrawingCoords(vertices[i]);
path.lineTo( (float)pt.getX(), (float)pt.getY() );
}
path.closePath();
currentGraphics.fill(path);
if (outlineColor != null)
currentGraphics.setColor(outlineColor);
currentGraphics.draw(path);
currentGraphics.setColor(saveColor);
}
else {
setUpForLeftEye();
Color saveColor = currentGraphics.getColor();
GeneralPath path = new GeneralPath();
Point2D pt = transform3D.objectToDrawingCoords(vertices[0]);
path.moveTo( (float)pt.getX(), (float)pt.getY() );
for (int i = 1; i < vertices.length; i++) {
pt = transform3D.objectToDrawingCoords(vertices[i]);
path.lineTo( (float)pt.getX(), (float)pt.getY() );
}
path.closePath();
currentGraphics.fill(path);
if (outlineColor != null)
currentGraphics.setColor(outlineColor);
currentGraphics.draw(path);
currentGraphics.setColor(saveColor);
setUpForRightEye();
saveColor = currentGraphics.getColor();
path.reset();
pt = transform3D.objectToDrawingCoords(vertices[0]);
path.moveTo( (float)pt.getX(), (float)pt.getY() );
for (int i = 1; i < vertices.length; i++) {
pt = transform3D.objectToDrawingCoords(vertices[i]);
path.lineTo( (float)pt.getX(), (float)pt.getY() );
}
path.closePath();
currentGraphics.fill(path);
if (outlineColor != null)
currentGraphics.setColor(outlineColor);
currentGraphics.draw(path);
currentGraphics.setColor(saveColor);
finishStereoView();
}
}
// ------------------------- methods to support stereo rendering
/**
* To be used with the setUpForLeftEye and finishStereoView methods to support
* 3D rendering. When rendering in one of the three stereo view styles, the image needs to be rendered
* twice, once for the left eye and once for the right eye. The setUpForLeftEye methods
* should be called first; this sets up the transform and current graphics context for rendering from
* the viewpoint of the left eye into the left eye image. Next comes the code for drawing the object.
* then setUpForRightEye, followed by a repeat of the code for drawing the object.
* Finally, calling finshStereoView must be called to restore the original drawing
* context. These three methods must always be used in this way. Note that most programmers will not
* have to worry about this -- these methods will only be used when writing methods for rendering
* new graphics primitives such as lines and surfaces in this class and its subclasses.
*/
protected void setUpForLeftEye() {
double separationFactor;
if (viewStyle == View3D.CROSS_EYE_STEREO_VIEW)
separationFactor = 0.04;
else if (viewStyle == View3D.STEREOGRAPH_VIEW)
separationFactor = -0.03;
else
separationFactor = 0.03;
separationFactor *= eyeSeparationMultiplier;
transform3D.selectLeftEye(separationFactor);
saveGraphicsDuringStereo = currentGraphics;
saveUntransformedGraphicsDuringStereo = transform3D.getUntransformedGraphics();
Color color = saveGraphicsDuringStereo.getColor(); // copying color and stroke to left and right views, in case they were changed in currentGraphics
leftEyeGraphics.setColor(color);
rightEyeGraphics.setColor(color);
Stroke stroke = saveGraphicsDuringStereo.getStroke();
leftEyeGraphics.setStroke(stroke);
rightEyeGraphics.setStroke(stroke);
Font font = saveGraphicsDuringStereo.getFont();
leftEyeGraphics.setFont(font);
rightEyeGraphics.setFont(font);
transform3D.useGraphics(leftEyeGraphics,leftEyeUntransformedGraphics);
currentGraphics = leftEyeGraphics;
}
/**
* To be used with {@link #setUpForLeftEye()} and finishStereoView to support
* 3D rendering.
*/
protected void setUpForRightEye() {
double separationFactor;
if (viewStyle == View3D.CROSS_EYE_STEREO_VIEW)
separationFactor = 0.04;
else if (viewStyle == View3D.STEREOGRAPH_VIEW)
separationFactor = -0.03;
else
separationFactor = 0.03;
separationFactor *= eyeSeparationMultiplier;
transform3D.selectRightEye(separationFactor);
transform3D.useGraphics(rightEyeGraphics,rightEyeUntransformedGraphics);
currentGraphics = rightEyeGraphics;
}
/**
* To be used with {@link #setUpForLeftEye()} and {@link #setUpForRightEye()} to support
* 3D rendering.
*/
protected void finishStereoView() {
transform3D.selectNoEye();
transform3D.useGraphics(saveGraphicsDuringStereo,saveUntransformedGraphicsDuringStereo);
currentGraphics = saveGraphicsDuringStereo;
saveGraphicsDuringStereo = null;
saveUntransformedGraphicsDuringStereo = null;
}
// ----------- Helper stuff for 3D rendering -----------------------------
private class CurveSegment extends Line2D.Double implements Comparable {
Vector3D v1, v2;
double midpoint_z;
CurveSegment(Vector3D v1, Vector3D v2) {
this.v1 = v1;
this.v2 = v2;
midpoint_z = (v1.z + v2.z)/2;
Point2D p1 = new Point2D.Double(v1.x, v1.y);
Point2D p2 = new Point2D.Double(v2.x, v2.y);
if (!transform3D.appliedTransform2D()) {
transform3D.windowToViewport(p1);
transform3D.windowToViewport(p2);
}
setLine(p1,p2);
}
public int compareTo(CurveSegment c) {
if (midpoint_z < c.midpoint_z)
return -1;
else if (midpoint_z > c.midpoint_z)
return 1;
else
return 0;
}
}
private void drawCollaredCurveDirect(Vector3D[] points, int startIndex, int endIndex, boolean reversed) {
Vector3D p1 = points[startIndex]==null? null : transform3D.objectToViewCoords(points[startIndex]);
ArrayList segments = new ArrayList();
for (int i = startIndex + 1; i <= endIndex; i++) {
Vector3D p2 = points[i]==null || clip(points[i])? null : transform3D.objectToViewCoords(points[i]);
if (p1 != null && p2 != null)
segments.add(new CurveSegment(p1,p2));
p1 = p2;
}
java.util.Collections.sort(segments);
Color saveColor = currentGraphics.getColor();
Stroke saveStroke = currentGraphics.getStroke();
Stroke wideStroke = new BasicStroke(transform3D.getDefaultStrokeSize() * 5, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
Stroke normalStroke = new BasicStroke(transform3D.getDefaultStrokeSize(), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
for (int i = 0; i < segments.size(); i++) {
currentGraphics.setStroke(wideStroke);
currentGraphics.setColor(reversed ? saveColor : currentGraphics.getBackground());
currentGraphics.draw(segments.get(i));
currentGraphics.setStroke(normalStroke);
currentGraphics.setColor(reversed ? currentGraphics.getBackground() : saveColor);
currentGraphics.draw(segments.get(i));
}
currentGraphics.setColor(saveColor);
currentGraphics.setStroke(saveStroke);
}
/**
* This method is used to test whether a point should be clipped. It is valid
* only during a 3D rendering operation. It is needed in {@link Grid3D} and in
* {@link vmm.polyhedron.IFS}.
*/
final public boolean clip(Vector3D objectPoint) {
return objectPoint.dot(viewDirection) > clipZ;
}
}