Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
javax.media.j3d.Renderer Maven / Gradle / Ivy
/*
* 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.
*
*/
/*
* Portions of this code were derived from work done by the Blackdown
* group (www.blackdown.org), who did the initial Linux implementation
* of the Java 3D API.
*/
package javax.media.j3d;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.logging.Level;
class Renderer extends J3dThread {
// This action causes this thread to wait
static final int WAIT = 0;
// This action causes this thread to notify the view, and then wait.
static final int NOTIFY_AND_WAIT = 1;
// This action causes this thread to be notified
static final int NOTIFY = 2;
// The following are DecalGroup rendering states
static final int DECAL_NONE = 0;
static final int DECAL_1ST_CHILD = 1;
static final int DECAL_NTH_CHILD = 2;
// stuff for scene antialiasing
static final int NUM_ACCUMULATION_SAMPLES = 8;
static final float ACCUM_SAMPLES_X[] =
{ -0.54818f, 0.56438f, 0.39462f, -0.54498f,
-0.83790f, -0.39263f, 0.32254f, 0.84216f};
static final float ACCUM_SAMPLES_Y[] =
{ 0.55331f, -0.53495f, 0.41540f, -0.52829f,
0.82102f, -0.27383f, 0.09133f, -0.84399f};
static final float accumValue = 1.0f / NUM_ACCUMULATION_SAMPLES;
// The following are Render arguments
static final int RENDER = 0;
static final int SWAP = 1;
static final int REQUESTRENDER = 2;
static final int REQUESTCLEANUP = 3;
// Renderer Structure used for the messaging to the renderer
RendererStructure rendererStructure = new RendererStructure();
// vworldtoVpc matrix for background geometry
Transform3D bgVworldToVpc = new Transform3D();
private static int numInstances = 0;
private int instanceNum = -1;
// Local copy of sharedStereZBuffer flag
boolean sharedStereoZBuffer;
// This is the id for the underlying sharable graphics context
Context sharedCtx = null;
// since the sharedCtx id can be the same as the previous one,
// we need to keep a time stamp to differentiate the contexts with the
// same id
long sharedCtxTimeStamp = 0;
// display and drawable, used to free shared context
private Drawable sharedCtxDrawable = null;
/**
* This is the id of the current rendering context
*/
Context currentCtx = null;
/**
* This is the id of the current rendering drawable
*/
Drawable currentDrawable = null;
// an unique bit to identify this renderer
int rendererBit = 0;
// an unique number to identify this renderer : ( rendererBit = 1 << rendererId)
int rendererId = 0;
// List of renderMolecules that are dirty due to additions
// or removal of renderAtoms from their display list set
// of renderAtoms
ArrayList dirtyRenderMoleculeList = new ArrayList();
// List of individual dlists that need to be rebuilt
ArrayList dirtyRenderAtomList = new ArrayList();
// List of (Rm, rInfo) pair of individual dlists that need to be rebuilt
ArrayList dirtyDlistPerRinfoList = new ArrayList();
// Texture and display list that should be freed
ArrayList textureIdResourceFreeList = new ArrayList();
ArrayList displayListResourceFreeList = new ArrayList();
// Texture that should be reload
ArrayList textureReloadList = new ArrayList();
J3dMessage[] renderMessage;
// The screen for this Renderer. Note that this renderer may share
// by both on screen and off screen. When view unregister, we need
// to set both reference to null.
Screen3D onScreen;
Screen3D offScreen;
// full screen anti-aliasing projection matrices
Transform3D accumLeftProj = new Transform3D();
Transform3D accumRightProj = new Transform3D();
Transform3D accumInfLeftProj = new Transform3D();
Transform3D accumInfRightProj = new Transform3D();
// rendering messages
J3dMessage m[];
int nmesg = 0;
// List of contexts created
ArrayList listOfCtxs = new ArrayList();
// Parallel list of canvases
ArrayList listOfCanvases = new ArrayList();
boolean needToRebuildDisplayList = false;
// True when either one of dirtyRenderMoleculeList,
// dirtyDlistPerRinfoList, dirtyRenderAtomList size > 0
boolean dirtyDisplayList = false;
// Remember OGL context resources to free
// before context is destroy.
// It is used when sharedCtx = true;
ArrayList textureIDResourceTable = new ArrayList(5);
// Instrumentation of Java 3D renderer
private long lastSwapTime = System.nanoTime();
private synchronized int newInstanceNum() {
return (++numInstances);
}
@Override
int getInstanceNum() {
if (instanceNum == -1)
instanceNum = newInstanceNum();
return instanceNum;
}
/**
* Constructs a new Renderer
*/
Renderer(ThreadGroup t) {
super(t);
setName("J3D-Renderer-" + getInstanceNum());
type = J3dThread.RENDER_THREAD;
rendererId = VirtualUniverse.mc.getRendererId();
rendererBit = (1 << rendererId);
renderMessage = new J3dMessage[1];
}
/**
* The main loop for the renderer.
*/
@Override
void doWork(long referenceTime) {
RenderBin renderBin = null;
Canvas3D cv, canvas=null;
Object firstArg;
View view = null;
int stereo_mode;
int num_stereo_passes, num_accum_passes = 1;
int pass, apass, i, j;
boolean doAccum = false;
double accumDx = 0.0f, accumDy = 0.0f;
double accumDxFactor = 1.0f, accumDyFactor = 1.0f;
double accumLeftX = 0.0, accumLeftY = 0.0,
accumRightX = 0.0, accumRightY = 0.0,
accumInfLeftX = 0.0, accumInfLeftY = 0.0,
accumInfRightX = 0.0, accumInfRightY = 0.0;
int opArg;
Transform3D t3d = null;
opArg = ((Integer)args[0]).intValue();
try {
if (opArg == SWAP) {
Object [] swapArray = (Object[])args[2];
view = (View)args[3];
for (i=0; i 0;
c.userStencilAvailable =
(userOwnsStencil && (c.actualStencilSize > 0));
c.systemStencilAvailable =
(!userOwnsStencil && (c.actualStencilSize > 0));
c.sceneAntialiasingMultiSamplesAvailable =
c.hasSceneAntialiasingMultisample();
if (c.sceneAntialiasingMultiSamplesAvailable) {
c.sceneAntialiasingAvailable = true;
} else {
c.sceneAntialiasingAvailable =
c.hasSceneAntialiasingAccum();
}
} catch (RuntimeException ex) {
ex.printStackTrace();
// Issue 260 : indicate fatal error and notify error listeners
c.setFatalError();
RenderingError err =
new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR,
J3dI18N.getString("Renderer1"));
err.setCanvas3D(c);
err.setGraphicsDevice(c.graphicsConfiguration.getDevice());
notifyErrorListeners(err);
}
GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY);
} else if (reqType == MasterControl.SET_QUERYPROPERTIES){
try {
c.createQueryContext();
} catch (RuntimeException ex) {
ex.printStackTrace();
// Issue 260 : indicate fatal error and notify error listeners
c.setFatalError();
RenderingError err =
new RenderingError(RenderingError.CONTEXT_CREATION_ERROR,
J3dI18N.getString("Renderer2"));
err.setCanvas3D(c);
err.setGraphicsDevice(c.graphicsConfiguration.getDevice());
notifyErrorListeners(err);
}
// currentCtx change after we create a new context
GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY);
currentCtx = null;
currentDrawable = null;
}
} else if (secondArg instanceof Integer) {
// Issue 121 - This was formerly used as a message from
// the now-nonexistant TextureRetained finalize() method
// to free the texture id
throw new AssertionError();
} else if (secondArg instanceof GeometryArrayRetained) {
// message from GeometryArrayRetained
// clearLive() to free D3D array
//((GeometryArrayRetained) secondArg).freeD3DArray(false);
} else if (secondArg instanceof GraphicsConfigTemplate3D) {
GraphicsConfigTemplate3D gct =
(GraphicsConfigTemplate3D) secondArg;
Integer reqType = (Integer) m[nmesg].args[2];
if (reqType == MasterControl.GETBESTCONFIG) {
GraphicsConfiguration gcfg = null;
GraphicsConfiguration [] gcList = (GraphicsConfiguration []) gct.testCfg;
try {
gcfg = Pipeline.getPipeline().getBestConfiguration(gct, gcList);
} catch (NullPointerException npe) {
npe.printStackTrace();
} catch (RuntimeException ex) {
ex.printStackTrace();
// Issue 260 : notify error listeners
RenderingError err =
new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR,
J3dI18N.getString("Renderer3"));
err.setGraphicsDevice(gcList[0].getDevice());
notifyErrorListeners(err);
}
gct.testCfg = gcfg;
} else if (reqType == MasterControl.ISCONFIGSUPPORT) {
boolean rval = false;
GraphicsConfiguration gc = (GraphicsConfiguration) gct.testCfg;
try {
if (Pipeline.getPipeline().isGraphicsConfigSupported(gct, gc)) {
rval = true;
}
} catch (NullPointerException npe) {
npe.printStackTrace();
} catch (RuntimeException ex) {
ex.printStackTrace();
// Issue 260 : notify error listeners
RenderingError err =
new RenderingError(RenderingError.GRAPHICS_CONFIG_ERROR,
J3dI18N.getString("Renderer4"));
err.setGraphicsDevice(gc.getDevice());
notifyErrorListeners(err);
}
gct.testCfg = Boolean.valueOf(rval);
}
GraphicsConfigTemplate3D.runMonitor(J3dThread.NOTIFY);
}
m[nmesg++].decRefcount();
continue;
}
canvas = (Canvas3D) firstArg;
renderType = m[nmesg].type;
if (renderType == J3dMessage.CREATE_OFFSCREENBUFFER) {
// Fix for issue 18.
// Fix for issue 20.
canvas.drawable = null;
try {
// Issue 396. Pass in a null ctx for 2 reasons :
// 1) We should not use ctx field directly without buffering in a msg.
// 2) canvas.ctx should be null.
canvas.drawable =
canvas.createOffScreenBuffer(null,
canvas.offScreenCanvasSize.width,
canvas.offScreenCanvasSize.height);
} catch (RuntimeException ex) {
ex.printStackTrace();
}
if (canvas.drawable == null) {
// Issue 260 : indicate fatal error and notify error listeners
canvas.setFatalError();
RenderingError err =
new RenderingError(RenderingError.OFF_SCREEN_BUFFER_ERROR,
J3dI18N.getString("Renderer5"));
err.setCanvas3D(canvas);
err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice());
notifyErrorListeners(err);
}
canvas.offScreenBufferPending = false;
m[nmesg++].decRefcount();
continue;
}
else if (renderType == J3dMessage.DESTROY_CTX_AND_OFFSCREENBUFFER) {
Object[] obj = m[nmesg].args;
// Fix for issue 175: destroy ctx & off-screen buffer
// Fix for issue 340: get display, drawable & ctx from msg
removeCtx(canvas,
(Drawable) obj[2],
(Context) obj[3],
false, !canvas.offScreen, true);
canvas.offScreenBufferPending = false;
m[nmesg++].decRefcount();
continue;
} else if (renderType == J3dMessage.ALLOCATE_CANVASID) {
canvas.allocateCanvasId();
} else if (renderType == J3dMessage.FREE_CANVASID) {
canvas.freeCanvasId();
}
if ((canvas.view == null) || !canvas.firstPaintCalled) {
// This happen when the canvas just remove from the View
if (renderType == J3dMessage.RENDER_OFFSCREEN) {
canvas.offScreenRendering = false;
}
m[nmesg++].decRefcount();
continue;
}
if (!canvas.validCanvas &&
(renderType != J3dMessage.RENDER_OFFSCREEN)) {
m[nmesg++].decRefcount();
continue;
}
if (renderType == J3dMessage.RESIZE_CANVAS) {
// render the image again after resize
VirtualUniverse.mc.sendRunMessage(canvas.view, J3dThread.RENDER_THREAD);
m[nmesg++].decRefcount();
} else if (renderType == J3dMessage.TOGGLE_CANVAS) {
VirtualUniverse.mc.sendRunMessage(canvas.view, J3dThread.RENDER_THREAD);
m[nmesg++].decRefcount();
} else if (renderType == J3dMessage.RENDER_IMMEDIATE) {
int command = ((Integer)m[nmesg].args[1]).intValue();
//System.err.println("command= " + command);
if (canvas.isFatalError()) {
continue;
}
try {
switch (command) {
case GraphicsContext3D.CLEAR:
canvas.graphicsContext3D.doClear();
break;
case GraphicsContext3D.DRAW:
canvas.graphicsContext3D.doDraw(
(Geometry)m[nmesg].args[2]);
break;
case GraphicsContext3D.SWAP:
canvas.doSwap();
break;
case GraphicsContext3D.READ_RASTER:
canvas.graphicsContext3D.doReadRaster(
(Raster)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_APPEARANCE:
canvas.graphicsContext3D.doSetAppearance(
(Appearance)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_BACKGROUND:
canvas.graphicsContext3D.doSetBackground(
(Background)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_FOG:
canvas.graphicsContext3D.doSetFog(
(Fog)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_LIGHT:
canvas.graphicsContext3D.doSetLight(
(Light)m[nmesg].args[2],
((Integer)m[nmesg].args[3]).intValue());
break;
case GraphicsContext3D.INSERT_LIGHT:
canvas.graphicsContext3D.doInsertLight(
(Light)m[nmesg].args[2],
((Integer)m[nmesg].args[3]).intValue());
break;
case GraphicsContext3D.REMOVE_LIGHT:
canvas.graphicsContext3D.doRemoveLight(
((Integer)m[nmesg].args[2]).intValue());
break;
case GraphicsContext3D.ADD_LIGHT:
canvas.graphicsContext3D.doAddLight(
(Light)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_HI_RES:
canvas.graphicsContext3D.doSetHiRes(
(HiResCoord)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_MODEL_TRANSFORM:
t3d = (Transform3D)m[nmesg].args[2];
canvas.graphicsContext3D.doSetModelTransform(t3d);
break;
case GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM:
t3d = (Transform3D)m[nmesg].args[2];
canvas.graphicsContext3D.doMultiplyModelTransform(t3d);
break;
case GraphicsContext3D.SET_SOUND:
canvas.graphicsContext3D.doSetSound(
(Sound)m[nmesg].args[2],
((Integer)m[nmesg].args[3]).intValue());
break;
case GraphicsContext3D.INSERT_SOUND:
canvas.graphicsContext3D.doInsertSound(
(Sound)m[nmesg].args[2],
((Integer)m[nmesg].args[3]).intValue());
break;
case GraphicsContext3D.REMOVE_SOUND:
canvas.graphicsContext3D.doRemoveSound(
((Integer)m[nmesg].args[2]).intValue());
break;
case GraphicsContext3D.ADD_SOUND:
canvas.graphicsContext3D.doAddSound(
(Sound)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_AURAL_ATTRIBUTES:
canvas.graphicsContext3D.doSetAuralAttributes(
(AuralAttributes)m[nmesg].args[2]);
break;
case GraphicsContext3D.SET_BUFFER_OVERRIDE:
canvas.graphicsContext3D.doSetBufferOverride(
((Boolean)m[nmesg].args[2]).booleanValue());
break;
case GraphicsContext3D.SET_FRONT_BUFFER_RENDERING:
canvas.graphicsContext3D.doSetFrontBufferRendering(
((Boolean)m[nmesg].args[2]).booleanValue());
break;
case GraphicsContext3D.SET_STEREO_MODE:
canvas.graphicsContext3D.doSetStereoMode(
((Integer)m[nmesg].args[2]).intValue());
break;
case GraphicsContext3D.FLUSH:
canvas.graphicsContext3D.doFlush(
((Boolean)m[nmesg].args[2]).booleanValue());
break;
case GraphicsContext3D.FLUSH2D:
canvas.graphics2D.doFlush();
break;
case GraphicsContext3D.DRAWANDFLUSH2D:
Object ar[] = m[nmesg].args;
canvas.graphics2D.doDrawAndFlushImage(
(BufferedImage) ar[2],
((Point) ar[3]).x,
((Point) ar[3]).y,
(ImageObserver) ar[4]);
break;
case GraphicsContext3D.DISPOSE2D:
// Issue 583 - the graphics2D field may be null here
if (canvas.graphics2D != null) {
canvas.graphics2D.doDispose();
}
break;
case GraphicsContext3D.SET_MODELCLIP:
canvas.graphicsContext3D.doSetModelClip(
(ModelClip)m[nmesg].args[2]);
break;
default:
break;
}
} catch (RuntimeException ex) {
ex.printStackTrace();
// Issue 260 : indicate fatal error and notify error listeners
canvas.setFatalError();
RenderingError err =
new RenderingError(RenderingError.CONTEXT_CREATION_ERROR,
J3dI18N.getString("Renderer6"));
err.setCanvas3D(canvas);
err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice());
notifyErrorListeners(err);
}
m[nmesg++].decRefcount();
} else { // retained mode rendering
long startRenderTime = 0L;
if (MasterControl.isStatsLoggable(Level.INFO)) {
// Instrumentation of Java 3D renderer
startRenderTime = System.nanoTime();
}
m[nmesg++].decRefcount();
if (canvas.isFatalError()) {
continue;
}
ImageComponent2DRetained offBufRetained = null;
if (renderType == J3dMessage.RENDER_OFFSCREEN) {
// Issue 131: set offScreenRendering flag here, since it
// otherwise won't be set for auto-off-screen rendering
// (which doesn't use renderOffScreenBuffer)
canvas.offScreenRendering = true;
if (canvas.drawable == null || !canvas.active) {
canvas.offScreenRendering = false;
continue;
} else {
offBufRetained = (ImageComponent2DRetained)
canvas.offScreenBuffer.retained;
if (offBufRetained.isByReference()) {
offBufRetained.geomLock.getLock();
}
offBufRetained.evaluateExtensions(canvas);
}
} else if (!canvas.active) {
continue;
}
// Issue 78 - need to get the drawingSurface info every
// frame; this is necessary since the HDC (window ID)
// on Windows can become invalidated without our
// being notified!
if (!canvas.offScreen) {
canvas.drawingSurfaceObject.getDrawingSurfaceObjectInfo();
}
renderBin = canvas.view.renderBin;
// setup rendering context
// We need to catch NullPointerException when the dsi
// gets yanked from us during a remove.
if (canvas.useSharedCtx) {
if (sharedCtx == null) {
sharedCtxDrawable = canvas.drawable;
// Always lock for context create
if (!canvas.drawingSurfaceObject.renderLock()) {
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
break doneRender;
}
synchronized (VirtualUniverse.mc.contextCreationLock) {
sharedCtx = null;
try {
sharedCtx = canvas.createNewContext(null, true);
} catch (RuntimeException ex) {
ex.printStackTrace();
}
if (sharedCtx == null) {
canvas.drawingSurfaceObject.unLock();
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
// Issue 260 : indicate fatal error and notify error listeners
canvas.setFatalError();
RenderingError err =
new RenderingError(RenderingError.CONTEXT_CREATION_ERROR,
J3dI18N.getString("Renderer7"));
err.setCanvas3D(canvas);
err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice());
notifyErrorListeners(err);
break doneRender;
}
sharedCtxTimeStamp =
VirtualUniverse.mc.getContextTimeStamp();
needToRebuildDisplayList = true;
}
canvas.drawingSurfaceObject.unLock();
}
}
if (canvas.ctx == null) {
// Always lock for context create
if (!canvas.drawingSurfaceObject.renderLock()) {
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
break doneRender;
}
synchronized (VirtualUniverse.mc.contextCreationLock) {
canvas.ctx = null;
try {
canvas.ctx = canvas.createNewContext(sharedCtx, false);
} catch (RuntimeException ex) {
ex.printStackTrace();
}
if (canvas.ctx == null) {
canvas.drawingSurfaceObject.unLock();
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
// Issue 260 : indicate fatal error and notify error listeners
canvas.setFatalError();
RenderingError err =
new RenderingError(RenderingError.CONTEXT_CREATION_ERROR,
J3dI18N.getString("Renderer7"));
err.setCanvas3D(canvas);
err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice());
notifyErrorListeners(err);
break doneRender;
}
if (canvas.graphics2D != null) {
canvas.graphics2D.init();
}
canvas.ctxTimeStamp =
VirtualUniverse.mc.getContextTimeStamp();
listOfCtxs.add(canvas.ctx);
listOfCanvases.add(canvas);
if (renderBin.nodeComponentList.size() > 0) {
for (i = 0; i < renderBin.nodeComponentList.size(); i++) {
NodeComponentRetained nc = (NodeComponentRetained)renderBin.nodeComponentList.get(i);
if(nc instanceof ImageComponentRetained) {
((ImageComponentRetained)nc).evaluateExtensions(canvas);
}
}
}
// enable separate specular color
canvas.enableSeparateSpecularColor();
}
// create the cache texture state in canvas
// for state download checking purpose
if (canvas.texUnitState == null) {
canvas.createTexUnitState();
}
canvas.resetImmediateRendering();
canvas.drawingSurfaceObject.contextValidated();
if (!canvas.useSharedCtx) {
canvas.needToRebuildDisplayList = true;
}
canvas.drawingSurfaceObject.unLock();
} else {
if (canvas.isRunning) {
canvas.makeCtxCurrent();
}
}
if (renderBin != null) {
if ((VirtualUniverse.mc.doDsiRenderLock) &&
(!canvas.drawingSurfaceObject.renderLock())) {
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
break doneRender;
}
// handle free resource
if (canvas.useSharedCtx) {
freeResourcesInFreeList(canvas);
} else {
canvas.freeResourcesInFreeList(canvas.ctx);
}
if (VirtualUniverse.mc.doDsiRenderLock) {
canvas.drawingSurfaceObject.unLock();
}
// Issue 109 : removed copyOfCvCache now that we have
// a separate canvasViewCache for computing view frustum
CanvasViewCache cvCache = canvas.canvasViewCache;
// Deadlock if we include updateViewCache in
// drawingSurfaceObject sync.
canvas.updateViewCache(false, null, null,
renderBin.geometryBackground != null);
if ((VirtualUniverse.mc.doDsiRenderLock) &&
(!canvas.drawingSurfaceObject.renderLock())) {
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
break doneRender;
}
int cvWidth = cvCache.getCanvasWidth();
int cvHeight = cvCache.getCanvasHeight();
// setup viewport
canvas.setViewport(canvas.ctx, 0, 0, cvWidth, cvHeight);
// rebuild the display list of all dirty renderMolecules.
if (canvas.useSharedCtx) {
if (needToRebuildDisplayList) {
renderBin.updateAllRenderMolecule(
this, canvas);
needToRebuildDisplayList = false;
}
if (dirtyDisplayList) {
renderBin.updateDirtyDisplayLists(canvas,
dirtyRenderMoleculeList,
dirtyDlistPerRinfoList,
dirtyRenderAtomList,true);
dirtyDisplayList = false;
}
// for shared context, download textures upfront
// to minimize the context switching overhead
int sz = textureReloadList.size();
if (sz > 0) {
for (j = sz-1; j>=0; j--) {
textureReloadList.get(j).reloadTextureSharedContext(canvas);
}
textureReloadList.clear();
}
} else {
// update each canvas
if (canvas.needToRebuildDisplayList) {
renderBin.updateAllRenderMolecule(canvas);
canvas.needToRebuildDisplayList = false;
}
if (canvas.dirtyDisplayList) {
renderBin.updateDirtyDisplayLists(canvas,
canvas.dirtyRenderMoleculeList,
canvas.dirtyDlistPerRinfoList,
canvas.dirtyRenderAtomList, false);
canvas.dirtyDisplayList = false;
}
}
// lighting setup
if (canvas.view.localEyeLightingEnable !=
canvas.ctxEyeLightingEnable) {
canvas.ctxUpdateEyeLightingEnable(canvas.ctx,
canvas.view.localEyeLightingEnable);
canvas.ctxEyeLightingEnable =
canvas.view.localEyeLightingEnable;
}
// stereo setup
boolean useStereo = cvCache.getUseStereo();
if (useStereo) {
num_stereo_passes = 2;
stereo_mode = Canvas3D.FIELD_LEFT;
sharedStereoZBuffer =
VirtualUniverse.mc.sharedStereoZBuffer;
} else {
num_stereo_passes = 1;
stereo_mode = Canvas3D.FIELD_ALL;
// just in case user set flag -
// disable since we are not in stereo
sharedStereoZBuffer = false;
}
// full screen anti-aliasing setup
if (canvas.view.getSceneAntialiasingEnable() &&
canvas.sceneAntialiasingAvailable) {
if (((canvas.extensionsSupported & Canvas3D.MULTISAMPLE) == 0) ||
!canvas.sceneAntialiasingMultiSamplesAvailable) {
doAccum = true;
num_accum_passes = NUM_ACCUMULATION_SAMPLES;
System.arraycopy(
cvCache.getLeftProjection().mat,
0, accumLeftProj.mat, 0, 16);
accumDxFactor = (
canvas.canvasViewCache.getPhysicalWindowWidth() /
canvas.canvasViewCache.getCanvasWidth())*canvas.view.fieldOfView;
accumDyFactor = (
canvas.canvasViewCache.getPhysicalWindowHeight() /
canvas.canvasViewCache.getCanvasHeight())*canvas.view.fieldOfView;
accumLeftX = accumLeftProj.mat[3];
accumLeftY = accumLeftProj.mat[7];
if (useStereo) {
System.arraycopy(
cvCache.getRightProjection().mat,
0, accumRightProj.mat, 0, 16);
accumRightX = accumRightProj.mat[3];
accumRightY = accumRightProj.mat[7];
}
if (renderBin.geometryBackground != null) {
System.arraycopy(
cvCache.getInfLeftProjection().mat,
0, accumInfLeftProj.mat, 0, 16);
accumInfLeftX = accumInfLeftProj.mat[3];
accumInfLeftY = accumInfLeftProj.mat[7];
if (useStereo) {
System.arraycopy(
cvCache.getInfRightProjection().mat,
0, accumInfRightProj.mat, 0, 16);
accumInfRightX = accumInfRightProj.mat[3];
accumInfRightY = accumInfRightProj.mat[7];
}
}
} else {
if (!canvas.isAntialiasingSet()) {
// System.err.println("Renderer : Enable FullSceneAntialiasing");
canvas.setFullSceneAntialiasing(canvas.ctx, true);
}
}
} else {
if (canvas.isAntialiasingSet()) {
// System.err.println("Renderer : Disable SceneAntialiasing");
canvas.setFullSceneAntialiasing(canvas.ctx, false);
}
}
// background geometry setup
if (renderBin.geometryBackground != null) {
renderBin.updateInfVworldToVpc();
}
// setup default render mode - render to both eyes
canvas.setRenderMode(canvas.ctx,
Canvas3D.FIELD_ALL,
canvas.useDoubleBuffer);
// clear background if not full screen antialiasing
// and not in stereo mode
if (!doAccum && !sharedStereoZBuffer) {
BackgroundRetained bg = renderBin.background;
canvas.clear(bg, cvWidth, cvHeight);
}
// handle preRender callback
if (VirtualUniverse.mc.doDsiRenderLock) {
canvas.drawingSurfaceObject.unLock();
}
canvas.view.inCanvasCallback = true;
try {
canvas.preRender();
} catch (RuntimeException e) {
System.err.println("Exception occurred during Canvas3D callback:");
e.printStackTrace();
} catch (Error e) {
// Issue 264 - catch Error so Renderer doesn't die
System.err.println("Error occurred during Canvas3D callback:");
e.printStackTrace();
}
canvas.view.inCanvasCallback = false;
if ((VirtualUniverse.mc.doDsiRenderLock) &&
(!canvas.drawingSurfaceObject.renderLock())) {
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
break doneRender;
}
// render loop
for (pass = 0; pass < num_stereo_passes; pass++) {
if (doAccum) {
canvas.clearAccum(canvas.ctx);
}
canvas.setRenderMode(canvas.ctx, stereo_mode,
canvas.useDoubleBuffer);
for (apass = 0; apass < num_accum_passes; apass++) {
// jitter projection matrix and clear background
// for full screen anti-aliasing rendering
if (doAccum) {
accumDx = ACCUM_SAMPLES_X[apass] *
accumDxFactor;
accumDy = ACCUM_SAMPLES_Y[apass] *
accumDyFactor;
accumLeftProj.mat[3] = accumLeftX +
accumLeftProj.mat[0] * accumDx +
accumLeftProj.mat[1] * accumDy;
accumLeftProj.mat[7] = accumLeftY +
accumLeftProj.mat[4] * accumDx +
accumLeftProj.mat[5] * accumDy;
if (useStereo) {
accumRightProj.mat[3] = accumRightX +
accumRightProj.mat[0] * accumDx +
accumRightProj.mat[1] * accumDy;
accumRightProj.mat[7] = accumRightY +
accumRightProj.mat[4] * accumDx +
accumRightProj.mat[5] * accumDy;
}
if (renderBin.geometryBackground != null) {
accumInfLeftProj.mat[3] = accumInfLeftX +
accumInfLeftProj.mat[0] * accumDx +
accumInfLeftProj.mat[1] * accumDy;
accumInfLeftProj.mat[7] = accumInfLeftY +
accumInfLeftProj.mat[4] * accumDx +
accumInfLeftProj.mat[5] * accumDy;
if (useStereo) {
accumInfRightProj.mat[3] =
accumInfRightX +
accumInfRightProj.mat[0] * accumDx +
accumInfRightProj.mat[1] * accumDy;
accumInfRightProj.mat[7] =
accumInfRightY +
accumInfRightProj.mat[4] * accumDx +
accumInfRightProj.mat[5] * accumDy;
}
}
}
// clear background for stereo and
// accumulation buffer cases
if (doAccum || sharedStereoZBuffer) {
BackgroundRetained bg = renderBin.background;
canvas.clear(bg, cvWidth, cvHeight);
}
// render background geometry
if (renderBin.geometryBackground != null) {
// setup rendering matrices
if (pass == 0) {
canvas.vpcToEc =
cvCache.getInfLeftVpcToEc();
if (doAccum) {
canvas.setProjectionMatrix(
canvas.ctx, accumInfLeftProj);
} else {
canvas.setProjectionMatrix(
canvas.ctx,
cvCache.getInfLeftProjection());
}
} else {
canvas.vpcToEc =
cvCache.getInfRightVpcToEc();
if (doAccum) {
canvas.setProjectionMatrix(
canvas.ctx, accumInfRightProj);
} else {
canvas.setProjectionMatrix(
canvas.ctx,
cvCache.getInfRightProjection());
}
}
canvas.vworldToEc.mul(canvas.vpcToEc,
cvCache.getInfVworldToVpc());
// render background geometry
renderBin.renderBackground(canvas);
}
// setup rendering matrices
if (pass == 0) {
canvas.vpcToEc = cvCache.getLeftVpcToEc();
if (doAccum) {
canvas.setProjectionMatrix(canvas.ctx, accumLeftProj);
} else {
canvas.setProjectionMatrix(canvas.ctx,
cvCache.getLeftProjection());
}
} else {
canvas.vpcToEc = cvCache.getRightVpcToEc();
if (doAccum) {
canvas.setProjectionMatrix(
canvas.ctx, accumRightProj);
} else {
canvas.setProjectionMatrix(canvas.ctx,
cvCache.getRightProjection());
}
}
canvas.vworldToEc.mul(canvas.vpcToEc,
cvCache.getVworldToVpc());
synchronized (cvCache) {
if (pass == 0) {
canvas.setFrustumPlanes(cvCache.getLeftFrustumPlanesInVworld());
} else {
canvas.setFrustumPlanes(cvCache.getRightFrustumPlanesInVworld());
}
}
// Force view matrix dirty for each eye.
if (useStereo) {
canvas.canvasDirty |= Canvas3D.VIEW_MATRIX_DIRTY;
}
// render opaque geometry
renderBin.renderOpaque(canvas);
// render ordered geometry
renderBin.renderOrdered(canvas);
// handle renderField callback
if (VirtualUniverse.mc.doDsiRenderLock) {
canvas.drawingSurfaceObject.unLock();
}
canvas.view.inCanvasCallback = true;
try {
canvas.renderField(stereo_mode);
} catch (RuntimeException e) {
System.err.println("Exception occurred during Canvas3D callback:");
e.printStackTrace();
} catch (Error e) {
// Issue 264 - catch Error so Renderer doesn't die
System.err.println("Error occurred during Canvas3D callback:");
e.printStackTrace();
}
canvas.view.inCanvasCallback = false;
if ((VirtualUniverse.mc.doDsiRenderLock) &&
(!canvas.drawingSurfaceObject.renderLock())) {
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.offScreenRendering = false;
break doneRender;
}
// render transparent geometry
renderBin.renderTransparent(canvas);
if (doAccum)
canvas.accum(canvas.ctx, accumValue);
}
if (doAccum)
canvas.accumReturn(canvas.ctx);
if (useStereo) {
stereo_mode = Canvas3D.FIELD_RIGHT;
canvas.rightStereoPass = true;
}
}
canvas.imageReady = true;
canvas.rightStereoPass = false;
// reset renderMode
canvas.setRenderMode(canvas.ctx,
Canvas3D.FIELD_ALL,
canvas.useDoubleBuffer);
// handle postRender callback
if (VirtualUniverse.mc.doDsiRenderLock) {
canvas.drawingSurfaceObject.unLock();
}
canvas.view.inCanvasCallback = true;
try {
canvas.postRender();
} catch (RuntimeException e) {
System.err.println("Exception occurred during Canvas3D callback:");
e.printStackTrace();
} catch (Error e) {
// Issue 264 - catch Error so Renderer doesn't die
System.err.println("Error occurred during Canvas3D callback:");
e.printStackTrace();
}
canvas.view.inCanvasCallback = false;
// end offscreen rendering
if (canvas.offScreenRendering) {
canvas.syncRender(canvas.ctx, true);
canvas.endOffScreenRendering();
canvas.offScreenRendering = false;
// Issue 489 - don't call postSwap here for auto-offscreen,
// since it will be called later by the SWAP operation
if (canvas.manualRendering) {
// do the postSwap for offscreen here
canvas.view.inCanvasCallback = true;
try {
canvas.postSwap();
} catch (RuntimeException e) {
System.err.println("Exception occurred during Canvas 3D callback:");
e.printStackTrace();
} catch (Error e) {
// Issue 264 - catch Error so Renderer doesn't die
System.err.println("Error occurred during Canvas3D callback:");
e.printStackTrace();
}
if (offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
canvas.view.inCanvasCallback = false;
canvas.releaseCtx();
}
}
if (MasterControl.isStatsLoggable(Level.INFO)) {
// Instrumentation of Java 3D renderer
long deltaTime = System.nanoTime() - startRenderTime;
VirtualUniverse.mc.recordTime(MasterControl.TimeType.RENDER, deltaTime);
}
} else { // if (renderBin != null)
if ((offBufRetained != null) &&
offBufRetained.isByReference()) {
offBufRetained.geomLock.unLock();
}
}
}
}
// clear array to prevent memory leaks
if (opArg == RENDER) {
m[0] = null;
} else {
Arrays.fill(m, 0, totalMessages, null);
}
}
} catch (NullPointerException ne) {
// Print NPE, but otherwise ignore it
ne.printStackTrace();
if (canvas != null) {
// drawingSurfaceObject will safely ignore
// this request if this is not lock before
canvas.drawingSurfaceObject.unLock();
}
} catch (RuntimeException ex) {
ex.printStackTrace();
if (canvas != null) {
// drawingSurfaceObject will safely ignore
// this request if this is not lock before
canvas.drawingSurfaceObject.unLock();
}
// Issue 260 : indicate fatal error and notify error listeners
canvas.setFatalError();
RenderingError err =
new RenderingError(RenderingError.UNEXPECTED_RENDERING_ERROR,
J3dI18N.getString("Renderer8"));
err.setCanvas3D(canvas);
err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice());
notifyErrorListeners(err);
}
}
// resource clean up
@Override
void shutdown() {
removeAllCtxs();
}
@Override
void cleanup() {
super.cleanup();
renderMessage = new J3dMessage[1];
rendererStructure = new RendererStructure();
bgVworldToVpc = new Transform3D();
sharedCtx = null;
sharedCtxTimeStamp = 0;
sharedCtxDrawable = null;
dirtyRenderMoleculeList.clear();
dirtyRenderAtomList.clear();
dirtyDlistPerRinfoList.clear();
textureIdResourceFreeList.clear();
displayListResourceFreeList.clear();
onScreen = null;
offScreen = null;
m = null;
nmesg = 0;
}
// This is only invoked from removeCtx()/removeAllCtxs()
// with drawingSurface already lock
final void makeCtxCurrent(Context sharedCtx, Drawable drawable) {
if (sharedCtx != currentCtx || drawable != currentDrawable) {
Canvas3D.useCtx(sharedCtx, drawable);
/*
if(!Canvas3D.useCtx(sharedCtx, display, drawable)) {
Thread.dumpStack();
System.err.println("useCtx Fail");
}
*/
currentCtx = sharedCtx;
currentDrawable = drawable;
}
}
// No need to free graphics2d and background if it is from
// Canvas3D postRequest() offScreen rendering since the
// user thread will not wait for it. Also we can just
// reuse it as Canvas3D did not destroy.
private void removeCtx(Canvas3D cv, Drawable drawable, Context ctx,
boolean resetCtx, boolean freeBackground,
boolean destroyOffScreenBuffer) {
synchronized (VirtualUniverse.mc.contextCreationLock) {
if (ctx != null) {
int idx = listOfCtxs.indexOf(ctx);
if (idx >= 0) {
listOfCtxs.remove(idx);
listOfCanvases.remove(idx);
// Issue 326 : don't check display variable here
if ((drawable != null) && cv.added) {
// cv.ctx may reset to -1 here so we
// always use the ctx pass in.
if (cv.drawingSurfaceObject.renderLock()) {
// if it is the last one, free shared resources
if (sharedCtx != null) {
if (listOfCtxs.isEmpty()) {
makeCtxCurrent(sharedCtx, sharedCtxDrawable);
freeResourcesInFreeList(null);
freeContextResources();
Canvas3D.destroyContext(sharedCtxDrawable, sharedCtx);
currentCtx = null;
currentDrawable = null;
} else {
freeResourcesInFreeList(cv);
}
cv.makeCtxCurrent(ctx, drawable);
} else {
cv.makeCtxCurrent(ctx, drawable);
cv.freeResourcesInFreeList(ctx);
}
cv.freeContextResources(this, freeBackground, ctx);
Canvas3D.destroyContext(drawable, ctx);
currentCtx = null;
currentDrawable = null;
cv.drawingSurfaceObject.unLock();
}
}
}
if (resetCtx) {
cv.ctx = null;
}
if ((sharedCtx != null) && listOfCtxs.isEmpty()) {
sharedCtx = null;
sharedCtxTimeStamp = 0;
}
cv.ctxTimeStamp = 0;
}
// Fix for issue 18.
// Since we are now the renderer thread,
// we can safely execute destroyOffScreenBuffer.
if(destroyOffScreenBuffer) {
cv.destroyOffScreenBuffer(ctx, drawable);
cv.offScreenBufferPending = false;
}
}
}
void removeAllCtxs() {
Canvas3D cv;
synchronized (VirtualUniverse.mc.contextCreationLock) {
for (int i=listOfCanvases.size()-1; i >=0; i--) {
cv = listOfCanvases.get(i);
if ((cv.screen != null) && (cv.ctx != null)) {
// Issue 326 : don't check display variable here
if ((cv.drawable != null) && cv.added) {
if (cv.drawingSurfaceObject.renderLock()) {
// We need to free sharedCtx resource
// first before last non-sharedCtx to
// workaround Nvidia driver bug under Linux
// that crash on freeTexture ID:4685156
if ((i == 0) && (sharedCtx != null)) {
makeCtxCurrent(sharedCtx, sharedCtxDrawable);
freeResourcesInFreeList(null);
freeContextResources();
Canvas3D.destroyContext(sharedCtxDrawable, sharedCtx);
currentCtx = null;
currentDrawable = null;
}
cv.makeCtxCurrent();
cv.freeResourcesInFreeList(cv.ctx);
cv.freeContextResources(this, true, cv.ctx);
Canvas3D.destroyContext(cv.drawable, cv.ctx);
currentCtx = null;
currentDrawable = null;
cv.drawingSurfaceObject.unLock();
}
}
}
cv.ctx = null;
cv.ctxTimeStamp = 0;
}
if (sharedCtx != null) {
sharedCtx = null;
sharedCtxTimeStamp = 0;
}
listOfCanvases.clear();
listOfCtxs.clear();
}
}
// handle free resource in the FreeList
void freeResourcesInFreeList(Canvas3D cv) {
Iterator it;
boolean isFreeTex = (textureIdResourceFreeList.size() > 0);
boolean isFreeDL = (displayListResourceFreeList.size() > 0);
int val;
if (isFreeTex || isFreeDL) {
if (cv != null) {
cv.makeCtxCurrent(sharedCtx);
}
if (isFreeDL) {
for (it = displayListResourceFreeList.iterator(); it.hasNext();) {
val = it.next().intValue();
if (val <= 0) {
continue;
}
Canvas3D.freeDisplayList(sharedCtx, val);
}
displayListResourceFreeList.clear();
}
if (isFreeTex) {
for (it = textureIdResourceFreeList.iterator(); it.hasNext();) {
val = it.next().intValue();
if (val <= 0) {
continue;
}
if (val >= textureIDResourceTable.size()) {
MasterControl.getCoreLogger().severe(
"Error in freeResourcesInFreeList : ResourceIDTableSize = " +
textureIDResourceTable.size() +
" val = " + val);
} else {
TextureRetained tex = textureIDResourceTable.get(val);
if (tex != null) {
synchronized (tex.resourceLock) {
tex.resourceCreationMask &= ~rendererBit;
if (tex.resourceCreationMask == 0) {
tex.freeTextureId(val);
}
}
}
textureIDResourceTable.set(val, null);
}
Canvas3D.freeTexture(sharedCtx, val);
}
textureIdResourceFreeList.clear();
}
if (cv != null) {
cv.makeCtxCurrent(cv.ctx);
}
}
}
final void addTextureResource(int id, TextureRetained obj) {
if (textureIDResourceTable.size() <= id) {
for (int i=textureIDResourceTable.size();
i < id; i++) {
textureIDResourceTable.add(null);
}
textureIDResourceTable.add(obj);
} else {
textureIDResourceTable.set(id, obj);
}
}
void freeContextResources() {
TextureRetained tex;
for (int id = textureIDResourceTable.size()-1; id >= 0; id--) {
tex = textureIDResourceTable.get(id);
if (tex == null) {
continue;
}
Canvas3D.freeTexture(sharedCtx, id);
synchronized (tex.resourceLock) {
tex.resourceCreationMask &= ~rendererBit;
if (tex.resourceCreationMask == 0) {
tex.freeTextureId(id);
}
}
}
textureIDResourceTable.clear();
// displayList is free in Canvas.freeContextResources()
}
/**
* Send a message to the notification thread, which will call the
* shader error listeners.
*/
static void notifyErrorListeners(RenderingError err) {
J3dNotification notification = new J3dNotification();
notification.type = J3dNotification.RENDERING_ERROR;
notification.universe = null;//cv.view.universe;
notification.args[0] = err;
VirtualUniverse.mc.sendNotification(notification);
}
// Default rendering error listener class
private static RenderingErrorListener defaultErrorListener = null;
synchronized static RenderingErrorListener getDefaultErrorListener() {
if (defaultErrorListener == null) {
defaultErrorListener = new DefaultErrorListener();
}
return defaultErrorListener;
}
static class DefaultErrorListener implements RenderingErrorListener {
@Override
public void errorOccurred(RenderingError error) {
System.err.println();
System.err.println("DefaultRenderingErrorListener.errorOccurred:");
error.printVerbose();
System.exit(1);
}
}
}