package org.dynmap.hdmap.renderer; import java.util.ArrayList; import java.util.BitSet; import java.util.List; import java.util.Map; import org.dynmap.renderer.CustomRenderer; import org.dynmap.renderer.MapDataContext; import org.dynmap.renderer.RenderPatch; import org.dynmap.renderer.RenderPatchFactory; public class StairBlockRenderer extends CustomRenderer { private static final int TEXTURE_SIDES = 0; private static final int TEXTURE_TOP = 1; private static final int TEXTURE_BOTTOM = 2; private static BitSet stair_ids = new BitSet(); // Array of meshes for normal steps - index = (data value & 7) private RenderPatch[][] stepmeshes = new RenderPatch[8][]; // Array of meshes for 3/4 steps - index = (data value & 7), with extra one clockwise from normal step private RenderPatch[][] step_3_4_meshes = new RenderPatch[8][]; // Array of meshes for 1/4 steps - index = (data value & 7), with clockwise quarter clopped from normal step private RenderPatch[][] step_1_4_meshes = new RenderPatch[8][]; private int textsetcnt = 0; private String textindex = null; private String[] tilefields = null; private String[] texturemap; @Override public boolean initializeRenderer(RenderPatchFactory rpf, int blkid, int blockdatamask, Map<String,String> custparm) { if(!super.initializeRenderer(rpf, blkid, blockdatamask, custparm)) return false; stair_ids.set(blkid); /* Mark block as a stair */ /* Build step meshes */ for(int i = 0; i < 8; i++) { stepmeshes[i] = buildStepMeshes(rpf, i); step_1_4_meshes[i] = buildCornerStepMeshes(rpf, i); step_3_4_meshes[i] = buildIntCornerStepMeshes(rpf, i); } textindex = custparm.get("textureindex"); if(textindex != null) { String cnt = custparm.get("texturecnt"); if(cnt != null) textsetcnt = Integer.parseInt(cnt); else textsetcnt = 16; tilefields = new String[] { textindex }; texturemap = new String[textsetcnt]; for (int i = 0; i < textsetcnt; i++) { texturemap[i] = custparm.get("textmap" + i); if (texturemap[i] == null) { texturemap[i] = Integer.toString(i); } } } return true; } @Override public int getMaximumTextureCount() { if(textsetcnt == 0) return 3; else return textsetcnt; } @Override public String[] getTileEntityFieldsNeeded() { return tilefields; } private static final int[] patchlist = { TEXTURE_BOTTOM, TEXTURE_TOP, TEXTURE_SIDES, TEXTURE_SIDES, TEXTURE_SIDES, TEXTURE_SIDES }; private void addBox(RenderPatchFactory rpf, List<RenderPatch> list, double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) { addBox(rpf, list, xmin, xmax, ymin, ymax, zmin, zmax, patchlist); } private RenderPatch[] buildStepMeshes(RenderPatchFactory rpf, int dat) { ArrayList<RenderPatch> list = new ArrayList<RenderPatch>(); /* If inverted, add half top */ if((dat & 0x4) != 0) { addBox(rpf, list, 0, 1, 0.5, 1, 0, 1); } else { // Else, add half bottom addBox(rpf, list, 0, 1, 0.0, 0.5, 0, 1); } switch(dat & 0x3) { case 0: addBox(rpf, list, 0.5, 1, 0, 1, 0, 1); break; case 1: addBox(rpf, list, 0, 0.5, 0, 1, 0, 1); break; case 2: addBox(rpf, list, 0, 1, 0, 1, 0.5, 1); break; case 3: addBox(rpf, list, 0, 1, 0, 1, 0, 0.5); break; } return list.toArray(new RenderPatch[list.size()]); } private RenderPatch[] buildCornerStepMeshes(RenderPatchFactory rpf, int dat) { ArrayList<RenderPatch> list = new ArrayList<RenderPatch>(); /* If inverted, add half top */ if((dat & 0x4) != 0) { addBox(rpf, list, 0, 1, 0.5, 1, 0, 1); } else { // Else, add half bottom addBox(rpf, list, 0, 1, 0.0, 0.5, 0, 1); } switch(dat & 0x3) { case 0: addBox(rpf, list, 0.5, 1, 0, 1, 0, 0.5); break; case 1: addBox(rpf, list, 0, 0.5, 0, 1, 0, 0.5); break; case 2: addBox(rpf, list, 0, 0.5, 0, 1, 0.5, 1); break; case 3: addBox(rpf, list, 0.5, 1, 0, 1, 0.5, 1); break; } return list.toArray(new RenderPatch[list.size()]); } private RenderPatch[] buildIntCornerStepMeshes(RenderPatchFactory rpf, int dat) { ArrayList<RenderPatch> list = new ArrayList<RenderPatch>(); /* If inverted, add half top */ if((dat & 0x4) != 0) { addBox(rpf, list, 0, 1, 0.5, 1, 0, 1); } else { // Else, add half bottom addBox(rpf, list, 0, 1, 0.0, 0.5, 0, 1); } switch(dat & 0x3) { case 0: addBox(rpf, list, 0.5, 1, 0, 1, 0, 1); addBox(rpf, list, 0, 0.5, 0, 1, 0, 0.5); break; case 1: addBox(rpf, list, 0.5, 1, 0, 1, 0, 1); addBox(rpf, list, 0, 0.5, 0, 1, 0.5, 1); break; case 2: addBox(rpf, list, 0, 0.5, 0, 1, 0, 1); addBox(rpf, list, 0.5, 1, 0, 1, 0, 0.5); break; case 3: addBox(rpf, list, 0, 0.5, 0, 1, 0, 1); addBox(rpf, list, 0.5, 1, 0, 1, 0.5, 1); break; } return list.toArray(new RenderPatch[list.size()]); } // Steps // 0 = up to east // 1 = up to west // 2 = up to south // 3 = up to north // Corners // 0 = NE // 1 = NW // 2 = SW // 3 = SE // Interior Corners // 0 = open to SW // 1 = open to NW // 2 = open to SE // 3 = open to NE private static final int off_x[] = { 1, -1, 0, 0, 1, -1, 0, 0 }; private static final int off_z[] = { 0, 0, 1, -1, 0, 0, 1, -1 }; private static final int match1[] = { 2, 3, 0, 1, 6, 7, 4, 5 }; private static final int corner1[] = { 3, 1, 3, 1, 7, 5, 7, 5 }; private static final int icorner1[] = { 1, 2, 1, 2, 5, 6, 5, 6 }; private static final int match2[] = { 3, 2, 1, 0, 7, 6, 5, 4 }; private static final int corner2[] = { 0, 2, 2, 0, 4, 6, 6, 4 }; private static final int icorner2[] = { 0, 3, 3, 0, 4, 7, 7, 4 }; @Override public RenderPatch[] getRenderPatchList(MapDataContext ctx) { RenderPatch[] rp = getBaseRenderPatchList(ctx); if(textindex != null) { int idx = 0; Object o = ctx.getBlockTileEntityField(textindex); if(o instanceof Number) { idx = ((Number)o).intValue(); } else if (o instanceof String) { String os = (String) o; for (int i = 0; i < texturemap.length; i++) { if (os.equals(texturemap[i])) { idx = i; break; } } } if((idx < 0) || (idx >= textsetcnt)) { idx = 0; } RenderPatch[] rp2 = new RenderPatch[rp.length]; for(int i = 0; i < rp.length; i++) { rp2[i] = ctx.getPatchFactory().getRotatedPatch(rp[i], 0, 0, 0, idx); } return rp2; } else { return rp; } } private RenderPatch[] getBaseRenderPatchList(MapDataContext ctx) { int data = ctx.getBlockData() & 0x07; /* Get block data */ /* Check block behind stair */ int cornerid = ctx.getBlockTypeIDAt(off_x[data], 0, off_z[data]); if(stair_ids.get(cornerid)) { /* If it is a stair */ int cornerdat = ctx.getBlockDataAt(off_x[data], 0, off_z[data]); if(cornerdat == match1[data]) { /* If right orientation */ /* Make sure we don't have matching stair to side */ int sideid = ctx.getBlockTypeIDAt(-off_x[cornerdat], 0, -off_z[cornerdat]); if((!stair_ids.get(sideid)) || (ctx.getBlockDataAt(-off_x[cornerdat], 0, -off_z[cornerdat]) != data)) { return step_1_4_meshes[corner1[data]]; } } else if(cornerdat == match2[data]) { /* If other orientation */ /* Make sure we don't have matching stair to side */ int sideid = ctx.getBlockTypeIDAt(-off_x[cornerdat], 0, -off_z[cornerdat]); if((!stair_ids.get(sideid)) || (ctx.getBlockDataAt(-off_x[cornerdat], 0, -off_z[cornerdat]) != data)) { return step_1_4_meshes[corner2[data]]; } } } /* Check block in front of stair */ cornerid = ctx.getBlockTypeIDAt(-off_x[data], 0, -off_z[data]); if(stair_ids.get(cornerid)) { /* If it is a stair */ int cornerdat = ctx.getBlockDataAt(-off_x[data], 0, -off_z[data]); if(cornerdat == match1[data]) { /* If right orientation */ /* Make sure we don't have matching stair to side */ int sideid = ctx.getBlockTypeIDAt(off_x[cornerdat], 0, off_z[cornerdat]); if((!stair_ids.get(sideid)) || (ctx.getBlockDataAt(off_x[cornerdat], 0, off_z[cornerdat]) != data)) { return step_3_4_meshes[icorner1[data]]; } } else if(cornerdat == match2[data]) { /* If other orientation */ /* Make sure we don't have matching stair to side */ int sideid = ctx.getBlockTypeIDAt(off_x[cornerdat], 0, off_z[cornerdat]); if((!stair_ids.get(sideid)) || (ctx.getBlockDataAt(off_x[cornerdat], 0, off_z[cornerdat]) != data)) { return step_3_4_meshes[icorner2[data]]; } } } return stepmeshes[data]; } }