dynmap/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/RotatedPatchRenderer.java

158 lines
6.2 KiB
Java

package org.dynmap.hdmap.renderer;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Map;
import org.dynmap.Log;
import org.dynmap.renderer.CustomRenderer;
import org.dynmap.renderer.MapDataContext;
import org.dynmap.renderer.RenderPatch;
import org.dynmap.renderer.RenderPatchFactory;
/**
* This renderer is used to define a model using a set of 1 or more patches (patch0=x, patch1=x - same syntax as patchblock),
* which can then be rotated based on an orientation mapping. This assumes the orientation is controlled by a numeric
* field - either the field in the block's TileEntity defined by the 'index' attribute value, or the block
* data/meta value (if index is not provided). The rotations are then defined by providing a 'rotN' attribute
* value (where N is the value of the rotation attribute that indicates the rotation is to be applied), with a value
* formatted as 'X/Y/Z' or as 'Y', where X=degrees counterclockwise around X axis, Y=degrees counterclockwise around Y axis,
* and Z=degrees counterclockwise around Z axis. Note: X/Y/Z rotations are always applied in the order X, then Y, then Z. If
* the rotation index value N does not match a corresponding 'rotN' setting, no rotation is assumed.
*/
public class RotatedPatchRenderer extends CustomRenderer {
// Default model
private RenderPatch[] basemodel;
// Models for rotation values
private RenderPatch[][] models;
// Highest texture index
private int maxTextureIndex = 0;
// Indexing attribute
private String idx_attrib = null;
private String[] tileEntityAttribs = null;
@Override
public boolean initializeRenderer(RenderPatchFactory rpf, String blkname, BitSet blockdatamask, Map<String,String> custparm) {
if(!super.initializeRenderer(rpf, blkname, blockdatamask, custparm))
return false;
ArrayList<RenderPatch> patches = new ArrayList<RenderPatch>();
ArrayList<int[]> rotations = new ArrayList<int[]>();
/* See if index attribute defined */
idx_attrib = custparm.get("index");
/* Now, traverse parameters */
for(String k : custparm.keySet()) {
String v = custparm.get(k);
/* If it is a patch definition */
if(k.startsWith("patch")) {
try {
int id = Integer.parseInt(k.substring(5));
RenderPatch p = rpf.getNamedPatch(custparm.get(k), id);
if(p == null) {
Log.warning("Invalid patch definition: " + v);
return false;
}
if(p.getTextureIndex() > maxTextureIndex) {
maxTextureIndex = p.getTextureIndex();
}
while(patches.size() <= id) {
patches.add(null);
}
patches.set(id, p);
} catch (NumberFormatException nfx) {
Log.warning("Invalid index for parameter: " + k);
return false;
}
}
/* If it is a rotation definition */
else if(k.startsWith("rot")) {
int id;
try {
id = Integer.parseInt(k.substring(3));
} catch (NumberFormatException nfx) {
Log.warning("Invalid index for parameter: " + k);
return false;
}
int[] rot = new int[3];
String[] rotvals = v.split("/");
try {
if(rotvals.length >= 3) {
rot[0] = Integer.parseInt(rotvals[0]);
rot[1] = Integer.parseInt(rotvals[1]);
rot[2] = Integer.parseInt(rotvals[2]);
}
else {
rot[1] = Integer.parseInt(rotvals[0]);
}
while(rotations.size() <= id) {
rotations.add(null);
}
rotations.set(id, rot);
} catch (NumberFormatException nfx) {
Log.warning("Invalid rotation value: " + v);
return false;
}
}
}
/* Remove missing patches */
for(int i = 0; i < patches.size(); i++) {
if(patches.get(i) == null) {
patches.remove(i);
i--;
}
}
/* Save patch list as base model */
basemodel = patches.toArray(new RenderPatch[patches.size()]);
/* Now build rotated models for all the defined rotations */
models = new RenderPatch[rotations.size()][];
for(int i = 0; i < rotations.size(); i++) {
int[] rots = rotations.get(i);
if (rots == null) continue; /* Skip default values */
models[i] = new RenderPatch[basemodel.length]; /* Build list of patches */
for(int j = 0; j < basemodel.length; j++) {
models[i][j] = rpf.getRotatedPatch(basemodel[j], rots[0], rots[1], rots[2], basemodel[j].getTextureIndex());
}
}
if(idx_attrib != null) {
tileEntityAttribs = new String[1];
tileEntityAttribs[0] = idx_attrib;
}
else {
tileEntityAttribs = null;
}
return true;
}
@Override
public int getMaximumTextureCount() {
return maxTextureIndex+1;
}
@Override
public String[] getTileEntityFieldsNeeded() {
return tileEntityAttribs;
}
@Override
public RenderPatch[] getRenderPatchList(MapDataContext ctx) {
int rotIdx = 0;
/* See if we have rotation index */
if(idx_attrib != null) {
Object idxv = ctx.getBlockTileEntityField(idx_attrib);
if(idxv instanceof Number) {
rotIdx = ((Number)idxv).intValue();
}
}
else { /* Else, use data if no index attribute */
rotIdx = ctx.getBlockType().stateIndex;
}
if((rotIdx >= 0) && (rotIdx < models.length) && (models[rotIdx] != null)) {
return models[rotIdx];
}
else {
return basemodel;
}
}
}