public void calcCellPositions() {
    float deltaA = bag.tileSizeX + bag.tileGap;
    float deltaD = bag.tileSizeZ + bag.tileGap;
    float deltaH = 1.01f * bag.tileSizeY;
    float minA = -(nbrAcross - 1) * 0.5f * deltaA;
    float minD = -(nbrDown - 1) * 0.5f * deltaD;
    float minH = -0.5f * deltaH;

    for (int a = 0; a < 2 * nbrAcross; a++)
      for (int d = 0; d < 2 * nbrDown; d++)
        for (int h = 0; h < nbrHigh; h++) {
          cell[a][d][h].x = minA + a * 0.5f * deltaA;
          cell[a][d][h].z = minD + d * 0.5f * deltaD;
          cell[a][d][h].y = minH - h * deltaH;
        }
    // Calculate table size
    float tSize = 1.08f * PApplet.max(nbrAcross * deltaA, nbrDown * deltaD);
    float tHeight = 1.0f;
    table = new Box(app, tSize, tHeight, tSize);
    table.pickable(false);
    table.moveBy(0, 0.51f * tHeight, 0);
    // Now get camera nearest approach distance to avoid
    // P3D clipping problems
    nearestApproach = tSize / 1.1f;
  }
 public void placeTiles() {
   map.clear();
   undoList.clear();
   bag.reset();
   Cell aCell;
   Box aTile;
   for (int a = 0; a < 2 * nbrAcross; a++)
     for (int d = 0; d < 2 * nbrDown; d++)
       for (int h = 0; h < nbrHigh; h++) {
         aCell = cell[a][d][h];
         if (aCell.tileReqd) {
           aTile = bag.nextTile();
           aTile.visible(true);
           aTile.pickable(true);
           aTile.moveTo(aCell.x, aCell.y, aCell.z);
           aCell.currTile = aTile;
           aCell.undoTile = null;
           map.put(aTile, aCell);
         }
       }
 }
 public void setTableColor(int c) {
   table.fill(c);
 }
 public void makeUndo() {
   currTile = undoTile;
   currTile.visible(true);
   undoTile = null;
 }
 public void makeRemoved() {
   currTile.visible(false);
   undoTile = currTile;
   currTile = null;
 }
 public void draw() {
   table.draw();
   for (int i = 0; i < bag.tiles.length; i++) bag.tiles[i].draw();
 }