import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; public class GameModel { private static int sine9[]; private static int sine11[]; private static int base64Alphabet[]; public int numVertices; public int projectVertexX[]; public int projectVertexY[]; public int projectVertexZ[]; public int vertexViewX[]; public int vertexViewY[]; public int vertexIntensity[]; public byte vertexAmbience[]; public int numFaces; public int faceNumVertices[]; public int faceVertices[][]; public int faceFillFront[]; public int faceFillBack[]; public int normalMagnitude[]; public int normalScale[]; public int faceIntensity[]; public int faceNormalX[]; public int faceNormalY[]; public int faceNormalZ[]; public int depth; public int transformState; public boolean visible; public int x1; public int x2; public int y1; public int y2; public int z1; public int z2; public boolean textureTranslucent; public boolean transparent; public int key; public int faceTag[]; public byte isLocalPlayer[]; public boolean isolated; public boolean unlit; public boolean unpickable; public boolean projected; public int maxVerts; public int vertexX[]; public int vertexY[]; public int vertexZ[]; public int vertexTransformedX[]; public int vertexTransformedY[]; public int vertexTransformedZ[]; protected int lightDiffuse; protected int lightAmbience; private boolean autocommit; private int magic; private int maxFaces; private int faceTransStateThing[][]; private int faceBoundLeft[]; private int faceBoundRight[]; private int faceBoundBottom[]; private int faceBoundTop[]; private int faceBoundNear[]; private int faceBoundFar[]; private int baseX; private int baseY; private int baseZ; private int orientationYaw; private int orientationPitch; private int orientationRoll; private int scaleFx; private int scaleFy; private int scaleFz; private int shearXy; private int shearXz; private int shearYx; private int shearYz; private int shearZx; private int shearZy; private int transformKind; private int diameter; private int lightDirectionX; private int lightDirectionY; private int lightDirectionZ; private int lightDirectionMagnitude; private int dataPtr; static { sine9 = new int[512]; sine11 = new int[2048]; base64Alphabet = new int[256]; for (int i = 0; i < 256; i++) { sine9[i] = (int) (Math.sin((double) i * 0.02454369D) * 32768D); sine9[i + 256] = (int) (Math.cos((double) i * 0.02454369D) * 32768D); } for (int j = 0; j < 1024; j++) { sine11[j] = (int) (Math.sin((double) j * 0.00613592315D) * 32768D); sine11[j + 1024] = (int) (Math.cos((double) j * 0.00613592315D) * 32768D); } for (int j1 = 0; j1 < 10; j1++) base64Alphabet[48 + j1] = j1; for (int k1 = 0; k1 < 26; k1++) base64Alphabet[65 + k1] = k1 + 10; for (int l1 = 0; l1 < 26; l1++) base64Alphabet[97 + l1] = l1 + 36; base64Alphabet[163] = 62; base64Alphabet[36] = 63; } public GameModel(int numVertices, int numFaces) { transformState = 1; visible = true; textureTranslucent = false; transparent = false; key = -1; autocommit = false; isolated = false; unlit = false; unpickable = false; projected = false; magic = World.colourTransparent; diameter = World.colourTransparent; lightDirectionX = 180; lightDirectionY = 155; lightDirectionZ = 95; lightDirectionMagnitude = 256; lightDiffuse = 512; lightAmbience = 32; allocate(numVertices, numFaces); faceTransStateThing = new int[numFaces][1]; for (int v = 0; v < numFaces; v++) faceTransStateThing[v][0] = v; } public GameModel(int numVertices, int numFaces, boolean autocommit, boolean isolated, boolean unlit, boolean unpickable, boolean projected) { transformState = 1; visible = true; textureTranslucent = false; transparent = false; key = -1; magic = World.colourTransparent; diameter = World.colourTransparent; lightDirectionX = 180; lightDirectionY = 155; lightDirectionZ = 95; lightDirectionMagnitude = 256; lightDiffuse = 512; lightAmbience = 32; this.autocommit = autocommit; this.isolated = isolated; this.unlit = unlit; this.unpickable = unpickable; this.projected = projected; allocate(numVertices, numFaces); } public GameModel(byte data[], int offset, boolean unused) { transformState = 1; visible = true; textureTranslucent = false; transparent = false; key = -1; autocommit = false; isolated = false; unlit = false; unpickable = false; projected = false; magic = World.colourTransparent; diameter = World.colourTransparent; lightDirectionX = 180; lightDirectionY = 155; lightDirectionZ = 95; lightDirectionMagnitude = 256; lightDiffuse = 512; lightAmbience = 32; int j = Utility.getUnsignedShort(data, offset); offset += 2; int k = Utility.getUnsignedShort(data, offset); offset += 2; allocate(j, k); faceTransStateThing = new int[k][1]; for (int l = 0; l < j; l++) { vertexX[l] = Utility.getSignedShort(data, offset); offset += 2; } for (int i1 = 0; i1 < j; i1++) { vertexY[i1] = Utility.getSignedShort(data, offset); offset += 2; } for (int j1 = 0; j1 < j; j1++) { vertexZ[j1] = Utility.getSignedShort(data, offset); offset += 2; } numVertices = j; for (int k1 = 0; k1 < k; k1++) faceNumVertices[k1] = data[offset++] & 0xff; for (int l1 = 0; l1 < k; l1++) { faceFillFront[l1] = Utility.getSignedShort(data, offset); offset += 2; if (faceFillFront[l1] == 32767) faceFillFront[l1] = magic; } for (int i2 = 0; i2 < k; i2++) { faceFillBack[i2] = Utility.getSignedShort(data, offset); offset += 2; if (faceFillBack[i2] == 32767) faceFillBack[i2] = magic; } for (int j2 = 0; j2 < k; j2++) { int k2 = data[offset++] & 0xff; if (k2 == 0) faceIntensity[j2] = 0; else faceIntensity[j2] = magic; } for (int l2 = 0; l2 < k; l2++) { faceVertices[l2] = new int[faceNumVertices[l2]]; for (int i3 = 0; i3 < faceNumVertices[l2]; i3++) if (j < 256) { faceVertices[l2][i3] = data[offset++] & 0xff; } else { faceVertices[l2][i3] = Utility.getUnsignedShort(data, offset); offset += 2; } } numFaces = k; transformState = 1; } public GameModel(String name) { transformState = 1; visible = true; textureTranslucent = false; transparent = false; key = -1; autocommit = false; isolated = false; unlit = false; unpickable = false; projected = false; magic = World.colourTransparent; diameter = World.colourTransparent; lightDirectionX = 180; lightDirectionY = 155; lightDirectionZ = 95; lightDirectionMagnitude = 256; lightDiffuse = 512; lightAmbience = 32; byte data[]; try { InputStream inputstream = Utility.openFile(name); DataInputStream datainputstream = new DataInputStream(inputstream); data = new byte[3]; dataPtr = 0; for (int i = 0; i < 3; i += datainputstream.read(data, i, 3 - i)) ; int sz = readBase64(data); data = new byte[sz]; dataPtr = 0; for (int j = 0; j < sz; j += datainputstream.read(data, j, sz - j)) ; datainputstream.close(); } catch (IOException Ex) { numVertices = 0; numFaces = 0; return; } int nV = readBase64(data); int nF = readBase64(data); allocate(nV, nF); faceTransStateThing = new int[nF][]; for (int j3 = 0; j3 < nV; j3++) { int x = readBase64(data); int y = readBase64(data); int z = readBase64(data); vertexAt(x, y, z); } for (int k3 = 0; k3 < nF; k3++) { int n = readBase64(data); int front = readBase64(data); int back = readBase64(data); int l2 = readBase64(data); lightDiffuse = readBase64(data); lightAmbience = readBase64(data); int gouraud = readBase64(data); int vs[] = new int[n]; for (int i = 0; i < n; i++) vs[i] = readBase64(data); int ai1[] = new int[l2]; for (int i4 = 0; i4 < l2; i4++) ai1[i4] = readBase64(data); int j4 = createFace(n, vs, front, back); faceTransStateThing[k3] = ai1; if (gouraud == 0) faceIntensity[j4] = 0; else faceIntensity[j4] = magic; } transformState = 1; } public GameModel(GameModel pieces[], int count, boolean autocommit, boolean isolated, boolean unlit, boolean unpickable) { transformState = 1; visible = true; textureTranslucent = false; transparent = false; key = -1; projected = false; magic = World.colourTransparent; diameter = World.colourTransparent; lightDirectionX = 180; lightDirectionY = 155; lightDirectionZ = 95; lightDirectionMagnitude = 256; lightDiffuse = 512; lightAmbience = 32; this.autocommit = autocommit; this.isolated = isolated; this.unlit = unlit; this.unpickable = unpickable; merge(pieces, count, false); } public GameModel(GameModel pieces[], int count) { transformState = 1; visible = true; textureTranslucent = false; transparent = false; key = -1; autocommit = false; isolated = false; unlit = false; unpickable = false; projected = false; magic = World.colourTransparent; diameter = World.colourTransparent; lightDirectionX = 180; lightDirectionY = 155; lightDirectionZ = 95; lightDirectionMagnitude = 256; lightDiffuse = 512; lightAmbience = 32; merge(pieces, count, true); } private void allocate(int numV, int numF) { vertexX = new int[numV]; vertexY = new int[numV]; vertexZ = new int[numV]; vertexIntensity = new int[numV]; vertexAmbience = new byte[numV]; faceNumVertices = new int[numF]; faceVertices = new int[numF][]; faceFillFront = new int[numF]; faceFillBack = new int[numF]; faceIntensity = new int[numF]; normalScale = new int[numF]; normalMagnitude = new int[numF]; if (!projected) { projectVertexX = new int[numV]; projectVertexY = new int[numV]; projectVertexZ = new int[numV]; vertexViewX = new int[numV]; vertexViewY = new int[numV]; } if (!unpickable) { isLocalPlayer = new byte[numF]; faceTag = new int[numF]; } if (autocommit) { vertexTransformedX = vertexX; vertexTransformedY = vertexY; vertexTransformedZ = vertexZ; } else { vertexTransformedX = new int[numV]; vertexTransformedY = new int[numV]; vertexTransformedZ = new int[numV]; } if (!unlit || !isolated) { faceNormalX = new int[numF]; faceNormalY = new int[numF]; faceNormalZ = new int[numF]; } if (!isolated) { faceBoundLeft = new int[numF]; faceBoundRight = new int[numF]; faceBoundBottom = new int[numF]; faceBoundTop = new int[numF]; faceBoundNear = new int[numF]; faceBoundFar = new int[numF]; } numFaces = 0; numVertices = 0; maxVerts = numV; maxFaces = numF; baseX = baseY = baseZ = 0; orientationYaw = orientationPitch = orientationRoll = 0; scaleFx = scaleFy = scaleFz = 256; shearXy = shearXz = shearYx = shearYz = shearZx = shearZy = 256; transformKind = 0; } public void projectionPrepare() { projectVertexX = new int[numVertices]; projectVertexY = new int[numVertices]; projectVertexZ = new int[numVertices]; vertexViewX = new int[numVertices]; vertexViewY = new int[numVertices]; } public void clear() { numFaces = 0; numVertices = 0; } public void reduce(int df, int dz) { numFaces -= df; if (numFaces < 0) numFaces = 0; numVertices -= dz; if (numVertices < 0) numVertices = 0; } public void merge(GameModel pieces[], int count, boolean transState) { int numF = 0; int numV = 0; for (int i = 0; i < count; i++) { numF += pieces[i].numFaces; numV += pieces[i].numVertices; } allocate(numV, numF); if (transState) faceTransStateThing = new int[numF][]; for (int i = 0; i < count; i++) { GameModel source = pieces[i]; source.commit(); lightAmbience = source.lightAmbience; lightDiffuse = source.lightDiffuse; lightDirectionX = source.lightDirectionX; lightDirectionY = source.lightDirectionY; lightDirectionZ = source.lightDirectionZ; lightDirectionMagnitude = source.lightDirectionMagnitude; for (int srcF = 0; srcF < source.numFaces; srcF++) { int dstVs[] = new int[source.faceNumVertices[srcF]]; int srcVs[] = source.faceVertices[srcF]; for (int v = 0; v < source.faceNumVertices[srcF]; v++) dstVs[v] = vertexAt(source.vertexX[srcVs[v]], source.vertexY[srcVs[v]], source.vertexZ[srcVs[v]]); int dstF = createFace(source.faceNumVertices[srcF], dstVs, source.faceFillFront[srcF], source.faceFillBack[srcF]); faceIntensity[dstF] = source.faceIntensity[srcF]; normalScale[dstF] = source.normalScale[srcF]; normalMagnitude[dstF] = source.normalMagnitude[srcF]; if (transState) if (count > 1) { faceTransStateThing[dstF] = new int[source.faceTransStateThing[srcF].length + 1]; faceTransStateThing[dstF][0] = i; for (int i2 = 0; i2 < source.faceTransStateThing[srcF].length; i2++) faceTransStateThing[dstF][i2 + 1] = source.faceTransStateThing[srcF][i2]; } else { faceTransStateThing[dstF] = new int[source.faceTransStateThing[srcF].length]; for (int j2 = 0; j2 < source.faceTransStateThing[srcF].length; j2++) faceTransStateThing[dstF][j2] = source.faceTransStateThing[srcF][j2]; } } } transformState = 1; } public int vertexAt(int x, int y, int z) { for (int l = 0; l < numVertices; l++) if (vertexX[l] == x && vertexY[l] == y && vertexZ[l] == z) return l; if (numVertices >= maxVerts) { return -1; } else { vertexX[numVertices] = x; vertexY[numVertices] = y; vertexZ[numVertices] = z; return numVertices++; } } public int createVertex(int i, int j, int k) { if (numVertices >= maxVerts) { return -1; } else { vertexX[numVertices] = i; vertexY[numVertices] = j; vertexZ[numVertices] = k; return numVertices++; } } public int createFace(int n, int vs[], int front, int back) { if (numFaces >= maxFaces) { return -1; } else { faceNumVertices[numFaces] = n; faceVertices[numFaces] = vs; faceFillFront[numFaces] = front; faceFillBack[numFaces] = back; transformState = 1; return numFaces++; } } public GameModel[] split(int unused1, int unused2, int pieceDx, int pieceDz, int rows, int count, int pieceMaxVertices, boolean pickable) { commit(); int pieceNV[] = new int[count]; int pieceNF[] = new int[count]; for (int i = 0; i < count; i++) { pieceNV[i] = 0; pieceNF[i] = 0; } for (int f = 0; f < numFaces; f++) { int sumX = 0; int sumZ = 0; int n = faceNumVertices[f]; int vs[] = faceVertices[f]; for (int i = 0; i < n; i++) { sumX += vertexX[vs[i]]; sumZ += vertexZ[vs[i]]; } int p = sumX / (n * pieceDx) + (sumZ / (n * pieceDz)) * rows; pieceNV[p] += n; pieceNF[p]++; } GameModel pieces[] = new GameModel[count]; for (int i = 0; i < count; i++) { if (pieceNV[i] > pieceMaxVertices) pieceNV[i] = pieceMaxVertices; pieces[i] = new GameModel(pieceNV[i], pieceNF[i], true, true, true, pickable, true); pieces[i].lightDiffuse = lightDiffuse; pieces[i].lightAmbience = lightAmbience; } for (int f = 0; f < numFaces; f++) { int sumX = 0; int sumZ = 0; int n = faceNumVertices[f]; int vs[] = faceVertices[f]; for (int i = 0; i < n; i++) { sumX += vertexX[vs[i]]; sumZ += vertexZ[vs[i]]; } int p = sumX / (n * pieceDx) + (sumZ / (n * pieceDz)) * rows; copyLighting(pieces[p], vs, n, f); } for (int p = 0; p < count; p++) pieces[p].projectionPrepare(); return pieces; } public void copyLighting(GameModel model, int srcVs[], int nV, int inF) { int dstVs[] = new int[nV]; for (int inV = 0; inV < nV; inV++) { int outV = dstVs[inV] = model.vertexAt(vertexX[srcVs[inV]], vertexY[srcVs[inV]], vertexZ[srcVs[inV]]); model.vertexIntensity[outV] = vertexIntensity[srcVs[inV]]; model.vertexAmbience[outV] = vertexAmbience[srcVs[inV]]; } int outF = model.createFace(nV, dstVs, faceFillFront[inF], faceFillBack[inF]); if (!model.unpickable && !unpickable) model.faceTag[outF] = faceTag[inF]; model.faceIntensity[outF] = faceIntensity[inF]; model.normalScale[outF] = normalScale[inF]; model.normalMagnitude[outF] = normalMagnitude[inF]; } public void setLight(boolean gouraud, int ambient, int diffuse, int x, int y, int z) { lightAmbience = 256 - ambient * 4; lightDiffuse = (64 - diffuse) * 16 + 128; if (unlit) return; for (int i = 0; i < numFaces; i++) if (gouraud) faceIntensity[i] = magic; else faceIntensity[i] = 0; lightDirectionX = x; lightDirectionY = y; lightDirectionZ = z; lightDirectionMagnitude = (int) Math.sqrt(x * x + y * y + z * z); light(); } public void setLight(int ambience, int diffuse, int x, int y, int z) { lightAmbience = 256 - ambience * 4; lightDiffuse = (64 - diffuse) * 16 + 128; if (!unlit) { lightDirectionX = x; lightDirectionY = y; lightDirectionZ = z; lightDirectionMagnitude = (int) Math.sqrt(x * x + y * y + z * z); light(); } } public void setLight(int x, int y, int z) { if (!unlit) { lightDirectionX = x; lightDirectionY = y; lightDirectionZ = z; lightDirectionMagnitude = (int) Math.sqrt(x * x + y * y + z * z); light(); } } public void setVertexAmbience(int v, int ambience) { vertexAmbience[v] = (byte) ambience; } public void rotate(int yaw, int pitch, int roll) { orientationYaw = orientationYaw + yaw & 0xff; orientationPitch = orientationPitch + pitch & 0xff; orientationRoll = orientationRoll + roll & 0xff; determineTransformKind(); transformState = 1; } public void orient(int yaw, int pitch, int roll) { orientationYaw = yaw & 0xff; orientationPitch = pitch & 0xff; orientationRoll = roll & 0xff; determineTransformKind(); transformState = 1; } public void translate(int x, int y, int z) { baseX += x; baseY += y; baseZ += z; determineTransformKind(); transformState = 1; } public void place(int x, int y, int z) { baseX = x; baseY = y; baseZ = z; determineTransformKind(); transformState = 1; } private void determineTransformKind() { if (shearXy != 256 || shearXz != 256 || shearYx != 256 || shearYz != 256 || shearZx != 256 || shearZy != 256) { transformKind = 4; } else if (scaleFx != 256 || scaleFy != 256 || scaleFz != 256) { transformKind = 3; } else if (orientationYaw != 0 || orientationPitch != 0 || orientationRoll != 0) { transformKind = 2; } else if (baseX != 0 || baseY != 0 || baseZ != 0) { transformKind = 1; } else { transformKind = 0; } } private void applyTranslate(int dx, int dy, int dz) { for (int v = 0; v < numVertices; v++) { vertexTransformedX[v] += dx; vertexTransformedY[v] += dy; vertexTransformedZ[v] += dz; } } private void applyRotation(int yaw, int roll, int pitch) { for (int v = 0; v < numVertices; v++) { if (pitch != 0) { int sin = sine9[pitch]; int cos = sine9[pitch + 256]; int x = vertexTransformedY[v] * sin + vertexTransformedX[v] * cos >> 15; vertexTransformedY[v] = vertexTransformedY[v] * cos - vertexTransformedX[v] * sin >> 15; vertexTransformedX[v] = x; } if (yaw != 0) { int sin = sine9[yaw]; int cos = sine9[yaw + 256]; int y = vertexTransformedY[v] * cos - vertexTransformedZ[v] * sin >> 15; vertexTransformedZ[v] = vertexTransformedY[v] * sin + vertexTransformedZ[v] * cos >> 15; vertexTransformedY[v] = y; } if (roll != 0) { int sin = sine9[roll]; int cos = sine9[roll + 256]; int x = vertexTransformedZ[v] * sin + vertexTransformedX[v] * cos >> 15; vertexTransformedZ[v] = vertexTransformedZ[v] * cos - vertexTransformedX[v] * sin >> 15; vertexTransformedX[v] = x; } } } private void applyShear(int xy, int xz, int yx, int yz, int zx, int zy) { for (int idx = 0; idx < numVertices; idx++) { if (xy != 0) vertexTransformedX[idx] += vertexTransformedY[idx] * xy >> 8; if (xz != 0) vertexTransformedZ[idx] += vertexTransformedY[idx] * xz >> 8; if (yx != 0) vertexTransformedX[idx] += vertexTransformedZ[idx] * yx >> 8; if (yz != 0) vertexTransformedY[idx] += vertexTransformedZ[idx] * yz >> 8; if (zx != 0) vertexTransformedZ[idx] += vertexTransformedX[idx] * zx >> 8; if (zy != 0) vertexTransformedY[idx] += vertexTransformedX[idx] * zy >> 8; } } private void applyScale(int fx, int fy, int fz) { for (int v = 0; v < numVertices; v++) { vertexTransformedX[v] = vertexTransformedX[v] * fx >> 8; vertexTransformedY[v] = vertexTransformedY[v] * fy >> 8; vertexTransformedZ[v] = vertexTransformedZ[v] * fz >> 8; } } private void computeBounds() { x1 = y1 = z1 = 0xf423f; diameter = x2 = y2 = z2 = 0xfff0bdc1; for (int face = 0; face < numFaces; face++) { int vs[] = faceVertices[face]; int v = vs[0]; int n = faceNumVertices[face]; int x1; int x2 = x1 = vertexTransformedX[v]; int y1; int y2 = y1 = vertexTransformedY[v]; int z1; int z2 = z1 = vertexTransformedZ[v]; for (int i = 0; i < n; i++) { v = vs[i]; if (vertexTransformedX[v] < x1) x1 = vertexTransformedX[v]; else if (vertexTransformedX[v] > x2) x2 = vertexTransformedX[v]; if (vertexTransformedY[v] < y1) y1 = vertexTransformedY[v]; else if (vertexTransformedY[v] > y2) y2 = vertexTransformedY[v]; if (vertexTransformedZ[v] < z1) z1 = vertexTransformedZ[v]; else if (vertexTransformedZ[v] > z2) z2 = vertexTransformedZ[v]; } if (!isolated) { faceBoundLeft[face] = x1; faceBoundRight[face] = x2; faceBoundBottom[face] = y1; faceBoundTop[face] = y2; faceBoundNear[face] = z1; faceBoundFar[face] = z2; } if (x2 - x1 > diameter) diameter = x2 - x1; if (y2 - y1 > diameter) diameter = y2 - y1; if (z2 - z1 > diameter) diameter = z2 - z1; if (x1 < this.x1) this.x1 = x1; if (x2 > this.x2) this.x2 = x2; if (y1 < this.y1) this.y1 = y1; if (y2 > this.y2) this.y2 = y2; if (z1 < this.z1) this.z1 = z1; if (z2 > this.z2) this.z2 = z2; } } public void light() { if (unlit) return; int divisor = lightDiffuse * lightDirectionMagnitude >> 8; for (int face = 0; face < numFaces; face++) if (faceIntensity[face] != magic) faceIntensity[face] = (faceNormalX[face] * lightDirectionX + faceNormalY[face] * lightDirectionY + faceNormalZ[face] * lightDirectionZ) / divisor; int normalX[] = new int[numVertices]; int normalY[] = new int[numVertices]; int normalZ[] = new int[numVertices]; int normalMagnitude[] = new int[numVertices]; for (int k = 0; k < numVertices; k++) { normalX[k] = 0; normalY[k] = 0; normalZ[k] = 0; normalMagnitude[k] = 0; } for (int face = 0; face < numFaces; face++) if (faceIntensity[face] == magic) { for (int v = 0; v < faceNumVertices[face]; v++) { int k1 = faceVertices[face][v]; normalX[k1] += faceNormalX[face]; normalY[k1] += faceNormalY[face]; normalZ[k1] += faceNormalZ[face]; normalMagnitude[k1]++; } } for (int v = 0; v < numVertices; v++) if (normalMagnitude[v] > 0) vertexIntensity[v] = (normalX[v] * lightDirectionX + normalY[v] * lightDirectionY + normalZ[v] * lightDirectionZ) / (divisor * normalMagnitude[v]); } public void relight() { if (unlit && isolated) return; for (int face = 0; face < numFaces; face++) { int verts[] = faceVertices[face]; int aX = vertexTransformedX[verts[0]]; int aY = vertexTransformedY[verts[0]]; int aZ = vertexTransformedZ[verts[0]]; int bX = vertexTransformedX[verts[1]] - aX; int bY = vertexTransformedY[verts[1]] - aY; int bZ = vertexTransformedZ[verts[1]] - aZ; int cX = vertexTransformedX[verts[2]] - aX; int cY = vertexTransformedY[verts[2]] - aY; int cZ = vertexTransformedZ[verts[2]] - aZ; int normX = bY * cZ - cY * bZ; int normY = bZ * cX - cZ * bX; int normZ; for (normZ = bX * cY - cX * bY; normX > 8192 || normY > 8192 || normZ > 8192 || normX < -8192 || normY < -8192 || normZ < -8192; normZ >>= 1) { normX >>= 1; normY >>= 1; } int normMag = (int) (256D * Math.sqrt(normX * normX + normY * normY + normZ * normZ)); if (normMag <= 0) normMag = 1; faceNormalX[face] = (normX * 0x10000) / normMag; faceNormalY[face] = (normY * 0x10000) / normMag; faceNormalZ[face] = (normZ * 65535) / normMag; normalScale[face] = -1; } light(); } public void apply() { if (transformState == 2) { transformState = 0; for (int v = 0; v < numVertices; v++) { vertexTransformedX[v] = vertexX[v]; vertexTransformedY[v] = vertexY[v]; vertexTransformedZ[v] = vertexZ[v]; } x1 = y1 = z1 = 0xff676981; diameter = x2 = y2 = z2 = 0x98967f; return; } if (transformState == 1) { transformState = 0; for (int v = 0; v < numVertices; v++) { vertexTransformedX[v] = vertexX[v]; vertexTransformedY[v] = vertexY[v]; vertexTransformedZ[v] = vertexZ[v]; } if (transformKind >= 2) applyRotation(orientationYaw, orientationPitch, orientationRoll); if (transformKind >= 3) applyScale(scaleFx, scaleFy, scaleFz); if (transformKind >= 4) applyShear(shearXy, shearXz, shearYx, shearYz, shearZx, shearZy); if (transformKind >= 1) applyTranslate(baseX, baseY, baseZ); computeBounds(); relight(); } } public void project(int cameraX, int cameraY, int cameraZ, int cameraPitch, int cameraRoll, int cameraYaw, int viewDist, int clipNear) { apply(); if (z1 > Scene.frustumNearZ || z2 < Scene.furstumFarZ || x1 > Scene.frustumMinX || x2 < Scene.frustumMaxX || y1 > Scene.furstumMinY || y2 < Scene.furstumMaxY) { visible = false; return; } visible = true; int yawSin = 0; int yawCos = 0; int pitchSin = 0; int pitchCos = 0; int rollSin = 0; int rollCos = 0; if (cameraYaw != 0) { yawSin = sine11[cameraYaw]; yawCos = sine11[cameraYaw + 1024]; } if (cameraRoll != 0) { rollSin = sine11[cameraRoll]; rollCos = sine11[cameraRoll + 1024]; } if (cameraPitch != 0) { pitchSin = sine11[cameraPitch]; pitchCos = sine11[cameraPitch + 1024]; } for (int v = 0; v < numVertices; v++) { int x = vertexTransformedX[v] - cameraX; int y = vertexTransformedY[v] - cameraY; int z = vertexTransformedZ[v] - cameraZ; if (cameraYaw != 0) { int X = y * yawSin + x * yawCos >> 15; y = y * yawCos - x * yawSin >> 15; x = X; } if (cameraRoll != 0) { int X = z * rollSin + x * rollCos >> 15; z = z * rollCos - x * rollSin >> 15; x = X; } if (cameraPitch != 0) { int Y = y * pitchCos - z * pitchSin >> 15; z = y * pitchSin + z * pitchCos >> 15; y = Y; } if (z >= clipNear) vertexViewX[v] = (x << viewDist) / z; else vertexViewX[v] = x << viewDist; if (z >= clipNear) vertexViewY[v] = (y << viewDist) / z; else vertexViewY[v] = y << viewDist; projectVertexX[v] = x; projectVertexY[v] = y; projectVertexZ[v] = z; } } public void commit() { apply(); for (int i = 0; i < numVertices; i++) { vertexX[i] = vertexTransformedX[i]; vertexY[i] = vertexTransformedY[i]; vertexZ[i] = vertexTransformedZ[i]; } baseX = baseY = baseZ = 0; orientationYaw = orientationPitch = orientationRoll = 0; scaleFx = scaleFy = scaleFz = 256; shearXy = shearXz = shearYx = shearYz = shearZx = shearZy = 256; transformKind = 0; } public GameModel copy() { GameModel pieces[] = new GameModel[1]; pieces[0] = this; GameModel gameModel = new GameModel(pieces, 1); gameModel.depth = depth; gameModel.transparent = transparent; return gameModel; } public GameModel copy(boolean autocommit, boolean isolated, boolean unlit, boolean pickable) { GameModel pieces[] = new GameModel[1]; pieces[0] = this; GameModel gameModel = new GameModel(pieces, 1, autocommit, isolated, unlit, pickable); gameModel.depth = depth; return gameModel; } public void copyPosition(GameModel model) { orientationYaw = model.orientationYaw; orientationPitch = model.orientationPitch; orientationRoll = model.orientationRoll; baseX = model.baseX; baseY = model.baseY; baseZ = model.baseZ; determineTransformKind(); transformState = 1; } public int readBase64(byte buff[]) { for (; buff[dataPtr] == 10 || buff[dataPtr] == 13; dataPtr++) ; int hi = base64Alphabet[buff[dataPtr++] & 0xff]; int mid = base64Alphabet[buff[dataPtr++] & 0xff]; int lo = base64Alphabet[buff[dataPtr++] & 0xff]; int val = (hi * 4096 + mid * 64 + lo) - 0x20000; if (val == 0x1e240) val = magic; return val; } }