private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n, boolean rebatch) {

    if (n instanceof Geometry) {

      if (!isBatch(n) && n.getBatchHint() != BatchHint.Never) {
        Geometry g = (Geometry) n;
        if (!g.isBatched() || rebatch) {
          if (g.getMaterial() == null) {
            throw new IllegalStateException(
                "No material is set for Geometry: "
                    + g.getName()
                    + " please set a material before batching");
          }
          List<Geometry> list = map.get(g.getMaterial());
          if (list == null) {
            // trying to compare materials with the isEqual method
            for (Map.Entry<Material, List<Geometry>> mat : map.entrySet()) {
              if (g.getMaterial().contentEquals(mat.getKey())) {
                list = mat.getValue();
              }
            }
          }
          if (list == null) {
            list = new ArrayList<Geometry>();
            map.put(g.getMaterial(), list);
          }
          g.setTransformRefresh();
          list.add(g);
        }
      }

    } else if (n instanceof Node) {
      for (Spatial child : ((Node) n).getChildren()) {
        if (child instanceof BatchNode) {
          continue;
        }
        gatherGeomerties(map, child, rebatch);
      }
    }
  }
  protected void doBatch() {
    Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>();
    int nbGeoms = 0;

    gatherGeomerties(matMap, this, needsFullRebatch);
    if (needsFullRebatch) {
      for (Batch batch : batches.getArray()) {
        batch.geometry.removeFromParent();
      }
      batches.clear();
      batchesByGeom.clear();
    }
    // only reset maxVertCount if there is something new to batch
    if (matMap.size() > 0) {
      maxVertCount = 0;
    }

    for (Map.Entry<Material, List<Geometry>> entry : matMap.entrySet()) {
      Mesh m = new Mesh();
      Material material = entry.getKey();
      List<Geometry> list = entry.getValue();
      nbGeoms += list.size();
      String batchName = name + "-batch" + batches.size();
      Batch batch;
      if (!needsFullRebatch) {
        batch = findBatchByMaterial(material);
        if (batch != null) {
          list.add(0, batch.geometry);
          batchName = batch.geometry.getName();
          batch.geometry.removeFromParent();
        } else {
          batch = new Batch();
        }
      } else {
        batch = new Batch();
      }
      mergeGeometries(m, list);
      m.setDynamic();

      batch.updateGeomList(list);

      batch.geometry = new Geometry(batchName);
      batch.geometry.setMaterial(material);
      this.attachChild(batch.geometry);

      batch.geometry.setMesh(m);
      batch.geometry.getMesh().updateCounts();
      batch.geometry.getMesh().updateBound();
      batches.add(batch);
    }
    if (batches.size() > 0) {
      needsFullRebatch = false;
    }

    logger.log(
        Level.FINE,
        "Batched {0} geometries in {1} batches.",
        new Object[] {nbGeoms, batches.size()});

    // init the temp arrays if something has been batched only.
    if (matMap.size() > 0) {
      // TODO these arrays should be allocated by chunk instead to avoid recreating them each time
      // the batch is changed.
      // init temp float arrays
      tmpFloat = new float[maxVertCount * 3];
      tmpFloatN = new float[maxVertCount * 3];
      if (useTangents) {
        tmpFloatT = new float[maxVertCount * 4];
      }
    }
  }