Some time ago I've implemented tiled rendering to capture high resolution screenshot of WWJ scene. I had to set detail hints to TiledImageLayers and SurfaceObjectTileBuilder as following:
Code:
package com.transas.tvmap.ui.worldwind.tools;
import gov.nasa.worldwind.BasicSceneController;
import gov.nasa.worldwind.View;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.layers.Layer;
import gov.nasa.worldwind.layers.LayerList;
import gov.nasa.worldwind.layers.TiledImageLayer;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.SurfaceObjectTileBuilder;
import gov.nasa.worldwind.view.AdvOrbitView;
import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.media.opengl.GL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.opengl.util.TileRenderer;
import com.transas.tvmap.ui.worldwind.tools.ExportImageTool.CaptureResult;
public class ExportImageSceneController extends BasicSceneController {
private static final Log LOG = LogFactory.getLog(ExportImageSceneController.class);
private final ExportImageTool tool;
private final Rectangle imageSize;
private TileRenderer tileRenderer = null;
private List<File> tileFiles = new LinkedList<File>();
private int currentTile = 0;
private int framesPerTile = 0;
private CaptureResult captureResult = null;
ExportImageSceneController(ExportImageTool tool, Rectangle imageSize) {
this.tool = tool;
this.imageSize = imageSize;
}
public void doRepaint(DrawContext dc)
{
if (captureResult != null) {
super.doRepaint(dc);
return ;
}
this.initializeFrame(dc);
if (tileRenderer == null) {
this.applyView(dc);
tileRenderer = createTileRenderer(dc);
}
try {
GL gl = dc.getGL();
AdvOrbitView aView = null;
if (view instanceof AdvOrbitView) {
aView = (AdvOrbitView)view;
}
if (aView == null) {
LOG.error("Invalid View instance: " + aView);
tool.capturingCancelled();
return ;
}
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPushMatrix();
tileRenderer.beginTile(gl);
// now we need to read matrix and apply it to the view
aView.readProjection(gl);
gl.glPopMatrix();
this.applyView(dc);
Angle savedFov = aView.getFieldOfView();
aView.setFieldOfView(tileFov);
Map<TiledImageLayer, Double> savedDetailHints = setupTiledImageLayers(dc, tileRenderer);
try {
this.createTerrain(dc);
this.preRender(dc);
this.clearFrame(dc);
this.draw(dc);
} finally {
cleanupTiledImageLayers(dc, savedDetailHints);
aView.setFieldOfView(savedFov);
}
framesPerTile++;
boolean hasMore = true;
if (framesPerTile > 40) {
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPushMatrix();
hasMore = tileRenderer.endTile(gl);
gl.glPopMatrix();
framesPerTile = 0;
if (captureResult == null) {
saveTile(gl);
}
currentTile++;
}
if (hasMore) {
dc.setRedrawRequested(100);
} else {
if (captureResult == null) {
int cols = tileRenderer.getParam(TileRenderer.TR_COLUMNS);
int rows = tileRenderer.getParam(TileRenderer.TR_ROWS);
captureResult = new CaptureResult(cols, rows, tileFiles);
tool.capturingDone(captureResult);
}
}
} finally {
this.finalizeFrame(dc);
}
}
private void cleanupTiledImageLayers(DrawContext dc,
Map<TiledImageLayer, Double> savedDetailHints) {
for (TiledImageLayer til : savedDetailHints.keySet()) {
Double hint = savedDetailHints.get(til);
til.setDetailHint(hint);
}
}
/**
* Increase detail hint for TiledImageLayers
* @param dc
* @param tileRenderer
*/
private Map<TiledImageLayer, Double> setupTiledImageLayers(DrawContext dc,
TileRenderer tileRenderer) {
Map<TiledImageLayer, Double> saved = new HashMap<TiledImageLayer, Double>();
double zoom = (double)tileRenderer.getParam(TileRenderer.TR_IMAGE_WIDTH)
/(double)tileRenderer.getParam(TileRenderer.TR_TILE_WIDTH);
double scaleLog = Math.log10(zoom);
LayerList layers = dc.getModel().getLayers();
for (Layer l : layers) {
if (l instanceof TiledImageLayer) {
// XXX
TiledImageLayer til = (TiledImageLayer)l;
saved.put(til, til.getDetailHint());
til.setDetailHint(scaleLog);
}
}
return saved;
}
private void saveTile(GL gl) {
int[] viewport = new int[4];
gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
try {
String dirName = System.getProperty("java.io.tmpdir");
File screenFolder = new File(dirName, "TransasGlobe");
if (!screenFolder.exists()) {
screenFolder.mkdirs();
}
File tileFile =
new File(screenFolder, "screen_" + currentTile + ".png");
if (tileFile.exists()) {
tileFile.delete();
}
com.sun.opengl.util.Screenshot.writeToFile(
tileFile,
viewport[2], viewport[3], false);
tileFiles.add(tileFile);
} catch (IOException e) {
LOG.error("Failed ", e);
}
}
private Angle tileFov = null;
private TileRenderer createTileRenderer(DrawContext dc) {
Rectangle viewport = dc.getView().getViewport();
tileRenderer = new TileRenderer();
tileRenderer.setTileSize(viewport.width, viewport.height, 0);
// tileRenderer.setTileSize(512, 512, 0);
tileRenderer.setImageSize(imageSize.width, imageSize.height);
tileRenderer.setRowOrder(TileRenderer.TR_TOP_TO_BOTTOM);
View view = dc.getView();
Angle fov = view.getFieldOfView(); // horizontal fov
// XXX fov is different for each tile, should compute it from frustum
double scale = (double)tileRenderer.getParam(TileRenderer.TR_TILE_WIDTH)
/ (double)tileRenderer.getParam(TileRenderer.TR_IMAGE_WIDTH);
tileFov = fov.multiply(scale);
double near = view.getNearClipDistance();
double far = view.getFarClipDistance();
int w = viewport.width;
int h = viewport.height;
double fovy = (fov.degrees * h) / w;
tileRenderer.trPerspective(
fovy,
(float) imageSize.width / (float) imageSize.height,
near,
far);
return tileRenderer;
}
@Override
protected SurfaceObjectTileBuilder createSurfaceObjectTileBuilder()
{
SurfaceObjectTileBuilder tileBuilder = super.createSurfaceObjectTileBuilder();
double zoom = (double)tileRenderer.getParam(TileRenderer.TR_IMAGE_WIDTH)
/(double)tileRenderer.getParam(TileRenderer.TR_TILE_WIDTH);
double scaleLog = Math.log10(zoom);
tileBuilder.setSplitScale(tileBuilder.getSplitScale() + scaleLog);
return tileBuilder;
}
}