private int decodeChunk(int prof) {

    int offset = 6;
    int id = getUShort();
    int longueur = getInt();
    if (longueur < 0) return 0;

    this.pushChunk(id);

    /*
    	for(int x=0;x<prof;x++)
    		System.out.print(" ");
    	Log.log(prof + " - ID=" + Integer.toHexString(id) + " LONGUEUR=" + longueur );

    */
    switch (id) {
      case FILE_VERSION:
        {
          long ver = getUInt();
          this.fileVersion = (int) ver;
          // System.out.println("FILE VERSION="+this.fileVersion);
          offset += 4;
        }
        break;

      case KEYFRAME_VERSION:
        {
          long ver = getUInt();
          this.keyFrameVersion = (int) ver;
          offset += 4;
          // System.out.println("KEYFRAME VERSION="+this.keyFrameVersion);
        }
        break;

      case MESH_VERSION:
        {
          long ver = getUInt();
          this.meshVersion = (int) ver;
          offset += 4;
          // System.out.println("MESH VERSION="+this.meshVersion);

        }
        break;
        /*
        case 0x0100:
        {
        	double scl=(double) getFloat();
        	offset+=4;
        	System.out.println("MASTER SCALE="+scl);
        }
        break;
        */

      case UNIT: // MASTER_SCALE 1.0 <=> 1==1inch
        this.unit = getFloat();
        offset += 4;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case BGCOLOR:
        do {
          int colorBId = getUShort();
          int lBColor = getInt();
          offset += 6;
          switch (colorBId) {
            case RGBF:
            case RGBFG:
              this.backgroundColor = readFloatColor();
              offset += 12;
              break;
            case RGBB:
            case RGBBG:
              this.backgroundColor = readByteColor();
              offset += 3;
              break;
          }
        } while (offset < longueur);
        break;

      case OBJECT:
        lastObjectName = getString();
        offset += lastObjectName.length() + 1;

        while (offset < longueur) offset += decodeChunk(prof + 1);

        // TODO: 3DS LOADING MAY BE IT IS NOT NEEDED
        if (cObjet instanceof Mesh3D) {

          //	((Mesh3D)cObjet).buildVertexId();
          //	((Mesh3D)cObjet).buildFaceId();
          //	((Mesh3D)cObjet).removeDuplicateVertices();

          //	((Mesh3D)cObjet).buildFacesNormals();
          //	((Mesh3D)cObjet).buildSphereBoxAndCenter();
          // Auto octree
          //	((Mesh3D)cObjet).buildMesh3DOctree();
        }

        //	if(cObjet!=null)
        // cObjet.build();
        break;

      case OBJECT_HIDDEN:
        ((Mesh3D) cObjet).setVisible(false);
        break;

      case OBJECT_DONT_CAST_SHADOW:
        if (cObjet instanceof Mesh3D) ((Mesh3D) cObjet).setCastShadow(false);
        break;
      case OBJECT_DONT_RECV_SHADOW:
        if (cObjet instanceof Mesh3D) ((Mesh3D) cObjet).setRecvShadow(false);
        break;

      case CAMERA_ATMOS_RANGE:
        float nearAtmosRange = getFloat();
        float farAtmosRange = getFloat();
        offset += 8;
        break;

      case CAMERA:
        {
          cObjet = new Camera3D();
          cObjet.id = -1;
          cObjet.nom = lastObjectName;
          cAxe = new Axis3D();
          cObjet.axes = cAxe;
          tObjets3D[nbObjet] = cObjet;
          nbObjet++;

          float x = getFloat();
          float y = getFloat();
          float z = getFloat();
          float tx = getFloat();
          float ty = getFloat();
          float tz = getFloat();
          float rz = getFloat();
          float focus = getFloat();
          // System.out.println("focal lenght="+focus);
          double FOV = 180.0 * 2.0 * Math.atan(44.1828 / (focus * 2)) / Math.PI;
          // System.out.println("FOV CALC="+FOV);

          cObjet.position.set(x, z, y);
          // cObjet.axes.add(x,z,y);
          // Log.log(cObjet.position.toString());

          cObjet.axes.origine.set(x, z, y);
          cObjet.axes.axeZ.set(tx - x, tz - z, ty - y);
          cObjet.axes.axeX.set(ty - y, 0, -(tx - x));

          cObjet.axes.axeY.copy(cObjet.axes.axeZ).cross(cObjet.axes.axeX);

          cObjet.axes.axeX.normalize();
          cObjet.axes.axeY.normalize();
          cObjet.axes.axeZ.normalize();

          cObjet.rotation.z = rz;
          cObjet.pivot.set(0, 0, 0);

          if (this.meshVersion == 0) focus = (float) ((Camera3D) cObjet).width;
          ((Camera3D) cObjet).focus = focus; // rotation.rz=rz;
          offset += 32;

          // tObjets3D[nbObjet]=new Scene3DObject();
          // nbObjet++;

          while (offset < longueur) offset += decodeChunk(prof + 1);
        }
        break;

      case LIGHT:
        {
          float x = getFloat();
          float y = getFloat();
          float z = getFloat();
          offset += 12;

          while (offset < longueur) offset += decodeChunk(prof + 1);
        }
        break;

      case TRIMESH:
        cObjet = new Mesh3D();
        cObjet.nom = lastObjectName;
        cObjet.id = -1;
        tObjets3D[nbObjet] = cObjet;
        nbObjet++;
        cAxe = new Axis3D();
        while (offset < longueur) offset += decodeChunk(prof + 1);
        cObjet.axes = cAxe;
        break;

      case VERTEXL:
        int nbV = getUShort();
        offset += 2;
        cPoints3D = new Vertex3D[nbV];
        mappingU = new float[nbV];
        mappingV = new float[nbV];

        for (int nV = 0; nV < nbV; nV++) {
          float x = getFloat();
          float y = getFloat();
          float z = getFloat();
          cPoints3D[nV] = new Vertex3D(x, z, y);
          offset += 12;
        }
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case FACEL:
        int nbP = getUShort();
        offset += 2;
        cPolygones3D = new Face3D[nbP];
        for (int nP = 0; nP < nbP; nP++) {
          int p1 = getUShort();
          int p2 = getUShort();
          int p3 = getUShort();
          int info = getUShort();
          Vertex3D p3D[] = new Vertex3D[3];
          p3D[0] = cPoints3D[p3];
          p3D[1] = cPoints3D[p2];
          p3D[2] = cPoints3D[p1];
          cPolygones3D[nP] = new Face3D(p3D[0], p3D[1], p3D[2]);
          cPolygones3D[nP].u0 = mappingU[p3];
          cPolygones3D[nP].v0 = mappingV[p3];
          cPolygones3D[nP].u1 = mappingU[p2];
          cPolygones3D[nP].v1 = mappingV[p2];
          cPolygones3D[nP].u2 = mappingU[p1];
          cPolygones3D[nP].v2 = mappingV[p1];
          offset += 8;
        }

        ((Mesh3D) cObjet).vertices3D = cPoints3D;
        ((Mesh3D) cObjet).faces3D = cPolygones3D;

        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case SMOOTHL:
        int nbpoly = cPolygones3D.length;
        for (int nP = 0; nP < nbpoly; nP++) {
          int nbSmooth = getInt();
          cPolygones3D[nP].smoothGroupMask = nbSmooth;
          offset += 4;
        }
        break;

      case FACEM:
        String nom = getString();
        offset += nom.length() + 1;
        cMateriau = getTempMateriauByName(nom);
        int nbF = getUShort();
        offset += 2;
        for (int nF = 0; nF < nbF; nF++) {
          int numF = getUShort();
          cPolygones3D[numF].material = cMateriau;
          offset += 2;
        }
        while (offset < longueur) offset += decodeChunk(prof + 1);

        break;

      case MAPPINGVL:
        int nbMV = getUShort();
        offset += 2;
        for (int nV = 0; nV < nbMV; nV++) {
          float u = getFloat();
          float v = getFloat();
          mappingU[nV] = u;
          mappingV[nV] = -v;
          offset += 8;
        }
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case OBJAXES:
        double x = getFloat();
        double y = getFloat();
        double z = getFloat();
        cAxe.axeX.set(x, z, y);

        x = getFloat();
        y = getFloat();
        z = getFloat();
        cAxe.axeZ.set(x, z, y);

        x = getFloat();
        y = getFloat();
        z = getFloat();
        cAxe.axeY.set(x, z, y);

        x = getFloat();
        y = getFloat();
        z = getFloat();
        cAxe.origine.set(x, z, y);

        offset += 48;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIAL:
        cMateriau = new Material();
        tMateriaux3D[nbMaterial] = cMateriau;
        nbMaterial++;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIALNAME:
        cMateriau.nom = getString();
        offset += cMateriau.nom.length() + 1;
        while (offset < longueur) offset += decodeChunk(prof + 1);

        break;

      case MATERIALAMBIENTCOLOR:
        do {
          int colorAId = getUShort();
          int lAColor = getInt();
          offset += 6;
          switch (colorAId) {
            case RGBF:
            case RGBFG:
              cMateriau.ambientColor = readFloatColor();
              offset += 12;
              break;
            case RGBB:
            case RGBBG:
              cMateriau.ambientColor = readByteColor();
              offset += 3;
              break;
          }
        } while (offset < longueur);
        break;

      case MATERIALDIFFUSECOLOR:
        do {
          int colorDId = getUShort();
          int lDColor = getInt();
          offset += 6;
          switch (colorDId) {
            case RGBF:
            case RGBFG:
              cMateriau.diffuseColor = readFloatColor();
              offset += 12;
              break;
            case RGBB:
            case RGBBG:
              cMateriau.diffuseColor = readByteColor();
              offset += 3;
              break;
          }
        } while (offset < longueur);
        break;

      case MATERIALSPECULARCOLOR:
        do {

          int colorSId = getUShort();
          int lSColor = getInt();
          offset += 6;
          switch (colorSId) {
            case RGBF:
            case RGBFG:
              cMateriau.specularColor = readFloatColor();
              offset += 12;
              break;
            case RGBB:
            case RGBBG:
              cMateriau.specularColor = readByteColor();
              offset += 3;
              break;
          }
        } while (offset < longueur);
        break;

      case MATERIALSHINEPERCENT:
        int shineId = getUShort();
        int lShine = getInt();
        offset += 6;
        switch (shineId) {
          case PERCENTF:
            cMateriau.specularPower = readFloatPercent();
            offset += 4;
            break;
          case PERCENTI:
            cMateriau.specularPower = readIntPercent();
            offset += 2;
            break;
        }
        break;

      case MATERIALILLUMPERCENT:
        int illumId = getUShort();
        int lIllum = getInt();
        offset += 6;
        switch (illumId) {
          case PERCENTF:
            cMateriau.selfIlluminationLevel = readFloatPercent();
            offset += 4;
            break;
          case PERCENTI:
            cMateriau.selfIlluminationLevel = readIntPercent();
            offset += 2;
            break;
        }
        // Log.log(cMateriau.nom+" emi="+emi);
        break;

      case MATERIALSHINEFPERCENT:
        int shineFId = getUShort();
        int lShineF = getInt();
        offset += 6;
        switch (shineFId) {
          case PERCENTF:
            cMateriau.specularLevel = readFloatPercent() * 255 / 100;
            offset += 4;
            break;
          case PERCENTI:
            cMateriau.specularLevel = (readIntPercent() * 255) / 100;
            offset += 2;
            break;
        }
        break;

      case MATERIALTRANSPERCENT:
        int transId = getUShort();
        int lTrans = getInt();
        offset += 6;
        switch (transId) {
          case PERCENTF:
            cMateriau.alphaLevel = readFloatPercent() * 255 / 100;
            offset += 4;
            break;
          case PERCENTI:
            cMateriau.alphaLevel = (readIntPercent() * 255) / 100;
            offset += 2;
            break;
        }
        break;

      case MATERIALTRANSFPERCENT:
        int transFId = getUShort();
        int lTransF = getInt();
        offset += 6;
        switch (transFId) {
          case PERCENTF:
            cMateriau.alphaFalloff = readFloatPercent() * 255 / 100;
            offset += 4;
            break;
          case PERCENTI:
            cMateriau.alphaFalloff = (readIntPercent() * 255) / 100;
            offset += 2;
            break;
        }
        break;

      case MATERIALTEXTUREDIFF:
        cMapping = new MappingUV();
        cMateriau.mapping = cMapping;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIALTEXTUREBUMP:
        cMapping = new MappingUV();
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIALTEXTUREENV:
        cMapping = new MappingUV();
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIALTEXTUREOPAC:
        cMapping = new MappingUV();
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIALTEXTURESPEC:
        cMapping = new MappingUV();
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIALTEXTURESHIN:
        cMapping = new MappingUV();
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MATERIALTEXTUREILLUM:
        cMapping = new MappingUV();
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MAPPINGFILE:
        String fileName = getString();
        // System.out.println("MAPPINGFILE="+fileName);
        offset += fileName.length() + 1;

        String textureCacheKey = this.ressourcePath + fileName;
        URLTexture nTexture = (URLTexture) textureCache.get(textureCacheKey);
        if (nTexture == null) {
          nTexture = new URLTexture();
          nTexture.nom = fileName;
          nTexture.sourceFile = fileName;
          nTexture.baseURL = this.ressourcePath;
          textureCache.put(textureCacheKey, nTexture);
          this.textures[this.nbTexture++] = nTexture;
        }

        // There cache will cause trouble if same texture used for different kind of map
        if (this.getLastParentChunk() == MATERIALTEXTUREDIFF) {
          nTexture.type = DzzD.TT_RGB;
          cMateriau.diffuseTexture = nTexture;
        }
        if (this.getLastParentChunk() == MATERIALTEXTUREBUMP) {
          nTexture.type = DzzD.TT_HNORMAL;
          cMateriau.bumpNormalTexture = nTexture;
        }
        if (this.getLastParentChunk() == MATERIALTEXTUREENV) {
          nTexture.type = DzzD.TT_ENV;
          cMateriau.envTexture = nTexture;
        }
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MAPPINGOFFSETU:
        float offseMappingU = getFloat();
        offset += 4;
        cMapping.ofsU = offseMappingU;
        break;

      case MAPPINGOFFSETV:
        float offseMappingV = getFloat();
        offset += 4;
        cMapping.ofsV = offseMappingV;
        break;

        /*
         * KEYFRAME BEGIN
         */
      case KEYFHIER:
        // System.out.println("KEYFHIER");
        lastObjectName = getString(); // Name in mesh section
        // System.out.println("Mesh section name="+lastObjectName);
        offset += lastObjectName.length() + 1;

        int info1 = getUShort();
        int info2 = getUShort();
        int idObjetParent = getShort();

        // System.out.println("------- info1: "+info1);
        // System.out.println("------- info2: "+info2);
        // System.out.println("------- idObjetParent parent:("+idObjetParent+")");

        offset += 6;

        if ((this.meshVersion >= 3)
            && ((info1 & 0x4000) == 0)
            && (!lastObjectName.equals("$$$DUMMY"))) {
          // Log.log("------------ Instance From Object" + lastObjectName);
          cObjet = (Scene3DObject) getTempObjetByName(lastObjectName).getClone(false);
          cObjet.nom = "Instance" + nbObjet; // lastObjectName;
          cObjet.id = this.cObjetId;
          tObjets3D[nbObjet] = cObjet;
          nbObjet++;
        } else {
          if (lastObjectName.equals("$$$DUMMY")) {
            // System.out.println("New object");
            cObjet = new Mesh3D();
            cObjet.nom = "$$$DUMMY";
            cObjet.id = this.cObjetId;
            tObjets3D[nbObjet] = cObjet;
            nbObjet++;
          } else {

            this.cObjet = getTempObjetByName(lastObjectName);
            if (this.cObjet instanceof Camera3D) {
              if (getLastParentChunk() == KEYFCAMTARGETFRAME) {
                // System.out.println("TARGET FOR "+lastObjectName);
                // this.cObjet.setTarget(DzzD.newPoint3D());
              }
            }
          }
        }

        // System.out.println("ID objet==" + cObjetId);

        this.cObjet.id = this.cObjetId;
        if (idObjetParent != 65535) {

          Scene3DObject parent = getTempObjetById(idObjetParent);
          if (parent != null) this.cObjet.parent = parent;
          // System.out.println(cObjet.getName()+" is child of "+cObjet.getParent().getName());
        }
        /*
        if(this.cObjet.parent!=null && !lastObjectName.equals("$$$DUMMY"))
        	System.out.println("-" + lastObjectName+"("+ this.cObjet.id +"):parent:("+idObjetParent+")"+this.cObjet.parent.nom);
        */
        while (offset < longueur) offset += decodeChunk(prof + 1);

        break;

      case KEYFNAME: // - Instance objects name.
        String instanceName = getString();
        // Log.log("instanceName="+instanceName);
        cObjet.nom = instanceName;
        offset += instanceName.length() + 1;
        break;

      case KEYFID:
        int idObjet = getUShort();

        offset += 2;
        this.cObjetId = idObjet;
        // System.out.println("ID OBJ="+cObjetId);
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case KEYFTRANS:

        // Read Track Header
        int info = getShort();
        offset += 2;
        for (int niu = 0; niu < 8; niu++) {
          // Read Unknow TrackHeader info 8 byte
          byte infoUnknow = (byte) getByte();
          offset += 1;
        }

        // Read number ok keys
        int nbKey = (int) getUInt();
        offset += 4;

        Point3D cPosition = new Point3D();
        Point3D lastPosition = new Point3D();
        if (this.animators[cObjetId] == null)
          this.animators[cObjetId] = new Scene3DObjectAnimator();

        // Read all track
        for (int xKey = 0; xKey < nbKey; xKey++) {
          // Read the frame number for this key
          int nKey = (int) getUInt();
          offset += 4;

          // Read Spline flag
          int splinef = getShort();
          offset += 2;

          // Read Spline info depending on spline flag
          if ((splinef & 1) != 0) {
            // Read tension
            getFloat();
            offset += 4;
          }
          if ((splinef & 2) != 0) {
            // Read continuity
            getFloat();
            offset += 4;
          }
          if ((splinef & 4) != 0) {
            // Read bias
            getFloat();
            offset += 4;
          }
          if ((splinef & 8) != 0) {
            // Read ease to
            getFloat();
            offset += 4;
          }
          if ((splinef & 16) != 0) {
            // Read ease from
            getFloat();
            offset += 4;
          }

          // Read this key pos (global coordinate
          x = getFloat();
          y = getFloat();
          z = getFloat();
          if (xKey == 0) this.key3DTrans[cObjetId] = new Point3D(x, z, y);

          cPosition.set(x, z, y);
          Point3D position = new Point3D();
          position.copy(cPosition);
          /*
          if(cObjetId!=-1)
          {

          	System.out.println(tObjets3D[cObjetId].getName());
          	System.out.println("pos="+position.toString());
          }
          */

          this.animators[cObjetId].addKeyPosition(nKey * 30, position);
          lastPosition.copy(cPosition);

          offset += 12;
        }
        break;

      case KEYFROT:
        int infor = getShort();
        offset += 2;
        for (int niu = 0; niu < 8; niu++) {
          byte infoUnknow = (byte) getByte();
          offset += 1;
        }
        int nbKeyr = (int) getUInt();
        offset += 4;

        Axis3D cAxis = new Axis3D();
        cAxis.init();
        Point3D cRotation = new Point3D();
        Point3D lastRotation = new Point3D();

        if (this.animators[cObjetId] == null)
          this.animators[cObjetId] = new Scene3DObjectAnimator();

        for (int xKey = 0; xKey < nbKeyr; xKey++) {
          int nKey = (int) getUInt();

          offset += 4;
          int infoAcceleration = getShort();
          offset += 2;
          double a = getFloat();
          offset += 4;
          x = getFloat();
          y = getFloat();
          z = getFloat();

          if (a > Math.PI && xKey != 0) a = 2.0 * Math.PI - a;

          if (xKey == 0) {
            this.key3DRotAng[cObjetId] = a;
            this.key3DRotAxe[cObjetId] = new Point3D(x, z, y);
          }

          cAxis.rotate(a, -x, -z, -y);
          cAxis.getRotationXZY(cRotation);

          Point3D rotation = new Point3D();
          rotation.copy(cRotation);

          this.animators[cObjetId].addKeyRotation(nKey * 30, rotation, new Point3D(-x, -z, -y), a);

          offset += 12;
        }

        break;

      case KEYFZOOM:
        int infoz = getShort();
        offset += 2;
        for (int niu = 0; niu < 8; niu++) {
          byte infoUnknow = (byte) getByte();
          offset += 1;
        }
        int nbKeyz = (int) getUInt();
        offset += 4;
        for (int xKey = 0; xKey < nbKeyz; xKey++) {
          int nKey = (int) getUInt();
          offset += 4;
          int infoAcceleration = getShort();
          offset += 2;
          x = getFloat();
          y = getFloat();
          z = getFloat();
          if (xKey == 0) this.key3DZoom[cObjetId] = new Point3D(x, z, y);
          offset += 12;
        }
        break;

      case KEYFCAMFOVFRAME:
        int infof = getShort();
        offset += 2;
        for (int niu = 0; niu < 8; niu++) {
          byte infoUnknow = (byte) getByte();
          offset += 1;
        }
        int nbKeyf = (int) getUInt();
        offset += 4;
        for (int xKey = 0; xKey < nbKeyf; xKey++) {
          int nKey = (int) getUInt();
          offset += 4;
          int infoAcceleration = getShort();
          offset += 2;
          float fov = getFloat();
          if (this.cObjet instanceof Camera3D) {
            ((Camera3D) this.cObjet).setFOV(fov);
          }

          offset += 4;
        }
        break;

      case KEYFPIVOT:
        x = getFloat();
        y = getFloat();
        z = getFloat();
        offset += 12;
        this.cObjet.pivot.set(x, z, y);
        break;

      case KEYFBOX:
        double x1 = getFloat();
        double y1 = getFloat();
        double z1 = getFloat();
        offset += 12;
        double x2 = getFloat();
        double y2 = getFloat();
        double z2 = getFloat();
        offset += 12;
        this.cObjet.center.set((x1 + x2) * 0.5, (z1 + z2) * 0.5, (y1 + y2) * 0.5);
        break;

      case KEYF3DS:
        this.isKeyFrame = true;
        // System.out.println("KEYF3DS");
        this.cObjetId = 0;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case KEYFHEADERACTIVE:
        long startf = getUInt();
        long endf = getUInt();
        // System.out.println("KEYFRAME START FRAME="+ startf);
        // System.out.println("KEYFRAME END FRAME="+ endf);
        offset += 8;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case KEYFHEADERCURRENT:
        long currentf = getUInt();
        // System.out.println("KEYFRAME CURRENT FRAME="+currentf);
        offset += 4;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case KEYFHEADERGLOBAL:
        this.keyFrameRevision = getShort();
        this.keyFrameFileName = getString();
        this.KeyFrameNbFrame = getUInt();
        offset += 2;
        offset += this.keyFrameFileName.length() + 1;
        offset += 4;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case MAIN3DS:
        this.cObjetId = 0;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case EDIT3DS:
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case KEYFOBJFRAME:
        this.cObjetId++;
        while (offset < longueur) offset += decodeChunk(prof + 1);
        break;

      case KEYFCAMFRAME:
        this.cObjetId++;
        // System.out.println("-----CAMERA-------");
        // System.out.println("ID1="+cObjetId);
        while (offset < longueur) offset += decodeChunk(prof + 1);
        // System.out.println("-----END CAMERA-------");
        break;

      case KEYFCAMTARGETFRAME:
        this.cObjetId++;
        // System.out.println("-----CAMERA TARGET-------");
        // System.out.println("ID1="+cObjetId);
        // MUST DO SPECIAL DECODE OF CHILD TO NOT OVERWRITE CAMERA TRACK POS/ROT

        // while(offset<longueur)
        //	offset+=decodeChunk(prof+1);
        // System.out.println("-----END CAMERA TARGET-------");
        break;

      default:
        break;
    }
    this.setProgress(50 + (50 * this.nbBytesDecoded) / this.data.length);
    skip(id, offset, longueur - offset);
    this.popChunk();
    return longueur;
  }
  private void loadAndDecode() {
    // LOAD 3DS FILE
    this.setAction(IProgressListener.ACTION_FILE_DOWNLOAD);
    ProgressListener pl = new ProgressListener();

    IOManagerAsynch aLoader = new IOManagerAsynch();
    aLoader.downloadData(this.baseURL + this.fileName, getClass(), null, pl, false);
    while (aLoader.running || !pl.getFinished()) {
      this.setProgress((50 * (pl.getProgress()) / pl.getMaximumProgress()));
      try {
        Thread.sleep(5);
      } catch (InterruptedException ie) {
        pl.setFinished(true);
        pl.setError(true);
        return;
      }
    }

    this.data = aLoader.getData();
    if (pl.getError() || this.data == null) {
      this.setError(true);
      this.setFinished(true);
      return;
    }

    // DECODE 3DS FILE
    this.input = new ByteArrayInputStream(this.data);
    this.setProgress(50);
    this.setAction(IProgressListener.ACTION_FILE_DECOMPRESS);
    int offset = 0;
    while (offset < data.length) offset += decodeChunk(0);

    // CREATE SCENE FROM LOADED SCENE (INIT WITH KEYFRAME IF AVAILABLE)
    objets3D = new Scene3DObject[nbObjet + 1];
    objets3D[0] = new Mesh3D();
    objets3D[0].setName(this.fileName);

    double zx = 1;
    double zy = 1;
    double zz = 1;

    for (int nbo = 0; nbo < nbObjet; nbo++) {
      cObjet = tObjets3D[nbo];
      objets3D[nbo + 1] = cObjet;

      Axis3D cAxe = cObjet.axes;
      Point3D o = cAxe.origine;
      Point3D ax = cAxe.axeX;
      Point3D ay = cAxe.axeY;
      Point3D az = cAxe.axeZ;

      // READ ZOOM FROM AXIS
      zx = ax.norm();
      zy = ay.norm();
      zz = az.norm();
      ax.add(o);
      ay.add(o);
      az.add(o);

      // if(cObjet instanceof Camera3D)
      //	System.out.println(cObjet.getPosition().toString());

      // NORMALIZE AXIS
      cAxe.normalize();

      if (cObjet instanceof Mesh3D) {
        Point3D vertex[] = ((Mesh3D) cObjet).vertices3D;
        for (int np = 0; np < vertex.length; np++)
          vertex[np].toLocalAxe(cAxe).zoom(1.0 / zx, 1.0 / zy, 1.0 / zz);
      }

      ax.sub(o);
      ay.sub(o);
      az.sub(o);

      // KEEP AXZ (TO KNOW IF ZOOM NEGATIVE)
      Point3D axz = new Point3D();
      axz.copy(ax).cross(ay);

      // IF ZOOM NEGATIVE INVERT ALL AXIS AND FLIP OBJECT'S FACES NORMALS
      if (az.dot(axz) < 0.0) {
        ax.mul(-1.0);
        ay.mul(-1.0);
        az.mul(-1.0);
        zx = -zx;
        zy = -zy;
        zz = -zz;
      }
      ax.add(o);
      ay.add(o);
      az.add(o);

      // SET OBJECT ROTATION AND PIVOT FROM AXIS
      cObjet.axes.getPosition(cObjet.position);
      cObjet.axes.getRotationXZY(cObjet.rotation);

      // SET OBJECT ZOOM
      cObjet.zoom.set(zx, zy, zz);
    }

    // SET OBJECT AXIS IN WORLD SPACE WITH PIVOT,POSITION,ROTATION
    for (int nbo = 1; nbo < objets3D.length; nbo++) {
      cObjet = objets3D[nbo];
      cObjet.axes.init();
      cObjet.axes.set(cObjet.pivot, cObjet.position, cObjet.rotation);
    }

    // UPDATE OBJECT HIERARCHY
    for (int nbo = 1; nbo < objets3D.length; nbo++) {
      cObjet = objets3D[nbo];
      if (cObjet.parent == null) cObjet.parent = objets3D[0];
      cObjet.setParent(cObjet.parent);
    }

    // UPDATE OBJECT FOR HIERARCHY NEW
    for (int nbo = 1; nbo < objets3D.length; nbo++) {
      cObjet = objets3D[nbo];
      // cObjet.axes.push();
      IAxis3D a = DzzD.newAxis3D();
      a.copy(cObjet.axes);

      if (cObjet.parent == null) cObjet.parent = objets3D[0];
      cObjet.toLocalAxe(cObjet.parent.axes);
      //	if(cObjet.parent instanceof ICamera3D)
      // cObjet.axes.pop();
      cObjet.axes.copy(a);
    }

    try {

      // UPDATE ALL OBJECT WITH FIRST KEYFRAMER KEY
      if (this.isKeyFrame) {
        for (int nbo = 1; nbo < objets3D.length; nbo++) {
          cObjet = objets3D[nbo];
          if (cObjet.id == -1) continue;
          IAxis3D a = DzzD.newAxis3D();
          a.copy(cObjet.axes);
          // cObjet.axes.push();
          Point3D rot = this.key3DRotAxe[cObjet.id];
          if (rot != null) {
            double rota = this.key3DRotAng[cObjet.id];
            cObjet.axes.init();
            cObjet.axes.rotate(rota, -rot.x, -rot.y, -rot.z);
            cObjet.axes.getRotationXZY(cObjet.rotation);
            // cObjet.axes.pop();
            cObjet.axes.copy(a);
          }

          Point3D trans = this.key3DTrans[cObjet.id];
          if (trans != null) {
            cObjet.position.set(trans.x, trans.y, trans.z);
            if (cObjet.parent != null) cObjet.position.add(cObjet.parent.pivot);
          }

          Point3D zoom = this.key3DZoom[cObjet.id];
          if (zoom != null) {
            cObjet.zoom.set(zoom.x, zoom.y, zoom.z);
          }
          cObjet.axes.copy(a);
          // cObjet.axes.pop();
        }
      }

      // Add animator to object
      for (int nbo = 1; nbo < objets3D.length; nbo++) {

        cObjet = objets3D[nbo];
        if (cObjet.id == -1) continue;
        if (this.animators[cObjet.id] != null)
          cObjet.setScene3DObjectAnimator(this.animators[cObjet.id]);
      }

    } catch (ArrayIndexOutOfBoundsException aioobe) {
      Log.log(aioobe);
    } catch (NullPointerException npe) {
      Log.log(npe);
    }

    for (int nbo = 1; nbo < objets3D.length; nbo++) {
      cObjet = objets3D[nbo];
      Point3D zoom = cObjet.zoom;
      cObjet.zoom(zoom.x, zoom.y, zoom.z);
    }

    this.setFinished(true);
    this.setProgress(100);
    return;
  }