Split perspective state out, to let shaders better interact with it

This commit is contained in:
Mike Primm 2011-07-07 08:41:31 -05:00
parent 4f73d2cbd6
commit 56e5f6fbb3
4 changed files with 147 additions and 65 deletions

View File

@ -104,35 +104,34 @@ public class DefaultHDShader implements HDShader {
/** /**
* Reset renderer state for new ray * Reset renderer state for new ray
*/ */
public void reset(int x, int y, Vector3D raystart, double scale) { public void reset(HDPerspectiveState ps) {
color.setTransparent(); color.setTransparent();
if(daycolor != null) if(daycolor != null)
daycolor.setTransparent(); daycolor.setTransparent();
pixelodd = (x & 0x3) + (y<<1); pixelodd = (ps.getPixelX() & 0x3) + (ps.getPixelY()<<1);
} }
protected Color[] getBlockColors(int blocktype, int blockdata) { protected Color[] getBlockColors(int blocktype, int blockdata) {
if((blockdata != 0) && (colorScheme.datacolors[blocktype] != null)) if((blockdata != 0) && (colorScheme.datacolors[blocktype] != null))
return colorScheme.datacolors[blocktype][blockdata]; return colorScheme.datacolors[blocktype][blockdata];
else else
return colorScheme.colors[blocktype]; return colorScheme.colors[blocktype];
} }
/** /**
* Process next ray step - called for each block on route * Process next ray step - called for each block on route
* @param blocktype - block type of current block
* @param blockdata - data nibble of current block
* @param skylightlevel - sky light level of previous block (surface on current block)
* @param emittedlightlevel - emitted light level of previous block (surface on current block)
* @param laststep - direction of last step
* @return true if ray is done, false if ray needs to continue * @return true if ray is done, false if ray needs to continue
*/ */
public boolean processBlock(int blocktype, int blockdata, int skylightlevel, int emittedlightlevel, HDMap.BlockStep laststep) { public boolean processBlock(HDPerspectiveState ps) {
int blocktype = ps.getBlockTypeID();
if(blocktype == 0) if(blocktype == 0)
return false; return false;
Color[] colors = getBlockColors(blocktype, blockdata); Color[] colors = getBlockColors(blocktype, ps.getBlockData());
if (colors != null) { if (colors != null) {
int seq; int seq;
/* Figure out which color to use */ /* Figure out which color to use */
HDMap.BlockStep laststep = ps.getLastBlockStep();
if((laststep == BlockStep.X_PLUS) || (laststep == BlockStep.X_MINUS)) if((laststep == BlockStep.X_PLUS) || (laststep == BlockStep.X_MINUS))
seq = 1; seq = 1;
else if((laststep == BlockStep.Z_PLUS) || (laststep == BlockStep.Z_MINUS)) else if((laststep == BlockStep.Z_PLUS) || (laststep == BlockStep.Z_MINUS))
@ -147,11 +146,11 @@ public class DefaultHDShader implements HDShader {
/* Handle light level, if needed */ /* Handle light level, if needed */
int lightlevel = 15, lightlevel_day = 15; int lightlevel = 15, lightlevel_day = 15;
if(shadowscale != null) { if(shadowscale != null) {
lightlevel = lightlevel_day = skylightlevel; lightlevel = lightlevel_day = ps.getSkyLightLevel();
if(lightscale != null) if(lightscale != null)
lightlevel = lightscale[lightlevel]; lightlevel = lightscale[lightlevel];
if((lightlevel < 15) || (lightlevel_day < 15)) { if((lightlevel < 15) || (lightlevel_day < 15)) {
int emitted = emittedlightlevel; int emitted = ps.getEmittedLightLevel();
lightlevel = Math.max(emitted, lightlevel); lightlevel = Math.max(emitted, lightlevel);
lightlevel_day = Math.max(emitted, lightlevel_day); lightlevel_day = Math.max(emitted, lightlevel_day);
} }
@ -207,7 +206,7 @@ public class DefaultHDShader implements HDShader {
/** /**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete) * Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/ */
public void rayFinished() { public void rayFinished(HDPerspectiveState ps) {
} }
/** /**
* Get result color - get resulting color for ray * Get result color - get resulting color for ray

View File

@ -1,24 +1,17 @@
package org.dynmap.hdmap; package org.dynmap.hdmap;
import org.dynmap.DynmapWorld; import org.dynmap.DynmapWorld;
import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment;
import org.dynmap.Client; import org.dynmap.Client;
import org.dynmap.Color; import org.dynmap.Color;
import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode; import org.dynmap.ConfigurationNode;
import org.dynmap.DynmapChunk; import org.dynmap.DynmapChunk;
import org.dynmap.Log; import org.dynmap.Log;
@ -26,23 +19,15 @@ import org.dynmap.MapManager;
import org.dynmap.MapTile; import org.dynmap.MapTile;
import org.dynmap.MapType; import org.dynmap.MapType;
import org.dynmap.TileHashManager; import org.dynmap.TileHashManager;
import org.dynmap.MapType.MapStep;
import org.dynmap.debug.Debug; import org.dynmap.debug.Debug;
import org.dynmap.flat.FlatMap.FlatMapTile;
import org.dynmap.kzedmap.KzedMap.KzedBufferedImage; import org.dynmap.kzedmap.KzedMap.KzedBufferedImage;
import org.dynmap.kzedmap.KzedMap; import org.dynmap.kzedmap.KzedMap;
import org.dynmap.kzedmap.MapTileRenderer;
import org.dynmap.utils.FileLockManager; import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator; import org.dynmap.utils.MapIterator;
import org.dynmap.utils.Matrix3D; import org.dynmap.utils.Matrix3D;
import org.dynmap.utils.Vector3D; import org.dynmap.utils.Vector3D;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
public class HDMap extends MapType { public class HDMap extends MapType {
/* View angles */ /* View angles */
@ -88,6 +73,57 @@ public class HDMap extends MapType {
private boolean need_biomedata = false; private boolean need_biomedata = false;
private boolean need_rawbiomedata = false; private boolean need_rawbiomedata = false;
private class OurPerspectiveState implements HDPerspectiveState {
int skylightlevel = 15;
int emittedlightlevel = 0;
int blocktypeid = 0;
int blockdata = 0;
Vector3D top, bottom;
int px, py;
BlockStep laststep = BlockStep.Y_MINUS;
/**
* Get sky light level - only available if shader requested it
*/
public final int getSkyLightLevel() { return skylightlevel; }
/**
* Get emitted light level - only available if shader requested it
*/
public final int getEmittedLightLevel() { return emittedlightlevel; }
/**
* Get current block type ID
*/
public final int getBlockTypeID() { return blocktypeid; }
/**
* Get current block data
*/
public final int getBlockData() { return blockdata; }
/**
* Get direction of last block step
*/
public final BlockStep getLastBlockStep() { return laststep; }
/**
* Get perspective scale
*/
public final double getScale() { return scale; }
/**
* Get start of current ray, in world coordinates
*/
public final Vector3D getRayStart() { return top; }
/**
* Get end of current ray, in world coordinates
*/
public final Vector3D getRayEnd() { return bottom; }
/**
* Get pixel X coordinate
*/
public final int getPixelX() { return px; }
/**
* Get pixel Y coordinate
*/
public final int getPixelY() { return py; }
}
public HDMap(ConfigurationNode configuration) { public HDMap(ConfigurationNode configuration) {
azimuth = configuration.getDouble("azimuth", 135.0); /* Get azimuth (default to classic kzed POV */ azimuth = configuration.getDouble("azimuth", 135.0); /* Get azimuth (default to classic kzed POV */
inclination = configuration.getDouble("inclination", 60.0); inclination = configuration.getDouble("inclination", 60.0);
@ -345,6 +381,9 @@ public class HDMap extends MapType {
if(shaders[i].isSkyLightLevelNeeded()) if(shaders[i].isSkyLightLevelNeeded())
need_skylightlevel = true; need_skylightlevel = true;
} }
/* Create perspective state object */
OurPerspectiveState ps = new OurPerspectiveState();
/* Create buffered image for each */ /* Create buffered image for each */
KzedBufferedImage im[] = new KzedBufferedImage[shaders.length]; KzedBufferedImage im[] = new KzedBufferedImage[shaders.length];
KzedBufferedImage dayim[] = new KzedBufferedImage[shaders.length]; KzedBufferedImage dayim[] = new KzedBufferedImage[shaders.length];
@ -359,26 +398,28 @@ public class HDMap extends MapType {
} }
} }
Vector3D top = new Vector3D(); ps.top = new Vector3D();
Vector3D bottom = new Vector3D(); ps.bottom = new Vector3D();
double xbase = t.tx * tileWidth; double xbase = t.tx * tileWidth;
double ybase = t.ty * tileHeight; double ybase = t.ty * tileHeight;
boolean shaderdone[] = new boolean[shaders.length]; boolean shaderdone[] = new boolean[shaders.length];
boolean rendered[] = new boolean[shaders.length]; boolean rendered[] = new boolean[shaders.length];
for(int x = 0; x < tileWidth; x++) { for(int x = 0; x < tileWidth; x++) {
ps.px = x;
for(int y = 0; y < tileHeight; y++) { for(int y = 0; y < tileHeight; y++) {
top.x = bottom.x = xbase + x + 0.5; /* Start at center of pixel at Y=127.5, bottom at Y=-0.5 */ ps.top.x = ps.bottom.x = xbase + x + 0.5; /* Start at center of pixel at Y=127.5, bottom at Y=-0.5 */
top.y = bottom.y = ybase + y + 0.5; ps.top.y = ps.bottom.y = ybase + y + 0.5;
top.z = 127.5; bottom.z = -0.5; ps.top.z = 127.5; ps.bottom.z = -0.5;
map_to_world.transform(top); /* Transform to world coordinates */ map_to_world.transform(ps.top); /* Transform to world coordinates */
map_to_world.transform(bottom); map_to_world.transform(ps.bottom);
ps.py = y;
for(int i = 0; i < shaders.length; i++) { for(int i = 0; i < shaders.length; i++) {
shaderstate[i].reset(x, y, top, scale); shaderstate[i].reset(ps);
} }
raytrace(cache, mapiter, top, bottom, shaderstate, shaderdone); raytrace(cache, mapiter, ps, shaderstate, shaderdone);
for(int i = 0; i < shaders.length; i++) { for(int i = 0; i < shaders.length; i++) {
if(shaderdone[i] == false) { if(shaderdone[i] == false) {
shaderstate[i].rayFinished(); shaderstate[i].rayFinished(ps);
} }
else { else {
shaderdone[i] = false; shaderdone[i] = false;
@ -394,7 +435,7 @@ public class HDMap extends MapType {
} }
} }
boolean renderedone = false; boolean renderone = false;
/* Test to see if we're unchanged from older tile */ /* Test to see if we're unchanged from older tile */
TileHashManager hashman = MapManager.mapman.hashman; TileHashManager hashman = MapManager.mapman.hashman;
for(int i = 0; i < shaders.length; i++) { for(int i = 0; i < shaders.length; i++) {
@ -402,6 +443,7 @@ public class HDMap extends MapType {
boolean tile_update = false; boolean tile_update = false;
String shadername = shaders[i].getName(); String shadername = shaders[i].getName();
if(rendered[i]) { if(rendered[i]) {
renderone = true;
String fname = t.getFilename(shadername); String fname = t.getFilename(shadername);
File f = new File(t.getDynmapWorld().worldtilepath, fname); File f = new File(t.getDynmapWorld().worldtilepath, fname);
FileLockManager.getWriteLock(f); FileLockManager.getWriteLock(f);
@ -428,7 +470,6 @@ public class HDMap extends MapType {
} }
} finally { } finally {
FileLockManager.releaseWriteLock(f); FileLockManager.releaseWriteLock(f);
renderedone = true;
KzedMap.freeBufferedImage(im[i]); KzedMap.freeBufferedImage(im[i]);
} }
MapManager.mapman.updateStatistics(tile, shadername, true, tile_update, !rendered[i]); MapManager.mapman.updateStatistics(tile, shadername, true, tile_update, !rendered[i]);
@ -462,21 +503,22 @@ public class HDMap extends MapType {
} }
} finally { } finally {
FileLockManager.releaseWriteLock(f); FileLockManager.releaseWriteLock(f);
renderedone = true;
KzedMap.freeBufferedImage(dayim[i]); KzedMap.freeBufferedImage(dayim[i]);
} }
MapManager.mapman.updateStatistics(tile, shadername, true, tile_update, !rendered[i]); MapManager.mapman.updateStatistics(tile, shadername, true, tile_update, !rendered[i]);
} }
} }
} }
return renderedone; return renderone;
} }
/** /**
* Trace ray, based on "Voxel Tranversal along a 3D line" * Trace ray, based on "Voxel Tranversal along a 3D line"
*/ */
private void raytrace(MapChunkCache cache, MapIterator mapiter, Vector3D top, Vector3D bottom, private void raytrace(MapChunkCache cache, MapIterator mapiter, OurPerspectiveState ps,
HDShaderState[] shaderstate, boolean[] shaderdone) { HDShaderState[] shaderstate, boolean[] shaderdone) {
Vector3D top = ps.top;
Vector3D bottom = ps.bottom;
/* Compute total delta on each axis */ /* Compute total delta on each axis */
double dx = Math.abs(bottom.x - top.x); double dx = Math.abs(bottom.x - top.x);
double dy = Math.abs(bottom.y - top.y); double dy = Math.abs(bottom.y - top.y);
@ -548,18 +590,18 @@ public class HDMap extends MapType {
t_next_z = (top.z - Math.floor(top.z)) * dt_dz; t_next_z = (top.z - Math.floor(top.z)) * dt_dz;
} }
/* Walk through scene */ /* Walk through scene */
BlockStep laststep = BlockStep.Y_MINUS; /* Last step is down into map */ ps.laststep = BlockStep.Y_MINUS; /* Last step is down into map */
mapiter.initialize(x, y, z); mapiter.initialize(x, y, z);
int sky_lightlevel = 15; ps.skylightlevel = 15;
int emitted_lightlevel = 15; ps.emittedlightlevel = 0;
for (; n > 0; --n) { for (; n > 0; --n) {
int blocktype = mapiter.getBlockTypeID(); ps.blocktypeid = mapiter.getBlockTypeID();
if(blocktype != 0) { if(ps.blocktypeid != 0) {
int blockdata = mapiter.getBlockData(); ps.blockdata = mapiter.getBlockData();
boolean done = true; boolean done = true;
for(int i = 0; i < shaderstate.length; i++) { for(int i = 0; i < shaderstate.length; i++) {
if(!shaderdone[i]) if(!shaderdone[i])
shaderdone[i] = shaderstate[i].processBlock(blocktype, blockdata, sky_lightlevel, emitted_lightlevel, laststep); shaderdone[i] = shaderstate[i].processBlock(ps);
done = done && shaderdone[i]; done = done && shaderdone[i];
} }
/* If all are done, we're out */ /* If all are done, we're out */
@ -567,20 +609,20 @@ public class HDMap extends MapType {
return; return;
} }
if(need_skylightlevel) if(need_skylightlevel)
sky_lightlevel = mapiter.getBlockSkyLight(); ps.skylightlevel = mapiter.getBlockSkyLight();
if(need_emittedlightlevel) if(need_emittedlightlevel)
emitted_lightlevel = mapiter.getBlockEmittedLight(); ps.emittedlightlevel = mapiter.getBlockEmittedLight();
/* If X step is next best */ /* If X step is next best */
if((t_next_x <= t_next_y) && (t_next_x <= t_next_z)) { if((t_next_x <= t_next_y) && (t_next_x <= t_next_z)) {
x += x_inc; x += x_inc;
t = t_next_x; t = t_next_x;
t_next_x += dt_dx; t_next_x += dt_dx;
if(x_inc > 0) { if(x_inc > 0) {
laststep = BlockStep.X_PLUS; ps.laststep = BlockStep.X_PLUS;
mapiter.incrementX(); mapiter.incrementX();
} }
else { else {
laststep = BlockStep.X_MINUS; ps.laststep = BlockStep.X_MINUS;
mapiter.decrementX(); mapiter.decrementX();
} }
} }
@ -590,13 +632,13 @@ public class HDMap extends MapType {
t = t_next_y; t = t_next_y;
t_next_y += dt_dy; t_next_y += dt_dy;
if(y_inc > 0) { if(y_inc > 0) {
laststep = BlockStep.Y_PLUS; ps.laststep = BlockStep.Y_PLUS;
mapiter.incrementY(); mapiter.incrementY();
if(mapiter.getY() > 127) if(mapiter.getY() > 127)
return; return;
} }
else { else {
laststep = BlockStep.Y_MINUS; ps.laststep = BlockStep.Y_MINUS;
mapiter.decrementY(); mapiter.decrementY();
if(mapiter.getY() < 0) if(mapiter.getY() < 0)
return; return;
@ -608,11 +650,11 @@ public class HDMap extends MapType {
t = t_next_z; t = t_next_z;
t_next_z += dt_dz; t_next_z += dt_dz;
if(z_inc > 0) { if(z_inc > 0) {
laststep = BlockStep.Z_PLUS; ps.laststep = BlockStep.Z_PLUS;
mapiter.incrementZ(); mapiter.incrementZ();
} }
else { else {
laststep = BlockStep.Z_MINUS; ps.laststep = BlockStep.Z_MINUS;
mapiter.decrementZ(); mapiter.decrementZ();
} }
} }

View File

@ -0,0 +1,46 @@
package org.dynmap.hdmap;
import org.dynmap.utils.Vector3D;
public interface HDPerspectiveState {
/**
* Get sky light level - only available if shader requested it
*/
int getSkyLightLevel();
/**
* Get emitted light level - only available if shader requested it
*/
int getEmittedLightLevel();
/**
* Get current block type ID
*/
int getBlockTypeID();
/**
* Get current block data
*/
int getBlockData();
/**
* Get direction of last block step
*/
HDMap.BlockStep getLastBlockStep();
/**
* Get perspective scale
*/
double getScale();
/**
* Get start of current ray, in world coordinates
*/
Vector3D getRayStart();
/**
* Get end of current ray, in world coordinates
*/
Vector3D getRayEnd();
/**
* Get pixel X coordinate
*/
int getPixelX();
/**
* Get pixel Y coordinate
*/
int getPixelY();
}

View File

@ -11,21 +11,16 @@ public interface HDShaderState {
/** /**
* Reset renderer state for new ray - passes in pixel coordinate for ray * Reset renderer state for new ray - passes in pixel coordinate for ray
*/ */
void reset(int x, int y, Vector3D raystart, double scale); void reset(HDPerspectiveState ps);
/** /**
* Process next ray step - called for each block on route * Process next ray step - called for each block on route
* @param blocktype - block type of current block
* @param blockdata - data nibble of current block
* @param skylightlevel - sky light level of previous block (surface on current block)
* @param emittedlightlevel - emitted light level of previous block (surface on current block)
* @param laststep - direction of last step
* @return true if ray is done, false if ray needs to continue * @return true if ray is done, false if ray needs to continue
*/ */
boolean processBlock(int blocktype, int blockdata, int skylightlevel, int emittedlightlevel, HDMap.BlockStep laststep); boolean processBlock(HDPerspectiveState ps);
/** /**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete) * Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/ */
void rayFinished(); void rayFinished(HDPerspectiveState ps);
/** /**
* Get result color - get resulting color for ray * Get result color - get resulting color for ray
* @param c - object to store color value in * @param c - object to store color value in