See More

package javaforce.gl.model; import java.io.*; import javaforce.*; import static javaforce.JSON.Element; import javaforce.gl.*; /** JSON Model reader. * * see https://minecraft.fandom.com/wiki/Tutorials/Models * * Notes: * - xyz coords and uv texture coords are based on pixels * * @author pquiring */ public class ModelJSON implements Model_IO { private static boolean debug = false; public float scale = 16.0f; private float tw, th; private float width, height, depth; private boolean mirror; public ModelJSON() { this.scale = 16f; } public ModelJSON(float scale) { this.scale = scale; } public Model load(String filename) { try { InputStream is = new FileInputStream(filename); Model model = load(is); is.close(); return model; } catch (Exception e) { e.printStackTrace(); return null; } } public Model load(InputStream is) { Model model = new Model(); int mapidx = 0; try { String json = new String(is.readAllBytes()); JSON.debug = debug; Element root = JSON.parse(json); if (debug) { root.print(); } for(Element child : root.children) { if (child.key.startsWith("geometry.")) { Element geo = child; //TODO : find entity based on name String ename = geo.key.substring(9); int idx = ename.indexOf('.'); if (idx != -1) { ename = ename.substring(0, idx); } Element etw = geo.getChild("texturewidth"); tw = getValue(etw.value); Element eth = geo.getChild("textureheight"); th = getValue(eth.value); Element bones = geo.getChild("bones"); for(Element box : bones.children) { Element name = box.getChild("name"); Element pvt = box.getChild("pivot"); float[] pvts = getValues(pvt); //Element rot = box.getChild("rotation"); //optional //float[] rots = getValues(rot); Element cubes = box.getChild("cubes"); if (cubes == null) continue; for(Element cube : cubes.children) { Element org = cube.getChild("origin"); //origin is lowest coord of cube in all 3 dims float[] orgs = getValues(org); Element size = cube.getChild("size"); float[] sizes = getValues(size); Element uv = cube.getChild("uv"); float[] uvs = getValues(uv); //text coords have 0,0 at top left corner float u = uvs[0]; float v = uvs[1]; Element _inflate = cube.getChild("inflate"); if (_inflate != null) { float inflate = getValue(_inflate.value) / scale; float inflate_2 = inflate * 2.0f; sizes[0] += inflate_2; sizes[1] += inflate_2; sizes[2] += inflate_2; orgs[0] -= inflate; orgs[1] -= inflate; orgs[2] -= inflate; } Element _mirror = cube.getChild("mirror"); mirror = _mirror != null && _mirror.value.equals("true"); float x = orgs[0]; float y = orgs[1]; float z = orgs[2]; width = sizes[0]; //x height = sizes[1]; //y depth = sizes[2]; //z { Object3 obj = new Object3(); obj.type = GL.GL_QUADS; UVMap map = obj.createUVMap(); map.name = "map-" + mapidx++; model.addObject(obj); //set origin (pivot) obj.org.x = pvts[0] / scale; obj.org.y = pvts[1] / scale; obj.org.z = pvts[2] / scale; obj.name = name.value; //each face starts at bottom left corner of texture //start @ origin (x,y,z) //uv starts high, bring down to first face (E) v += depth + height; //move to E x += width; z += depth; if (mirror) addFaceE(obj, x, y, z, u + depth + width, v); else addFaceE(obj, x, y, z, u, v); //move to N z -= depth; u += depth; addFaceN(obj, x, y, z, u, v); if (mirror) mirror(obj); //move to W x -= width; u += width; if (mirror) addFaceW(obj, x, y, z, u - depth - width, v); else addFaceW(obj, x, y, z, u, v); //move to S z += depth; u += depth; addFaceS(obj, x, y, z, u, v); if (mirror) mirror(obj); //move to B (two steps) v -= height; u -= depth; addFaceB(obj, x, y, z, u, v); if (mirror) mirror(obj); //move to A y += height; u -= width; addFaceA(obj, x, y, z, u, v); if (mirror) mirror(obj); } } } } } return model; } catch (Exception e) { JFLog.log(e); } return null; } private float[] xyz = new float[3]; private float[] uv = new float[2]; private int[] pts = new int[4]; private void addFaceW(Object3 obj, float x, float y, float z, float u, float v) { int vidx = obj.getVertexCount(); //add 4 vertex in CCW order starting at origin addVertex(obj, x, y, z, u, v); z += depth; u += depth; addVertex(obj, x, y, z, u, v); y += height; v -= height; addVertex(obj, x, y, z, u, v); z -= depth; u -= depth; addVertex(obj, x, y, z, u, v); for(int a=0;a<4;a++) { pts[a] = vidx++; } obj.addPoly(pts); } private void addFaceS(Object3 obj, float x, float y, float z, float u, float v) { int vidx = obj.getVertexCount(); //add 4 vertex in CCW order addVertex(obj, x, y, z, u, v); x += width; u += width; addVertex(obj, x, y, z, u, v); y += height; v -= height; addVertex(obj, x, y, z, u, v); x -= width; u -= width; addVertex(obj, x, y, z, u, v); for(int a=0;a<4;a++) { pts[a] = vidx++; } obj.addPoly(pts); } private void addFaceE(Object3 obj, float x, float y, float z, float u, float v) { int vidx = obj.getVertexCount(); //add 4 vertex in CCW order addVertex(obj, x, y, z, u, v); z -= depth; u += depth; addVertex(obj, x, y, z, u, v); y += height; v -= height; addVertex(obj, x, y, z, u, v); z += depth; u -= depth; addVertex(obj, x, y, z, u, v); for(int a=0;a<4;a++) { pts[a] = vidx++; } obj.addPoly(pts); } private void addFaceN(Object3 obj, float x, float y, float z, float u, float v) { int vidx = obj.getVertexCount(); //add 4 vertex in CCW order addVertex(obj, x, y, z, u, v); x -= width; u += width; addVertex(obj, x, y, z, u, v); y += height; v -= height; addVertex(obj, x, y, z, u, v); x += width; u -= width; addVertex(obj, x, y, z, u, v); for(int a=0;a<4;a++) { pts[a] = vidx++; } obj.addPoly(pts); } //TODO : not sure if this needs to be mirrored in the x axis private void addFaceB(Object3 obj, float x, float y, float z, float u, float v) { int vidx = obj.getVertexCount(); //add 4 vertex in CCW order addVertex(obj, x, y, z, u, v); z -= depth; v -= depth; addVertex(obj, x, y, z, u, v); x += width; u += width; addVertex(obj, x, y, z, u, v); z += depth; v += depth; addVertex(obj, x, y, z, u, v); for(int a=0;a<4;a++) { pts[a] = vidx++; } obj.addPoly(pts); } private void addFaceA(Object3 obj, float x, float y, float z, float u, float v) { int vidx = obj.getVertexCount(); //add 4 vertex in CCW order addVertex(obj, x, y, z, u, v); x += width; u += width; addVertex(obj, x, y, z, u, v); z -= depth; v -= depth; addVertex(obj, x, y, z, u, v); x -= width; u -= width; addVertex(obj, x, y, z, u, v); for(int a=0;a<4;a++) { pts[a] = vidx++; } obj.addPoly(pts); } private void mirror(Object3 obj) { //mirror u text coord in vertex 1 <-> 2 and 3 <-> 4 float[] uv = obj.getUVMap(0).uvl.getBuffer(); int idx = obj.getVertexCount(); int v1 = (idx - 4) * 2; int v2 = (idx - 3) * 2; int v3 = (idx - 2) * 2; int v4 = (idx - 1) * 2; float tmp; //swap 1 <-> 2 tmp = uv[v1]; uv[v1] = uv[v2]; uv[v2] = tmp; //swap 3 <-> 4 tmp = uv[v3]; uv[v3] = uv[v4]; uv[v4] = tmp; } private void addVertex(Object3 obj, float x, float y, float z, float u, float v) { //coords are based on pixels, the org game is based on 8x textures xyz[0] = x / scale; xyz[1] = y / scale; xyz[2] = z / scale; //scale uv : 0-1 uv[0] = u / tw; uv[1] = v / th; obj.addVertex(xyz, uv); } private float getValue(String e) { return Float.valueOf(e); } private float[] getValues(Element array) { int cnt = array.getChildCount(); float[] values = new float[cnt]; for(int i=0;i