ginkage

Load3DS

Jun 1st, 2012
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package com.ginkage.postcard;
  2.  
  3. import java.io.BufferedInputStream;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.FileNotFoundException;
  7. import java.io.IOException;
  8. import java.util.ArrayList;
  9.  
  10. import android.opengl.Matrix;
  11. import android.os.Environment;
  12.  
  13. public class Load3DS {
  14.     private final int CHUNK_MAIN     = 0x4D4D;
  15.     private final int CHUNK_OBJMESH  = 0x3D3D;
  16.     private final int CHUNK_OBJBLOCK = 0x4000;
  17.     private final int CHUNK_TRIMESH  = 0x4100;
  18.     private final int CHUNK_VERTLIST = 0x4110;
  19.     private final int CHUNK_FACELIST = 0x4120;
  20.     private final int CHUNK_FACEMAT  = 0x4130;
  21.     private final int CHUNK_MAPLIST  = 0x4140;
  22.     private final int CHUNK_SMOOTHG  = 0x4150;
  23.     private final int CHUNK_TRMATRIX = 0x4160;
  24.     private final int CHUNK_LIGHT    = 0x4600;
  25.     private final int CHUNK_SPOTL    = 0x4610;
  26.     private final int CHUNK_ONOFF    = 0x4620;
  27.     private final int CHUNK_CAMERA   = 0x4700;
  28.     private final int CHUNK_RGBC     = 0x0010;
  29.     private final int CHUNK_RGB24    = 0x0011;
  30.     private final int CHUNK_SHORT    = 0x0030;
  31.     private final int CHUNK_BACKCOL  = 0x1200;
  32.     private final int CHUNK_AMB      = 0x2100;
  33.     private final int CHUNK_MATERIAL = 0xAFFF;
  34.     private final int CHUNK_MATNAME  = 0xA000;
  35.     private final int CHUNK_AMBIENT  = 0xA010;
  36.     private final int CHUNK_DIFFUSE  = 0xA020;
  37.     private final int CHUNK_SPECULAR = 0xA030;
  38.     private final int CHUNK_SHININES = 0xA040;
  39.     private final int CHUNK_SHINSTRN = 0xA041;
  40.     private final int CHUNK_TRANSP   = 0xA050;
  41.     private final int CHUNK_SELFILL  = 0xA084;
  42.     private final int CHUNK_MTLTYPE  = 0xA100;
  43.     private final int CHUNK_TEXTURE  = 0xA200;
  44.     private final int CHUNK_REFLMAP  = 0xA220;
  45.     private final int CHUNK_BUMPMAP  = 0xA230;
  46.     private final int CHUNK_MAPFILE  = 0xA300;
  47.     private final int CHUNK_MAPPARAM = 0xA351;
  48.     private final int CHUNK_KEYFRAMER = 0xB000;
  49.     private final int CHUNK_TRACKINFO = 0xB002;
  50.     private final int CHUNK_SPOTINFO  = 0xB007;
  51.     private final int CHUNK_FRAMES    = 0xB008;
  52.     private final int CHUNK_OBJNAME   = 0xB010;
  53.     private final int CHUNK_PIVOT     = 0xB013;
  54.     private final int CHUNK_TRACKPOS  = 0xB020;
  55.     private final int CHUNK_TRACKROT  = 0xB021;
  56.     private final int CHUNK_TRACKSCL  = 0xB022;
  57.     private final int CHUNK_HIERARCHY = 0xB030;
  58.  
  59.     private BufferedInputStream file;
  60.     private byte[] bytes = new byte[8];
  61.     private long filePos;
  62.  
  63.     public Scene3D Load(String fileName)
  64.     {
  65.         file = null;
  66.         Scene3D scene = null;
  67.         File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
  68.         File fil = new File(dir.getAbsolutePath() + File.separator + fileName);
  69.         if (!fil.exists()) return scene;
  70.  
  71.         try {
  72.             filePos = 0;
  73.             file = new BufferedInputStream(new FileInputStream(fil));
  74.             scene = ProcessFile(fil.length());
  75.         } catch (FileNotFoundException e) {
  76.             e.printStackTrace();
  77.         } catch (IOException e) {
  78.             e.printStackTrace();
  79.         }
  80.  
  81.         try {
  82.             if (file != null)
  83.                 file.close();
  84.         } catch (IOException e) {
  85.             e.printStackTrace();
  86.         }
  87.  
  88.         return scene;
  89.     }
  90.  
  91.     private void Skip(long count) throws IOException
  92.     {
  93.         file.skip(count);
  94.         filePos += count;
  95.     }
  96.  
  97.     private void Seek(long end) throws IOException
  98.     {
  99.         if (filePos < end) {
  100.             Skip(end - filePos);
  101.             filePos = end;
  102.         }
  103.     }
  104.  
  105.     private byte ReadByte() throws IOException
  106.     {
  107.         file.read(bytes, 0, 1);
  108.         filePos++;
  109.         return bytes[0];
  110.     }
  111.  
  112.     private int ReadUnsignedByte() throws IOException
  113.     {
  114.         file.read(bytes, 0, 1);
  115.         filePos++;
  116.         return (bytes[0]&0xff);
  117.     }
  118.  
  119.     private int ReadUnsignedShort() throws IOException
  120.     {
  121.         file.read(bytes, 0, 2);
  122.         filePos += 2;
  123.         return ((bytes[1]&0xff) << 8 | (bytes[0]&0xff));
  124.     }
  125.  
  126.     private int ReadInt() throws IOException
  127.     {
  128.         file.read(bytes, 0, 4);
  129.         filePos += 4;
  130.         return (bytes[3]) << 24 | (bytes[2]&0xff) << 16 | (bytes[1]&0xff) <<  8 | (bytes[0]&0xff);
  131.     }
  132.  
  133.     private float ReadFloat() throws IOException
  134.     {
  135.         return Float.intBitsToFloat(ReadInt());
  136.     }
  137.  
  138.     private Scene3D ProcessFile(long fileLen) throws IOException
  139.     {
  140.         Scene3D scene = null;
  141.  
  142.         while (filePos < fileLen) {
  143.             int chunkID = ReadUnsignedShort();
  144.             int chunkLen = ReadInt() - 6;
  145.  
  146.             switch (chunkID) {
  147.             case CHUNK_MAIN:
  148.                 if (scene == null)
  149.                     scene = ChunkMain(chunkLen);
  150.                 else
  151.                     Skip(chunkLen);
  152.                 break;
  153.  
  154.             default:
  155.                 Skip(chunkLen);
  156.             }
  157.         }
  158.  
  159.         return scene;
  160.     }
  161.  
  162.     private Scene3D ChunkMain(int len) throws IOException
  163.     {
  164.         Scene3D scene = new Scene3D();
  165.         scene.materials = new ArrayList<Material3D>();
  166.         scene.objects = new ArrayList<Object3D>();
  167.         scene.lights = new ArrayList<Light3D>();
  168.         scene.animations = new ArrayList<Animation>();
  169.  
  170.         long end = filePos + len;
  171.         while (filePos < end) {
  172.             int chunkID = ReadUnsignedShort();
  173.             int chunkLen = ReadInt() - 6;
  174.  
  175.             switch (chunkID) {
  176.             case CHUNK_OBJMESH:
  177.                 Chunk3DEditor(scene, chunkLen);
  178.                 break;
  179.  
  180.             case CHUNK_KEYFRAMER:
  181.                 ChunkKeyframer(scene, chunkLen);
  182.                 break;
  183.  
  184.             case CHUNK_BACKCOL:
  185.                 scene.background = new float[4];
  186.                 ChunkColor(chunkLen, scene.background);
  187.                 break;
  188.  
  189.             case CHUNK_AMB:
  190.                 scene.ambient = new float[4];
  191.                 ChunkColor(chunkLen, scene.ambient);
  192.                 break;
  193.  
  194.             default:
  195.                 Skip(chunkLen);
  196.             }
  197.         }
  198.         Seek(end);
  199.  
  200.         scene.Compute(0);
  201.  
  202.         return scene;
  203.     }
  204.  
  205.     private void Chunk3DEditor(Scene3D scene, int len) throws IOException
  206.     {
  207.         long end = filePos + len;
  208.         while (filePos < end) {
  209.             int chunkID = ReadUnsignedShort();
  210.             int chunkLen = ReadInt() - 6;
  211.  
  212.             switch (chunkID) {
  213.             case CHUNK_OBJBLOCK:
  214.                 ChunkObject(scene, chunkLen);
  215.                 break;
  216.  
  217.             case CHUNK_MATERIAL:
  218.                 Material3D mat = ChunkMaterial(scene, chunkLen);
  219.                 if (mat != null)
  220.                     scene.materials.add(mat);
  221.                 break;
  222.  
  223.             default:
  224.                 Skip(chunkLen);
  225.             }
  226.         }
  227.         Seek(end);
  228.     }
  229.  
  230.     private void ChunkObject(Scene3D scene, int len) throws IOException
  231.     {
  232.         long end = filePos + len;
  233.  
  234.         if (len == 0) return;
  235.         String name = ChunkName(0);
  236.  
  237.         while (filePos < end) {
  238.             int chunkID = ReadUnsignedShort();
  239.             int chunkLen = ReadInt() - 6;
  240.  
  241.             switch (chunkID) {
  242.             case CHUNK_TRIMESH:
  243.                 Object3D obj = ChunkTrimesh(chunkLen, name, scene);
  244.                 if (obj != null)
  245.                     scene.objects.add(obj);
  246.                 break;
  247.  
  248.             case CHUNK_LIGHT:
  249.                 Light3D light = ChunkLight(chunkLen, name);
  250.                 if (light != null)
  251.                     scene.lights.add(light);
  252.                 break;
  253.  
  254.             case CHUNK_CAMERA:
  255.             default:
  256.                 Skip(chunkLen);
  257.             }
  258.         }
  259.         Seek(end);
  260.     }
  261.  
  262.     private Object3D ChunkTrimesh(int len, String name, Scene3D scene) throws IOException
  263.     {
  264.         long end = filePos + len;
  265.  
  266.         Object3D obj = new Object3D();
  267.         obj.name = name;
  268.         obj.faceMats = new ArrayList<FaceMat>();
  269.         obj.indCount = 0;
  270.  
  271.         int i, k, num;
  272.  
  273.         while (filePos < end) {
  274.             int chunkID = ReadUnsignedShort();
  275.             int chunkLen = ReadInt() - 6;
  276.  
  277.             switch (chunkID) {
  278.             case CHUNK_FACELIST:
  279.                 ChunkFaceList(chunkLen, obj, scene);
  280.                 break;
  281.  
  282.             case CHUNK_MAPLIST:
  283.                 num = ReadUnsignedShort();
  284.                 for (i = 0, k = 6; i < num; i++, k += 8) {
  285.                     obj.vertexBuffer[k + 0] = ReadFloat();
  286.                     obj.vertexBuffer[k + 1] = 1 - ReadFloat();
  287.                 }
  288.                 break;
  289.  
  290.             case CHUNK_VERTLIST:
  291.                 num = ReadUnsignedShort();
  292.                 obj.vertCount = num;
  293.                 obj.vertexBuffer = new float[8*num];
  294.                 for (i = 0, k = 0; i < num; i++, k += 8) {
  295.                     ChunkVector(obj.vertexBuffer, k);
  296.                     obj.vertexBuffer[k + 3] = 0;
  297.                     obj.vertexBuffer[k + 4] = 0;
  298.                     obj.vertexBuffer[k + 5] = 0;
  299.                     obj.vertexBuffer[k + 6] = 0;
  300.                     obj.vertexBuffer[k + 7] = 0;
  301.                 }
  302.                 break;
  303.  
  304.             case CHUNK_TRMATRIX:
  305.                 float[] localCoord = new float[16];
  306.                 ChunkVector(localCoord, 4*0);
  307.                 ChunkVector(localCoord, 4*2);
  308.                 ChunkVector(localCoord, 4*1);
  309.                 ChunkVector(localCoord, 4*3);
  310.                 localCoord[3] = localCoord[7] = localCoord[11] = 0;
  311.                 localCoord[15] = 1;
  312.  
  313.                 obj.trMatrix = new float[16];
  314.                 Matrix.invertM(obj.trMatrix, 0, localCoord, 0);
  315.                 break;
  316.  
  317.             default:
  318.                 Skip(chunkLen);
  319.             }
  320.         }
  321.         Seek(end);
  322.  
  323.         return obj;
  324.     }
  325.  
  326.     private static void CrossProduct(float[] res, float[] v1, float[] v2)
  327.     {
  328.         res[0] = v1[1]*v2[2] - v1[2]*v2[1];
  329.         res[1] = v1[2]*v2[0] - v1[0]*v2[2];
  330.         res[2] = v1[0]*v2[1] - v1[1]*v2[0];
  331.     }
  332.  
  333.     private static float DotSquare(float[] v, int offset)
  334.     {
  335.         return v[offset + 0]*v[offset + 0] + v[offset + 1]*v[offset + 1] + v[offset + 2]*v[offset + 2];
  336.     }
  337.  
  338.     private static void VecSubstract(float[] res, float[] v, int offset1, int offset2)
  339.     {
  340.         res[0] = v[offset1 + 0] - v[offset2 + 0];
  341.         res[1] = v[offset1 + 1] - v[offset2 + 1];
  342.         res[2] = v[offset1 + 2] - v[offset2 + 2];
  343.     }
  344.  
  345.     private static void VecAdd(float[] v, int offset, float[] a, int off)
  346.     {
  347.         v[offset + 0] += a[off + 0];
  348.         v[offset + 1] += a[off + 1];
  349.         v[offset + 2] += a[off + 2];
  350.     }
  351.  
  352.     private void VecNormalize(float[] v, int offset)
  353.     {
  354.         double nlen = 1 / Math.sqrt(DotSquare(v, offset));
  355.         v[offset + 0] *= nlen;
  356.         v[offset + 1] *= nlen;
  357.         v[offset + 2] *= nlen;
  358.     }
  359.  
  360.     private void ChunkFaceList(int len, Object3D obj, Scene3D scene) throws IOException
  361.     {
  362.         long end = filePos + len;
  363.  
  364.         int i, j, k, l, m, t, num = ReadUnsignedShort(), unused = num, idx;
  365.  
  366.         int faceCount = num;
  367.         int[] faceBuffer = new int[3*faceCount];
  368.         boolean[] faceUsed = new boolean[faceCount];
  369.         float[] v = new float[3];
  370.         float[] v1 = new float[3];
  371.         float[] v2 = new float[3];
  372.  
  373.         float[] vgNorm = new float[3*3*faceCount]; // per-vertex normal for each face
  374.         int[] vertGroup = new int[3*faceCount]; // per-vertex group for each face
  375.         boolean[] vgUsed = new boolean[3*faceCount]; // per-vertex "group used" bit for each face
  376.         int[] vgNum = new int[obj.vertCount + 1]; // per-vertex face count, and then offset
  377.         int[] faceGroup = new int[faceCount]; // per-face smoothing group
  378.  
  379.         int[] vgUniqs = new int[obj.vertCount + 1]; // per-vertex unique groups count
  380.         int[] vertUGroup = new int[3*faceCount]; // per-vertex unique groups list for each face
  381.  
  382.         for (i = 0; i <= obj.vertCount; i++)
  383.             vgNum[i] = vgUniqs[i] = 0;
  384.  
  385.         for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
  386.             j = ReadUnsignedShort();
  387.             k = ReadUnsignedShort();
  388.             l = ReadUnsignedShort();
  389.             Skip(2);
  390.  
  391.             faceUsed[i] = false;
  392.             faceBuffer[idx + 0] = j;
  393.             faceBuffer[idx + 2] = k;
  394.             faceBuffer[idx + 1] = l;
  395.  
  396.             // initialize smoothing groups data
  397.             faceGroup[i] = 0;
  398.  
  399.             for (t = 0; t < 9; t++)
  400.                 vgNorm[i * 9 + t] = 0;
  401.  
  402.             for (t = 0; t < 3; t++) {
  403.                 vertGroup[idx + t] = 0;
  404.                 vertUGroup[idx + t] = 0;
  405.                 vgUsed[idx + t] = false;
  406.             }
  407.  
  408.             vgNum[j]++;
  409.             vgNum[k]++;
  410.             vgNum[l]++;
  411.         }
  412.  
  413.         int a, sum = 0;
  414.         for (i = 0; i < obj.vertCount; i++) {
  415.             a = vgNum[i];
  416.             vgNum[i] = sum;
  417.             sum += a;
  418.         }
  419.         vgNum[obj.vertCount] = sum; // now we can store all the faces and their normals and groups per-vertex
  420.  
  421.         for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
  422.             j = faceBuffer[idx + 0];
  423.             k = faceBuffer[idx + 2];
  424.             l = faceBuffer[idx + 1];
  425.  
  426.             VecSubstract(v1, obj.vertexBuffer, l*8, j*8);
  427.             VecSubstract(v2, obj.vertexBuffer, k*8, j*8);
  428.             CrossProduct(v, v1, v2);
  429.  
  430.             VecAdd(vgNorm, vgNum[j]*3, v, 0);
  431.             VecAdd(vgNorm, vgNum[k]*3, v, 0);
  432.             VecAdd(vgNorm, vgNum[l]*3, v, 0);
  433.            
  434.             vgNum[j]++;
  435.             vgNum[k]++;
  436.             vgNum[l]++;
  437.         }
  438.  
  439.         for (i = obj.vertCount - 1; i > 0; i--) // offsets were shifted, so shift them back
  440.             vgNum[i] = vgNum[i - 1];
  441.         vgNum[0] = 0;
  442.  
  443.         boolean gotSmoothGroups = false;
  444.  
  445.         while (filePos < end) {
  446.             int chunkID = ReadUnsignedShort();
  447.             int chunkLen = ReadInt() - 6;
  448.  
  449.             switch (chunkID) {
  450.             case CHUNK_FACEMAT:
  451.                 FaceMat mat = new FaceMat();
  452.                 String name = ChunkName(0);
  453.                 mat.material = scene.FindMaterial(name);
  454.                 num = ReadUnsignedShort();
  455.                 mat.indCount = num;
  456.                 mat.indexBuffer = new int[3*num];
  457.                 mat.bufOffset = obj.indCount;
  458.                 obj.indCount += 3*num;
  459.                 k = 0;
  460.                 for (i = 0; i < num; i++) {
  461.                     j = ReadUnsignedShort();
  462.                     if (!faceUsed[j]) {
  463.                         faceUsed[j] = true;
  464.                         unused--;
  465.                     }
  466.                     j *= 3;
  467.                     for (t = 0; t < 3; t++)
  468.                         mat.indexBuffer[k++] = j;
  469.                 }
  470.                 obj.faceMats.add(mat);
  471.                 break;
  472.  
  473.             case CHUNK_SMOOTHG:
  474.                 for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
  475.                     faceGroup[i] = ReadInt();
  476.                    
  477.                     for (t = 0; t < 3; t++) {
  478.                         j = faceBuffer[idx + t];
  479.                         vertGroup[vgNum[j]] = faceGroup[i];
  480.                         vgNum[j]++;
  481.                     }
  482.                 }
  483.                 for (i = obj.vertCount - 1; i > 0; i--)
  484.                     vgNum[i] = vgNum[i - 1];
  485.                 vgNum[0] = 0;
  486.                 gotSmoothGroups = true;
  487.                 break;
  488.  
  489.             default:
  490.                 Skip(chunkLen);
  491.             }
  492.         }
  493.         Seek(end);
  494.  
  495.         int newVertCount = 0, g;
  496.  
  497.         if (gotSmoothGroups) {
  498.             for (i = 0; i < obj.vertCount; i++) {
  499.                 for (m = vgNum[i]; m < vgNum[i + 1]; m++) { // for every normal and face of this vertex
  500.                     if (!vgUsed[m]) {
  501.                         // vertGroup[m] is a new group...
  502.                         vertUGroup[vgNum[i] + vgUniqs[i]] = vertGroup[m];
  503.                         vgUniqs[i]++;
  504.                         newVertCount++;
  505.                     }
  506.    
  507.                     for (t = m; t < vgNum[i + 1]; t++) // mark all equal groups (including this one) as duplicates
  508.                         if (vertGroup[t] == vertGroup[m])
  509.                             vgUsed[t] = true;
  510.                 }
  511.             }
  512.  
  513.             if (newVertCount == obj.vertCount)
  514.                 gotSmoothGroups = false;
  515.         }
  516.  
  517.         if (gotSmoothGroups) {
  518.             // reindex all vertices, build new normals
  519.             int newIndex = 0;
  520.             int[] vertIndex = new int[faceCount*3]; // new vertex indices
  521.             float[] newVertexBuffer = new float[newVertCount*8];
  522.  
  523.             for (i = 0, idx = 0; i < faceCount; i++, idx += 3)
  524.                 for (t = 0; t < 3; t++)
  525.                     vertIndex[idx + t] = 0;
  526.  
  527.             idx = 3;
  528.             for (i = 0; i < obj.vertCount; i++) {
  529.                 for (t = 0; t < vgUniqs[i]; t++) { // for every unique normal and face of this vertex
  530.                     for (m = 0; m < 8; m++)
  531.                         newVertexBuffer[newIndex*8 + m] = obj.vertexBuffer[i*8 + m]; // duplicate all vertex data (including zero normals)
  532.  
  533.                     g = vertUGroup[vgNum[i] + t]; // unique group mask for this vertex
  534.                     for (m = vgNum[i]; m < vgNum[i + 1]; m++) // for every NON-unique normal and face of this vertex
  535.                         if ((vertGroup[m] & g) != 0 || vertGroup[m] == g) // also works for zero group
  536.                             VecAdd(newVertexBuffer, idx, vgNorm, m*3); // add normal to vertex
  537.    
  538.                     vertIndex[vgNum[i] + t] = newIndex;
  539.                     newIndex++;
  540.                     idx += 8;
  541.                 }
  542.             }
  543.  
  544.             int fg, vi;
  545.             for (i = 0, idx = 0; i < faceCount; i++, idx += 3) {
  546.                 fg = faceGroup[i];
  547.                 for (m = 0; m < 3; m++) {
  548.                     vi = faceBuffer[idx + m]; // face vertex
  549.                     for (t = 0; t < vgUniqs[vi]; t++) // for every unique group of this vertex
  550.                         if (fg == vertUGroup[vgNum[vi] + t]) { // found the right one
  551.                             faceBuffer[idx + m] = vertIndex[vgNum[vi] + t];
  552.                             break;
  553.                         }
  554.                 }
  555.             }
  556.  
  557.             obj.vertCount = newVertCount;
  558.             obj.vertexBuffer = newVertexBuffer;
  559.         }
  560.         else // nothing changed, no need to recalculate anything
  561.             for (i = 0, idx = 3; i < obj.vertCount; i++, idx += 8) // just copy all the normals
  562.                 for (m = vgNum[i]; m < vgNum[i + 1]; m++) // for every NON-unique normal and face of this vertex
  563.                     VecAdd(obj.vertexBuffer, idx, vgNorm, m*3); // add normal to vertex
  564.  
  565.         for (i = 0, k = 3; i < obj.vertCount; i++, k += 8)
  566.             VecNormalize(obj.vertexBuffer, k);
  567.  
  568.         for (m = 0; m < obj.faceMats.size(); m++) {
  569.             FaceMat mat = obj.faceMats.get(m);
  570.             k = 0;
  571.             for (i = 0; i < mat.indCount; i++)
  572.                 for (t = 0; t < 3; t++) {
  573.                     j = mat.indexBuffer[k];
  574.                     mat.indexBuffer[k++] = faceBuffer[j + t];
  575.                 }
  576.         }
  577.  
  578.         if (unused > 0) {
  579.             FaceMat mat = new FaceMat();
  580.             mat.indexBuffer = new int[3*unused];
  581.             mat.bufOffset = obj.indCount;
  582.             obj.indCount += 3*unused;
  583.             k = 0;
  584.             for (i = 0; i < faceCount; i++)
  585.                 if (!faceUsed[i]) {
  586.                     faceUsed[i] = true;
  587.                     j = i * 3;
  588.                     for (t = 0; t < 3; t++)
  589.                         mat.indexBuffer[k++] = faceBuffer[j + t];
  590.                 }
  591.             obj.faceMats.add(mat);
  592.         }
  593.     }
  594.  
  595.     private Light3D ChunkLight(int len, String name) throws IOException
  596.     {
  597.         long end = filePos + len;
  598.  
  599.         Light3D light = new Light3D();
  600.         light.name = name;
  601.         light.pos = new float[3];
  602.         ChunkVector(light.pos, 0);
  603.  
  604.         while (filePos < end) {
  605.             int chunkID = ReadUnsignedShort();
  606.             int chunkLen = ReadInt() - 6;
  607.  
  608.             switch (chunkID) {
  609.             case CHUNK_RGBC:
  610.                 light.color = new float[4];
  611.                 ChunkRGBC(light.color);
  612.                 break;
  613.  
  614.             case CHUNK_RGB24:
  615.                 light.color = new float[4];
  616.                 ChunkRGB24(light.color);
  617.                 break;
  618.  
  619.             case CHUNK_SPOTL:
  620.                 light.dir = new float[4];
  621.                 ChunkVector(light.dir, 0);
  622.                 light.theta = (float) (ReadFloat() * Math.PI / 180.0f);
  623.                 light.phi = (float) (ReadFloat() * Math.PI / 180.0f);
  624.                 break;
  625.  
  626.             case CHUNK_ONOFF:
  627.             default:
  628.                 Skip(chunkLen);
  629.             }
  630.         }
  631.         Seek(end);
  632.  
  633.         return light;
  634.     }
  635.  
  636.     private Material3D ChunkMaterial(Scene3D scene, int len) throws IOException
  637.     {
  638.         long end = filePos + len;
  639.  
  640.         Material3D mat = new Material3D();
  641.  
  642.         while (filePos < end) {
  643.             int chunkID = ReadUnsignedShort();
  644.             int chunkLen = ReadInt() - 6;
  645.  
  646.             switch (chunkID) {
  647.             case CHUNK_TEXTURE:
  648.                 mat.texture = ChunkMap(chunkLen);
  649.                 break;
  650.  
  651.             case CHUNK_BUMPMAP:
  652.             case CHUNK_REFLMAP:
  653.                 ChunkMap(chunkLen);
  654.                 break;
  655.  
  656.             case CHUNK_AMBIENT:
  657.                 mat.ambient = new float[4];
  658.                 ChunkColor(chunkLen, mat.ambient);
  659.                 break;
  660.  
  661.             case CHUNK_DIFFUSE:
  662.                 mat.diffuse = new float[4];
  663.                 ChunkColor(chunkLen, mat.diffuse);
  664.                 break;
  665.  
  666.             case CHUNK_SPECULAR:
  667.                 mat.specular = new float[4];
  668.                 ChunkColor(chunkLen, mat.specular);
  669.                 break;
  670.  
  671.             case CHUNK_MATNAME:
  672.                 mat.name = ChunkName(chunkLen);
  673.                 break;
  674.  
  675.             case CHUNK_MTLTYPE:
  676.                 mat.type = ReadUnsignedShort();
  677.                 break;
  678.  
  679.             case CHUNK_SHININES:
  680.                 mat.shininess = 100 - ChunkPercent(chunkLen);
  681.                 break;
  682.  
  683.             case CHUNK_SHINSTRN:
  684.                 mat.shinStren = ChunkPercent(chunkLen);
  685.                 break;
  686.  
  687.             case CHUNK_TRANSP:
  688.                 mat.transparency = ChunkPercent(chunkLen);
  689.                 break;
  690.  
  691.             case CHUNK_SELFILL:
  692.                 mat.selfIllum = ChunkPercent(chunkLen);
  693.                 break;
  694.  
  695.             default:
  696.                 Skip(chunkLen);
  697.             }
  698.         }
  699.         Seek(end);
  700.  
  701.         return mat;
  702.     }
  703.  
  704.     private String ChunkMap(int len) throws IOException
  705.     {
  706.         long end = filePos + len;
  707.  
  708.         String name = null;
  709.  
  710.         while (filePos < end) {
  711.             int chunkID = ReadUnsignedShort();
  712.             int chunkLen = ReadInt() - 6;
  713.  
  714.             switch (chunkID) {
  715.             case CHUNK_MAPFILE:
  716.                 name = ChunkName(chunkLen);
  717.                 break;
  718.  
  719.             case CHUNK_MAPPARAM:
  720.             default:
  721.                 Skip(chunkLen);
  722.             }
  723.         }
  724.         Seek(end);
  725.  
  726.         return name;
  727.     }
  728.  
  729.     private void ChunkKeyframer(Scene3D scene, int len) throws IOException
  730.     {
  731.         int fstart = 0, fend = 100;
  732.  
  733.         long end = filePos + len;
  734.         while (filePos < end) {
  735.             int chunkID = ReadUnsignedShort();
  736.             int chunkLen = ReadInt() - 6;
  737.  
  738.             switch (chunkID) {
  739.             case CHUNK_FRAMES:
  740.                 fstart = ReadInt();
  741.                 fend = ReadInt();
  742.                 break;
  743.  
  744.             case CHUNK_TRACKINFO:
  745.                 Animation anim = ChunkMeshTrack(chunkLen, scene);
  746.                 if (anim != null)
  747.                     scene.animations.add(anim);
  748.                 break;
  749.  
  750.             case CHUNK_SPOTINFO:
  751.             default:
  752.                 Skip(chunkLen);
  753.             }
  754.         }
  755.  
  756.         if (fstart < fend)
  757.             for (int i = 0; i < scene.animations.size(); i++) {
  758.                 Animation anim = scene.animations.get(i);
  759.                 if (anim.position != null)
  760.                     for (int j = 0; j < anim.position.length; j++)
  761.                         anim.position[j].time = (anim.position[j].time - fstart) / (fend - fstart);
  762.                 if (anim.rotation != null)
  763.                     for (int j = 0; j < anim.rotation.length; j++)
  764.                         anim.rotation[j].time = (anim.rotation[j].time - fstart) / (fend - fstart);
  765.                 if (anim.scaling != null)
  766.                     for (int j = 0; j < anim.scaling.length; j++)
  767.                         anim.scaling[j].time = (anim.scaling[j].time - fstart) / (fend - fstart);
  768.             }
  769.  
  770.         Seek(end);
  771.     }
  772.  
  773.     private Animation ChunkMeshTrack(int len, Scene3D scene) throws IOException
  774.     {
  775.         Animation anim = new Animation();
  776.         int num, i, j, k;
  777.  
  778.         anim.result = new float[16];
  779.         Matrix.setIdentityM(anim.result, 0);
  780.  
  781.         anim.world = new float[16];
  782.         Matrix.setIdentityM(anim.world, 0);
  783.  
  784.         long end = filePos + len;
  785.         while (filePos < end) {
  786.             int chunkID = ReadUnsignedShort();
  787.             int chunkLen = ReadInt() - 6;
  788.  
  789.             switch (chunkID) {
  790.             case CHUNK_HIERARCHY:
  791.                 anim.id = ReadUnsignedShort();
  792.                 break;
  793.  
  794.             case CHUNK_OBJNAME:
  795.                 String name = ChunkName(0);
  796.                 anim.light = scene.FindLight(name);
  797.                 anim.object = scene.FindObject(name);
  798.                 Skip(4);
  799.                 anim.parent = scene.FindAnimation(ReadUnsignedShort());
  800.                 break;
  801.  
  802.             case CHUNK_PIVOT:
  803.                 anim.pivot = new float[3];
  804.                 ChunkVector(anim.pivot, 0);
  805.                 break;
  806.  
  807.             case CHUNK_TRACKPOS:
  808.                 Skip(10);
  809.                 num = ReadInt();
  810.                 anim.position = new AnimKey[num];
  811.                 for (i = 0; i < num; i++) {
  812.                     anim.position[i] = new AnimKey();
  813.                     anim.position[i].time = ReadInt();
  814.                     k = ReadUnsignedShort();
  815.                     for (j = 0; j < 5; j++)
  816.                         if ((k & (1 << j)) != 0)
  817.                             Skip(4);
  818.                     anim.position[i].data = new float[3];
  819.                     ChunkVector(anim.position[i].data, 0);
  820.                 }
  821.                 break;
  822.  
  823.             case CHUNK_TRACKROT:
  824.                 Skip(10);
  825.                 num = ReadInt();
  826.                 anim.rotation = new AnimKey[num];
  827.                 for (i = 0; i < num; i++) {
  828.                     anim.rotation[i] = new AnimKey();
  829.                     anim.rotation[i].time = ReadInt();
  830.                     k = ReadUnsignedShort();
  831.                     for (j = 0; j < 5; j++)
  832.                         if ((k & (1 << j)) != 0)
  833.                             Skip(4);
  834.                     anim.rotation[i].data = new float[4];
  835.                     anim.rotation[i].data[3] = ReadFloat();
  836.                     ChunkVector(anim.rotation[i].data, 0);
  837.                 }
  838.                 break;
  839.  
  840.             case CHUNK_TRACKSCL:
  841.                 Skip(10);
  842.                 num = ReadInt();
  843.                 anim.scaling = new AnimKey[num];
  844.                 for (i = 0; i < num; i++) {
  845.                     anim.scaling[i] = new AnimKey();
  846.                     anim.scaling[i].time = ReadInt();
  847.                     k = ReadUnsignedShort();
  848.                     for (j = 0; j < 5; j++)
  849.                         if ((k & (1 << j)) != 0)
  850.                             Skip(4);
  851.                     anim.scaling[i].data = new float[3];
  852.                     ChunkVector(anim.scaling[i].data, 0);
  853.                 }
  854.                 break;
  855.  
  856.             default:
  857.                 Skip(chunkLen);
  858.             }
  859.         }
  860.         Seek(end);
  861.  
  862.         return anim;
  863.     }
  864.  
  865.     private void ChunkColor(int len, float[] color) throws IOException
  866.     {
  867.         long end = filePos + len;
  868.         while (filePos < end) {
  869.             int chunkID = ReadUnsignedShort();
  870.             int chunkLen = ReadInt() - 6;
  871.  
  872.             switch (chunkID) {
  873.             case CHUNK_RGBC:
  874.                 ChunkRGBC(color);
  875.                 break;
  876.  
  877.             case CHUNK_RGB24:
  878.                 ChunkRGB24(color);
  879.                 break;
  880.  
  881.             default:
  882.                 Skip(chunkLen);
  883.             }
  884.         }
  885.         Seek(end);
  886.     }
  887.  
  888.     private float ChunkPercent(int len) throws IOException
  889.     {
  890.         float v = 0;
  891.  
  892.         long end = filePos + len;
  893.         while (filePos < end) {
  894.             int chunkID = ReadUnsignedShort();
  895.             int chunkLen = ReadInt() - 6;
  896.  
  897.             switch (chunkID) {
  898.             case CHUNK_SHORT:
  899.                 v = ReadUnsignedShort() / 100.0f;
  900.                 break;
  901.  
  902.             default:
  903.                 Skip(chunkLen);
  904.             }
  905.         }
  906.         Seek(end);
  907.  
  908.         return v;
  909.     }
  910.  
  911.     private String ChunkName(int len) throws IOException
  912.     {
  913.         long end = filePos + len;
  914.         int slen = 0;
  915.         byte[] buffer = new byte[128];
  916.         byte c;
  917.  
  918.         do {
  919.             c = ReadByte();
  920.             if (c != 0)
  921.                 buffer[slen++] = c;
  922.         } while (c != 0);
  923.  
  924.         if (len != 0)
  925.             Seek(end);
  926.  
  927.         String name = new String(buffer, 0, slen);
  928.  
  929.         return name;
  930.     }
  931.  
  932.     private void ChunkVector(float[] vec, int offset) throws IOException
  933.     {
  934.         vec[offset + 0] = ReadFloat();
  935.         vec[offset + 2] = ReadFloat();
  936.         vec[offset + 1] = ReadFloat();
  937.     }
  938.  
  939.     private void ChunkRGBC(float[] c) throws IOException
  940.     {
  941.         c[0] = ReadFloat();
  942.         c[1] = ReadFloat();
  943.         c[2] = ReadFloat();
  944.         c[3] = 1;
  945.     }
  946.  
  947.     private void ChunkRGB24(float[] c) throws IOException
  948.     {
  949.         c[0] = ReadUnsignedByte() / 255.0f;
  950.         c[1] = ReadUnsignedByte() / 255.0f;
  951.         c[2] = ReadUnsignedByte() / 255.0f;
  952.         c[3] = 1;
  953.     }
  954. }
Advertisement
Add Comment
Please, Sign In to add comment