/** * * Copyright 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.4.1 */ package loon.opengl.parse; import loon.BaseIO; import loon.utils.ArrayByte; import loon.utils.MathUtils; import loon.utils.NumberUtils; public class D3DMdLoader { public static String TAG_TORSO = "tag_torso"; public static String TAG_HEAD = "tag_head"; private float scale = 0.1f; private int unsignedByteToInt(byte b) { return (int) b & 0xFF; } private int read16(byte buffer[], int offset) { int res; int res2; res = unsignedByteToInt(buffer[offset]); res2 = unsignedByteToInt(buffer[offset + 1]) << 8; res = res | res2; return res; } private int signedread16(byte buffer[], int offset) { int res = read16(buffer, offset); if (res > 0x7fff) { res = -(0xffff - res); } return res; } private int read32(byte buffer[], int offset) { int res = 0; res = unsignedByteToInt(buffer[offset]); res = res | (unsignedByteToInt(buffer[offset + 1]) << 8); res = res | (unsignedByteToInt(buffer[offset + 2]) << 16); res = res | (unsignedByteToInt(buffer[offset + 3]) << 24); return res; } private String getString(byte[] input) { String s = ""; try { s = new String(input); if (s.indexOf(0) != -1) { s = s.substring(0, s.indexOf(0)); } } catch (Exception e) { e.printStackTrace(); } return s; } private int getInt(byte[] input) { int v = 0; v = read32(input, 0); return v; } private void readData(ArrayByte is, byte[] arg) { for (int i = 0; i < arg.length; i++) { arg[i] = (byte) is.read(); } readCount += arg.length; } private void skip(ArrayByte is, int count) { for (int i = 0; i < count; i++) { readData(is, read8); } } private void loadHeader(ArrayByte input, D3DIMdLoaderAdapter md3loader) { readCount = 0; // Read magic readData(input, read32); // Read version readData(input, read32); // Read name readData(input, readName); // Read flags readData(input, read32); // Read frames number readData(input, read32); frameNumber = getInt(read32); md3loader.setFrameNumberHeader(frameNumber); // Read tags readData(input, read32); tagNumber = getInt(read32); md3loader.setTagNumber(tagNumber); // Read surfaces readData(input, read32); surfaceNumber = getInt(read32); md3loader.setSurfaceNumber(surfaceNumber); // Read skins readData(input, read32); // Read offset frames readData(input, read32); frameOffset = getInt(read32); // Read offset tags readData(input, read32); tagOffset = getInt(read32); // Read offset surfaces readData(input, read32); surfaceOffset = getInt(read32); // Skipping following data to frame data this.skip(input, frameOffset - readCount); this.skip(input, tagOffset - readCount); loadTags(input, md3loader); } private void loadFrame(ArrayByte input) { this.skip(input, surfaceOffset - readCount); } private void loadTags(ArrayByte input, D3DIMdLoaderAdapter md3loader) { for (int k = 0; k < frameNumber; k++) { for (int i = 0; i < tagNumber; i++) { readData(input, readName); readData(input, read32); float x = NumberUtils.intBitsToFloat(getInt(read32)); readData(input, read32); float y = NumberUtils.intBitsToFloat(getInt(read32)); readData(input, read32); float z = NumberUtils.intBitsToFloat(getInt(read32)); for (int j = 0; j < 9; j++) { readData(input, read32); rotMatrix[j] = NumberUtils.intBitsToFloat(getInt(read32)); } md3loader.addTag(k, i, getString(readName), scale * x, scale * y, scale * z, rotMatrix); } } } private void loadSurface(ArrayByte input, D3DIMdLoaderAdapter md3loader) { for (int surfaceId = 0; surfaceId < this.surfaceNumber; surfaceId++) { int surfaceStart = readCount; readData(input, read32); // Read name readData(input, readName); md3loader.setSurfaceName(surfaceId, getString(readName)); // Read flags readData(input, read32); // Read frames number readData(input, read32); frameNumber = getInt(read32); md3loader.setFrameNumber(surfaceId, frameNumber); // Read shaders number readData(input, read32); shaderNumber = getInt(read32); md3loader.setShaderNumber(surfaceId, shaderNumber); // Read vertices number readData(input, read32); verticesNumber = getInt(read32); md3loader.setVerticeNumber(surfaceId, verticesNumber); // Read triangles number readData(input, read32); triangleNumber = getInt(read32); md3loader.setTriangleNumber(surfaceId, triangleNumber); // Read triangle offset readData(input, read32); triangleOffset = getInt(read32) + surfaceStart; // Read shader offset readData(input, read32); shaderOffset = getInt(read32) + surfaceStart; // Read st offset readData(input, read32); stOffset = getInt(read32) + surfaceStart; // Read xyz normal offset readData(input, read32); xyzNormalOffset = getInt(read32) + surfaceStart; // Read end surface offset readData(input, read32); endSurfaceOffset = getInt(read32) + surfaceStart; this.skip(input, xyzNormalOffset - readCount); for (int frameId = 0; frameId < frameNumber; frameId++) loadXYZNormal(input, md3loader, surfaceId, frameId); this.skip(input, endSurfaceOffset - readCount); } } public void loadShader(ArrayByte input, D3DIMdLoaderAdapter md3loader, int surfaceId) { for (int i = 0; i < shaderNumber; i++) { readData(input, readName); readData(input, read32); md3loader.setShader(surfaceId, getString(readName)); } } public void loadTriangles(ArrayByte input, D3DIMdLoaderAdapter md3loader, int surfaceId) { for (int i = 0; i < triangleNumber; i++) { readData(input, read32); int a = getInt(read32); readData(input, read32); int b = getInt(read32); readData(input, read32); int c = getInt(read32); md3loader.addTriangleIndices(surfaceId, i, a, b, c); } } public void loadSt(ArrayByte input, D3DIMdLoaderAdapter md3loader, int surfaceId) { for (int i = 0; i < verticesNumber; i++) { readData(input, read32); float u = NumberUtils.intBitsToFloat(getInt(read32)); readData(input, read32); float v = NumberUtils.intBitsToFloat(getInt(read32)); md3loader.addTexCoords(surfaceId, i, u, v); } } private float extractFloat(byte[] data, float factor) { int val = signedread16(read16, 0); return factor * (float) val; } private float cos(float v) { return MathUtils.cos(v); } private float sin(float v) { return MathUtils.sin(v); } private void loadXYZNormal(ArrayByte input, D3DIMdLoaderAdapter md3loader, int surfaceId, int frameId) { float factor = 1.0f / 64.0f; float x; float y; float z; float xn; float yn; float zn; for (int i = 0; i < verticesNumber; i++) { readData(input, read16); x = extractFloat(read16, factor); readData(input, read16); y = extractFloat(read16, factor); readData(input, read16); z = extractFloat(read16, factor); readData(input, read8); int zenith = unsignedByteToInt(read8[0]); readData(input, read8); int azimuth = unsignedByteToInt(read8[0]); float lat = (float) zenith * (2 * MathUtils.PI) / 255.0f; float lng = (float) azimuth * (2 * MathUtils.PI) / 255.0f; xn = cos(lng) * sin(lat); yn = sin(lng) * sin(lat); zn = cos(lat); md3loader.addVertexCoords(surfaceId, frameId, i, x * scale, y * scale, z * scale); md3loader.addNormalCoords(surfaceId, frameId, i, xn, yn, zn); } } private byte readName[] = new byte[64]; private byte read32[] = new byte[4]; private byte read16[] = new byte[2]; private byte read8[] = new byte[1]; private float rotMatrix[] = new float[9]; private int readCount = 0; private int frameOffset = 0; private int surfaceOffset = 0; private int surfaceNumber = 0; private int tagOffset = 0; private int tagNumber = 0; private int frameNumber = 0; private int verticesNumber = 0; private int triangleNumber = 0; private int triangleOffset = 0; private int stOffset = 0; private int xyzNormalOffset = 0; private int endSurfaceOffset = 0; private int shaderNumber = 0; private int shaderOffset = 0; public void loadMD3(String filePath, D3DIMdLoaderAdapter md3loader) { ArrayByte input = BaseIO.loadArrayByte(filePath); loadHeader(input, md3loader); loadFrame(input); loadSurface(input, md3loader); input.close(); } public int getTriangleOffset() { return triangleOffset; } public void setTriangleOffset(int triangleOffset) { this.triangleOffset = triangleOffset; } public int getStOffset() { return stOffset; } public void setStOffset(int stOffset) { this.stOffset = stOffset; } public int getShaderOffset() { return shaderOffset; } public void setShaderOffset(int shaderOffset) { this.shaderOffset = shaderOffset; } }