#include "TVirtualGL.h"
#include "KeySymbols.h"
#include "TVirtualX.h"
#include "Buttons.h"
#include "TString.h"
#include "TROOT.h"
#include "TColor.h"
#include "TMath.h"
#include "TH1.h"
#include "TF3.h"
#include "TGLOrthoCamera.h"
#include "TGLTF3Painter.h"
#include "TGLIncludes.h"
ClassImp(TGLTF3Painter)
TGLTF3Painter::TGLTF3Painter(TF3 *fun, TH1 *hist, TGLOrthoCamera *camera,
                             TGLPlotCoordinates *coord, TGLPaintDevice *dev)
                  : TGLPlotPainter(hist, camera, coord, dev, kTRUE, kTRUE, kTRUE),
                    fStyle(kDefault),
                    fF3(fun),
                    fXOZSlice("XOZ", (TH3 *)hist, fun, coord, &fBackBox, TGLTH3Slice::kXOZ),
                    fYOZSlice("YOZ", (TH3 *)hist, fun, coord, &fBackBox, TGLTH3Slice::kYOZ),
                    fXOYSlice("XOY", (TH3 *)hist, fun, coord, &fBackBox, TGLTH3Slice::kXOY)
{
   
}
char *TGLTF3Painter::GetPlotInfo(Int_t , Int_t )
{
   
   return "fun3";
}
namespace {
   void MarchingCube(Double_t x, Double_t y, Double_t z, Double_t stepX, Double_t stepY,
                     Double_t stepZ, Double_t scaleX, Double_t scaleY, Double_t scaleZ,
                     const TF3 *fun, std::vector<TGLTF3Painter::TriFace_t> &mesh,
                     Rgl::Range_t &minMax);
}
Bool_t TGLTF3Painter::InitGeometry()
{
   
   fCoord->SetCoordType(kGLCartesian);
   if (!fCoord->SetRanges(fHist, kFALSE, kTRUE))
      return kFALSE;
   fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
   if (fCamera) fCamera->SetViewVolume(fBackBox.Get3DBox());
   
   fMesh.clear();
   const Int_t nX = fHist->GetNbinsX();
   const Int_t nY = fHist->GetNbinsY();
   const Int_t nZ = fHist->GetNbinsZ();
   const Double_t xMin = fXAxis->GetBinLowEdge(fXAxis->GetFirst());
   const Double_t xStep = (fXAxis->GetBinUpEdge(fXAxis->GetLast()) - xMin) / nX;
   const Double_t yMin = fYAxis->GetBinLowEdge(fYAxis->GetFirst());
   const Double_t yStep = (fYAxis->GetBinUpEdge(fYAxis->GetLast()) - yMin) / nY;
   const Double_t zMin = fZAxis->GetBinLowEdge(fZAxis->GetFirst());
   const Double_t zStep = (fZAxis->GetBinUpEdge(fZAxis->GetLast()) - zMin) / nZ;
   Rgl::Range_t minMax;
   minMax.first  = fF3->Eval(xMin, yMin, zMin);
   minMax.second = minMax.first;
   for (Int_t i = 0; i < nX; ++i) {
      for (Int_t j= 0; j < nY; ++j) {
         for (Int_t k = 0; k < nZ; ++k) {
            MarchingCube(xMin + i * xStep, yMin + j * yStep, zMin + k * zStep,
                         xStep, yStep, zStep, fCoord->GetXScale(), fCoord->GetYScale(),
                         fCoord->GetZScale(), fF3, fMesh, minMax);
         }
      }
   }
   
   minMax.second = 0.001 * minMax.first;
   fXOZSlice.SetMinMax(minMax);
   fYOZSlice.SetMinMax(minMax);
   fXOYSlice.SetMinMax(minMax);
   if (fCoord->Modified()) {
      fUpdateSelection = kTRUE;
      const TGLVertex3 &vertex = fBackBox.Get3DBox()[0];
      fXOZSectionPos = vertex.Y();
      fYOZSectionPos = vertex.X();
      fXOYSectionPos = vertex.Z();
      fCoord->ResetModified();
   }
   return kTRUE;
}
void TGLTF3Painter::StartPan(Int_t px, Int_t py)
{
   
   fMousePosition.fX = px;
   fMousePosition.fY = fCamera->GetHeight() - py;
   fCamera->StartPan(px, py);
   fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
}
void TGLTF3Painter::Pan(Int_t px, Int_t py)
{
   
   
   if (!MakeGLContextCurrent())
      return;
   if (fSelectedPart >= fSelectionBase)
      fCamera->Pan(px, py);
   else if (fSelectedPart > 0) {
      
      
      py = fCamera->GetHeight() - py;
      if (!fHighColor) {
         if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
            fBoxCut.MoveBox(px, py, fSelectedPart);
         else
            MoveSection(px, py);
      } else {
         MoveSection(px, py);
      }
   }
   fMousePosition.fX = px, fMousePosition.fY = py;
   fUpdateSelection = kTRUE;
}
void TGLTF3Painter::AddOption(const TString &)
{
   
}
void TGLTF3Painter::ProcessEvent(Int_t event, Int_t , Int_t py)
{
   
   if (event == kKeyPress) {
      if (py == kKey_s || py == kKey_S) {
         fStyle < kMaple2 ? fStyle = ETF3Style(fStyle + 1) : fStyle = kDefault;
      } else if (py == kKey_c || py == kKey_C) {
         if (fHighColor)
            Info("ProcessEvent", "Cut box does not work in high color, please, switch to true color");
         else {
            fBoxCut.TurnOnOff();
            fUpdateSelection = kTRUE;
         }
      }
   } else if (event == kButton1Double && (fBoxCut.IsActive() || HasSections())) {
      if (fBoxCut.IsActive())
         fBoxCut.TurnOnOff();
      const TGLVertex3 *frame = fBackBox.Get3DBox();
      fXOZSectionPos = frame[0].Y();
      fYOZSectionPos = frame[0].X();
      fXOYSectionPos = frame[0].Z();
      if (!gVirtualX->IsCmdThread())
         gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%x)->Paint()", this));
      else
         Paint();
   }
}
void TGLTF3Painter::InitGL()const
{
   
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_DEPTH_TEST);
   glDisable(GL_CULL_FACE);
   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}
namespace {
   void GetColor(Double_t *color, const TGLVector3 &normal);
}
void TGLTF3Painter::DrawPlot()const
{
   
   fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
   DrawSections();
   if (!fSelectionPass && HasSections() && fStyle < kMaple2) {
      
      
      
      
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glDepthMask(GL_FALSE);
   }
   
   if (!fSelectionPass)
      fStyle > kDefault ? glDisable(GL_LIGHTING) : SetSurfaceColor();
   if (fStyle == kMaple1) {
      glEnable(GL_POLYGON_OFFSET_FILL);
      glPolygonOffset(1.f, 1.f);
   } else if (fStyle == kMaple2)
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
   if (!fBoxCut.IsActive()) {
      glBegin(GL_TRIANGLES);
      Double_t color[] = {0., 0., 0., 0.15};
      if (!fSelectionPass) {
         for (UInt_t i = 0, e = fMesh.size(); i < e; ++i) {
            glNormal3dv(fMesh[i].fNormals[0].CArr());
            GetColor(color, fMesh[i].fNormals[0]);
            glColor4dv(color);
            glVertex3dv(fMesh[i].fXYZ[0].CArr());
            glNormal3dv(fMesh[i].fNormals[1].CArr());
            GetColor(color, fMesh[i].fNormals[1]);
            glColor4dv(color);
            glVertex3dv(fMesh[i].fXYZ[1].CArr());
            glNormal3dv(fMesh[i].fNormals[2].CArr());
            GetColor(color, fMesh[i].fNormals[2]);
            glColor4dv(color);
            glVertex3dv(fMesh[i].fXYZ[2].CArr());
         }
      } else {
         Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
         for (UInt_t i = 0, e = fMesh.size(); i < e; ++i) {
            glVertex3dv(fMesh[i].fXYZ[0].CArr());
            glVertex3dv(fMesh[i].fXYZ[1].CArr());
            glVertex3dv(fMesh[i].fXYZ[2].CArr());
         }
      }
      glEnd();
      if (fStyle == kMaple1 && !fSelectionPass) {
         glDisable(GL_POLYGON_OFFSET_FILL);
         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
         glColor4d(0., 0., 0., 0.25);
         glBegin(GL_TRIANGLES);
         for (UInt_t i = 0, e = fMesh.size(); i < e; ++i) {
            glVertex3dv(fMesh[i].fXYZ[0].CArr());
            glVertex3dv(fMesh[i].fXYZ[1].CArr());
            glVertex3dv(fMesh[i].fXYZ[2].CArr());
         }
         glEnd();
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      } else if (fStyle == kMaple2)
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      if (fStyle > kDefault && !fSelectionPass)
         glEnable(GL_LIGHTING); 
   } else {
      glBegin(GL_TRIANGLES);
      
      Double_t color[] = {0., 0., 0., 0.15};
      if (!fSelectionPass) {
         for (UInt_t i = 0, e = fMesh.size(); i < e; ++i) {
            const TriFace_t &tri = fMesh[i];
            const Double_t xMin = TMath::Min(TMath::Min(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t xMax = TMath::Max(TMath::Max(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t yMin = TMath::Min(TMath::Min(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t yMax = TMath::Max(TMath::Max(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t zMin = TMath::Min(TMath::Min(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            const Double_t zMax = TMath::Max(TMath::Max(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
               continue;
            glNormal3dv(tri.fNormals[0].CArr());
            GetColor(color, tri.fNormals[0]);
            glColor4dv(color);
            glVertex3dv(tri.fXYZ[0].CArr());
            glNormal3dv(tri.fNormals[1].CArr());
            GetColor(color, tri.fNormals[1]);
            glColor4dv(color);
            glVertex3dv(tri.fXYZ[1].CArr());
            glNormal3dv(tri.fNormals[2].CArr());
            GetColor(color, tri.fNormals[2]);
            glColor4dv(color);
            glVertex3dv(tri.fXYZ[2].CArr());
         }
      } else {
         Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
         for (UInt_t i = 0, e = fMesh.size(); i < e; ++i) {
            const TriFace_t &tri = fMesh[i];
            const Double_t xMin = TMath::Min(TMath::Min(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t xMax = TMath::Max(TMath::Max(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t yMin = TMath::Min(TMath::Min(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t yMax = TMath::Max(TMath::Max(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t zMin = TMath::Min(TMath::Min(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            const Double_t zMax = TMath::Max(TMath::Max(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
               continue;
            glVertex3dv(tri.fXYZ[0].CArr());
            glVertex3dv(tri.fXYZ[1].CArr());
            glVertex3dv(tri.fXYZ[2].CArr());
         }
      }
      glEnd();
      if (fStyle == kMaple1 && !fSelectionPass) {
         glDisable(GL_POLYGON_OFFSET_FILL);
         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
         glColor4d(0., 0., 0., 0.25);
         glBegin(GL_TRIANGLES);
         for (UInt_t i = 0, e = fMesh.size(); i < e; ++i) {
            const TriFace_t &tri = fMesh[i];
            const Double_t xMin = TMath::Min(TMath::Min(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t xMax = TMath::Max(TMath::Max(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t yMin = TMath::Min(TMath::Min(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t yMax = TMath::Max(TMath::Max(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t zMin = TMath::Min(TMath::Min(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            const Double_t zMax = TMath::Max(TMath::Max(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
               continue;
            glVertex3dv(tri.fXYZ[0].CArr());
            glVertex3dv(tri.fXYZ[1].CArr());
            glVertex3dv(tri.fXYZ[2].CArr());
         }
         glEnd();
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      } else if (fStyle == kMaple2)
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      if (fStyle > kDefault && !fSelectionPass)
         glEnable(GL_LIGHTING); 
      fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
   }
   if (!fSelectionPass && HasSections() && fStyle < kMaple2) {
      glDisable(GL_BLEND);
      glDepthMask(GL_TRUE);
   }
}
void TGLTF3Painter::SetSurfaceColor()const
{
   
   Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.15f};
   if (fF3->GetFillColor() != kWhite)
      if (const TColor *c = gROOT->GetColor(fF3->GetFillColor()))
         c->GetRGB(diffColor[0], diffColor[1], diffColor[2]);
   glMaterialfv(GL_BACK, GL_DIFFUSE, diffColor);
   diffColor[0] /= 2, diffColor[1] /= 2, diffColor[2] /= 2;
   glMaterialfv(GL_FRONT, GL_DIFFUSE, diffColor);
   const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
}
Bool_t TGLTF3Painter::HasSections()const
{
   
   return fXOZSectionPos > fBackBox.Get3DBox()[0].Y() || fYOZSectionPos > fBackBox.Get3DBox()[0].X() ||
          fXOYSectionPos > fBackBox.Get3DBox()[0].Z();
}
void TGLTF3Painter::DrawSectionXOZ()const
{
   
   if (fSelectionPass)
      return;
   fXOZSlice.DrawSlice(fXOZSectionPos / fCoord->GetYScale());
}
void TGLTF3Painter::DrawSectionYOZ()const
{
   
   if (fSelectionPass)
      return;
   fYOZSlice.DrawSlice(fYOZSectionPos / fCoord->GetXScale());
}
void TGLTF3Painter::DrawSectionXOY()const
{
   
   if (fSelectionPass)
      return;
   fXOYSlice.DrawSlice(fXOYSectionPos / fCoord->GetZScale());
}
ClassImp(TGLIsoPainter)
TGLIsoPainter::TGLIsoPainter(TH1 *hist, TGLOrthoCamera *camera, TGLPlotCoordinates *coord, TGLPaintDevice *dev)
                  : TGLPlotPainter(hist, camera, coord, dev, kTRUE, kTRUE, kTRUE),
                    fXOZSlice("XOZ", (TH3 *)hist, coord, &fBackBox, TGLTH3Slice::kXOZ),
                    fYOZSlice("YOZ", (TH3 *)hist, coord, &fBackBox, TGLTH3Slice::kYOZ),
                    fXOYSlice("XOY", (TH3 *)hist, coord, &fBackBox, TGLTH3Slice::kXOY),
                    fInit(kFALSE)
{
   
   if (hist->GetDimension() < 3)
      Error("TGLIsoPainter::TGLIsoPainter", "Wrong type of histogramm, must have 3 dimensions");
}
char *TGLIsoPainter::GetPlotInfo(Int_t , Int_t )
{
   
   return "iso";
}
namespace {
   void MarchingCube(Double_t x, Double_t y, Double_t z, Double_t stepX, Double_t stepY,
                     Double_t stepZ, Double_t scaleX, Double_t scaleY, Double_t scaleZ,
                     const Double_t *funValues, std::vector<TGLIsoPainter::TriFace_t> &mesh,
                     Double_t isoValue);
   inline Double_t Abs(Double_t val)
   {
      if(val < 0.) val *= -1.;
      return val;
   }
   inline Bool_t Eq(const TGLVertex3 &v1, const TGLVertex3 &v2)
   {
      return Abs(v1.X() - v2.X()) < 0.0000001 &&
             Abs(v1.Y() - v2.Y()) < 0.0000001 &&
             Abs(v1.Z() - v2.Z()) < 0.0000001;
   }
}
Bool_t TGLIsoPainter::InitGeometry()
{
   
   if (fHist->GetDimension() < 3) {
      Error("TGLIsoPainter::TGLIsoPainter", "Wrong type of histogramm, must have 3 dimensions");
      return kFALSE;
   }
   
   
   
   if (fInit)
      return kTRUE;
   
   fCoord->SetCoordType(kGLCartesian);
   if (!fCoord->SetRanges(fHist, kFALSE, kTRUE))
      return kFALSE;
   fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
   if (fCamera) fCamera->SetViewVolume(fBackBox.Get3DBox());
   
   if (!fIsos.empty())
      fCache.splice(fCache.begin(), fIsos);
   
   UInt_t nContours = fHist->GetContour();
   if (nContours > 1) {
      fColorLevels.resize(nContours);
      FindMinMax();
      if (fHist->TestBit(TH1::kUserContour)) {
         
         for (UInt_t i = 0; i < nContours; ++i)
            fColorLevels[i] = fHist->GetContourLevelPad(i);
      } else {
         
         const Double_t isoStep = (fMinMax.second - fMinMax.first) / nContours;
         for (UInt_t i = 0; i < nContours; ++i)
            fColorLevels[i] = fMinMax.first + i * isoStep;
      }
      fPalette.GeneratePalette(nContours, fMinMax, kFALSE);
   } else {
      
      fColorLevels.resize(nContours = 1);
      fColorLevels[0] = fHist->GetSumOfWeights() / (fHist->GetNbinsX() * fHist->GetNbinsY() * fHist->GetNbinsZ());
   }
   MeshIter_t firstMesh = fCache.begin();
   
   
   for (UInt_t i = 0; i < nContours; ++i) {
      if (firstMesh != fCache.end()) {
         
         SetMesh(*firstMesh, fColorLevels[i]);
         MeshIter_t next = firstMesh;
         ++next;
         fIsos.splice(fIsos.begin(), fCache, firstMesh);
         firstMesh = next;
      } else {
         
         
         
         
         Mesh_t newMesh;
         SetMesh(newMesh, fColorLevels[i]);
         fIsos.push_back(fDummyMesh);
         fIsos.back().Swap(newMesh);
      }
   }
   if (fCoord->Modified()) {
      fUpdateSelection = kTRUE;
      fXOZSectionPos = fBackBox.Get3DBox()[0].Y();
      fYOZSectionPos = fBackBox.Get3DBox()[0].X();
      fXOYSectionPos = fBackBox.Get3DBox()[0].Z();
      fCoord->ResetModified();
   }
   
   fInit = kTRUE;
   return kTRUE;
}
void TGLIsoPainter::StartPan(Int_t px, Int_t py)
{
   
   fMousePosition.fX = px;
   fMousePosition.fY = fCamera->GetHeight() - py;
   fCamera->StartPan(px, py);
   fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
}
void TGLIsoPainter::Pan(Int_t px, Int_t py)
{
   
   
   
   
   if (!MakeGLContextCurrent())
      return;
   if (fSelectedPart >= fSelectionBase)
      fCamera->Pan(px, py);
   else if (fSelectedPart > 0) {
      
      
      py = fCamera->GetHeight() - py;
      if (!fHighColor) {
         if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
            fBoxCut.MoveBox(px, py, fSelectedPart);
         else
            MoveSection(px, py);
      } else {
         MoveSection(px, py);
      }
   }
   fMousePosition.fX = px, fMousePosition.fY = py;
   fUpdateSelection = kTRUE;
}
void TGLIsoPainter::AddOption(const TString &)
{
   
}
void TGLIsoPainter::ProcessEvent(Int_t event, Int_t , Int_t py)
{
   
   if (event == kKeyPress) {
      if (py == kKey_c || py == kKey_C) {
         if (fHighColor)
            Info("ProcessEvent", "Cut box does not work in high color, please, switch to true color");
         else {
            fBoxCut.TurnOnOff();
            fUpdateSelection = kTRUE;
         }
      }
   } else if (event == kButton1Double && (fBoxCut.IsActive() || HasSections())) {
      if (fBoxCut.IsActive())
         fBoxCut.TurnOnOff();
      const TGLVertex3 *frame = fBackBox.Get3DBox();
      fXOZSectionPos = frame[0].Y();
      fYOZSectionPos = frame[0].X();
      fXOYSectionPos = frame[0].Z();
      if (!gVirtualX->IsCmdThread())
         gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%x)->Paint()", this));
      else
         Paint();
   }
}
void TGLIsoPainter::InitGL()const
{
   
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_DEPTH_TEST);
   glDisable(GL_CULL_FACE);
   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}
void TGLIsoPainter::DrawPlot()const
{
   
   fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
   DrawSections();
   if (fIsos.size() != fColorLevels.size()) {
      Error("TGLIsoPainter::DrawPlot", "Non-equal number of levels and isos");
      return;
   }
   if (!fSelectionPass && HasSections()) {
      
      
      
      
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glDepthMask(GL_FALSE);
   }
   UInt_t colorInd = 0;
   ConstMeshIter_t iso = fIsos.begin();
   for (; iso != fIsos.end(); ++iso, ++colorInd)
      DrawMesh(*iso, colorInd);
   if (!fSelectionPass && HasSections()) {
      glDisable(GL_BLEND);
      glDepthMask(GL_TRUE);
   }
   if (fBoxCut.IsActive())
      fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
}
void TGLIsoPainter::DrawSectionXOZ()const
{
   
   if (fSelectionPass)
      return;
   fXOZSlice.DrawSlice(fXOZSectionPos / fCoord->GetYScale());
}
void TGLIsoPainter::DrawSectionYOZ()const
{
   
   if (fSelectionPass)
      return;
   fYOZSlice.DrawSlice(fYOZSectionPos / fCoord->GetXScale());
}
void TGLIsoPainter::DrawSectionXOY()const
{
   
   if (fSelectionPass)
      return;
   fXOYSlice.DrawSlice(fXOYSectionPos / fCoord->GetZScale());
}
Bool_t TGLIsoPainter::HasSections()const
{
   
   return fXOZSectionPos > fBackBox.Get3DBox()[0].Y() || fYOZSectionPos > fBackBox.Get3DBox()[0].X() ||
          fXOYSectionPos > fBackBox.Get3DBox()[0].Z();
}
void TGLIsoPainter::SetSurfaceColor(Int_t ind)const
{
   
   Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.25f};
   if (fColorLevels.size() == 1) {
      if (fHist->GetFillColor() != kWhite)
         if (const TColor *c = gROOT->GetColor(fHist->GetFillColor()))
            c->GetRGB(diffColor[0], diffColor[1], diffColor[2]);
   } else {
      const UChar_t *color = fPalette.GetColour(ind);
      diffColor[0] = color[0] / 255.;
      diffColor[1] = color[1] / 255.;
      diffColor[2] = color[2] / 255.;
   }
   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
   const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
   diffColor[0] /= 3.5, diffColor[1] /= 3.5, diffColor[2] /= 3.5;
   glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, diffColor);
   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 30.f);
}
void TGLIsoPainter::SetMesh(Mesh_t &m, Double_t isoValue)
{
   
   
   
   
   
   
   
   
   
   
   const Int_t nX = fHist->GetNbinsX();
   const Int_t nY = fHist->GetNbinsY();
   const Int_t nZ = fHist->GetNbinsZ();
   const Double_t xMin      = fXAxis->GetBinCenter(fXAxis->GetFirst());
   const Double_t xStep     = (fXAxis->GetBinCenter(fXAxis->GetLast()) - xMin) / (nX - 1);
   const Double_t yMin      = fYAxis->GetBinCenter(fYAxis->GetFirst());
   const Double_t yStep     = (fYAxis->GetBinCenter(fYAxis->GetLast()) - yMin) / (nY - 1);
   const Double_t zMin      = fZAxis->GetBinCenter(fZAxis->GetFirst());
   const Double_t zStep     = (fZAxis->GetBinCenter(fZAxis->GetLast()) - zMin) / (nZ - 1);
   const Int_t    sliceSize = (nY + 2) * (nZ + 2);
   std::vector<Range_t> &boxRanges = m.fBoxRanges;
   std::vector<TriFace_t> &mesh = m.fMesh;
   boxRanges.assign((nX + 2) * (nY + 2) * (nZ + 2), Range_t());
   
   
   
   for (Int_t i = 0, ir = fXAxis->GetFirst(), ei = fXAxis->GetLast(); ir < ei; ++i, ++ir) {
      for (Int_t j = 0, jr = fYAxis->GetFirst(), ej = fYAxis->GetLast(); jr < ej; ++j, ++jr) {
         for (Int_t k = 0, kr = fZAxis->GetFirst(), ek = fZAxis->GetLast(); kr < ek; ++k, ++kr) {
            const Double_t cube[] = {fHist->GetBinContent(ir, jr, kr),             fHist->GetBinContent(ir + 1, jr, kr),
                                     fHist->GetBinContent(ir + 1, jr + 1, kr),     fHist->GetBinContent(ir, jr + 1, kr),
                                     fHist->GetBinContent(ir, jr, kr + 1),         fHist->GetBinContent(ir + 1, jr, kr + 1),
                                     fHist->GetBinContent(ir + 1, jr + 1, kr + 1), fHist->GetBinContent(ir, jr + 1, kr + 1)};
            Int_t start  = Int_t(mesh.size());
            MarchingCube(xMin + i * xStep, yMin + j * yStep, zMin + k * zStep, xStep, yStep, zStep,
                         fCoord->GetXScale(), fCoord->GetYScale(), fCoord->GetZScale(), cube, mesh,
                         isoValue);
            Int_t finish = Int_t(mesh.size());
            if (start != finish)
               boxRanges[(ir + 1) * sliceSize + (jr + 1) * (nZ + 2) + kr + 1] = Range_t(start, finish);
         }
      }
   }
   for (Int_t i = 1; i <= nX; ++i) {
      for (Int_t j = 1; j <= nY; ++j) {
         for (Int_t k = 1; k <= nZ; ++k) {
            Range_t &box = boxRanges[i * sliceSize + j * (nZ + 2) + k];
            if (box.fFirst != -1) {
               for (Int_t tri = box.fFirst; tri < box.fLast; ++tri) {
                  TriFace_t &face = mesh[tri];
                  
                  for (Int_t k1 = 0; k1 < 3; ++k1) face.fPerVertexNormals[k1] = face.fNormal;
                  const TGLVertex3 &v0 = face.fXYZ[0];
                  const TGLVertex3 &v1 = face.fXYZ[1];
                  const TGLVertex3 &v2 = face.fXYZ[2];
                  for (Int_t tri1 = box.fFirst; tri1 < box.fLast; ++tri1) {
                     if (tri != tri1) {
                        const TriFace_t &testFace = mesh[tri1];
                        if (Eq(v0, testFace.fXYZ[0]))
                           face.fPerVertexNormals[0] += testFace.fNormal;
                        if (Eq(v0, testFace.fXYZ[1]))
                           face.fPerVertexNormals[0] += testFace.fNormal;
                        if (Eq(v0, testFace.fXYZ[2]))
                           face.fPerVertexNormals[0] += testFace.fNormal;
                        if (Eq(v1, testFace.fXYZ[0]))
                           face.fPerVertexNormals[1] += testFace.fNormal;
                        if (Eq(v1, testFace.fXYZ[1]))
                           face.fPerVertexNormals[1] += testFace.fNormal;
                        if (Eq(v1, testFace.fXYZ[2]))
                           face.fPerVertexNormals[1] += testFace.fNormal;
                        if (Eq(v2, testFace.fXYZ[0]))
                           face.fPerVertexNormals[2] += testFace.fNormal;
                        if (Eq(v2, testFace.fXYZ[1]))
                           face.fPerVertexNormals[2] += testFace.fNormal;
                        if (Eq(v2, testFace.fXYZ[2]))
                           face.fPerVertexNormals[2] += testFace.fNormal;
                     }
                  }
                  const Int_t nZ2 = nZ + 2;
                  Range_t &box1  = boxRanges[(i - 1) * sliceSize + (j - 1) * nZ2 + k - 1];
                  CheckBox(mesh, face, box1);
                  Range_t &box2  = boxRanges[(i) * sliceSize + (j - 1) * nZ2 + k - 1];
                  CheckBox(mesh, face, box2);
                  Range_t &box3  = boxRanges[(i + 1) * sliceSize + (j - 1) * nZ2 + k - 1];
                  CheckBox(mesh, face, box3);
                  Range_t &box4  = boxRanges[(i + 1) * sliceSize + (j) * nZ2 + k - 1];
                  CheckBox(mesh, face, box4);
                  Range_t &box5  = boxRanges[(i + 1) * sliceSize + (j + 1) * nZ2 + k - 1];
                  CheckBox(mesh, face, box5);
                  Range_t &box6  = boxRanges[(i) * sliceSize + (j + 1) * nZ2 + k - 1];
                  CheckBox(mesh, face, box6);
                  Range_t &box7  = boxRanges[(i - 1) * sliceSize + (j + 1) * nZ2 + k - 1];
                  CheckBox(mesh, face, box7);
                  Range_t &box8  = boxRanges[(i - 1) * sliceSize + (j) * nZ2 + k - 1];
                  CheckBox(mesh, face, box8);
                  Range_t &box9  = boxRanges[(i) * sliceSize + (j) * nZ2 + k - 1];
                  CheckBox(mesh, face, box9);
                  Range_t &box10  = boxRanges[(i - 1) * sliceSize + (j - 1) * nZ2 + k];
                  CheckBox(mesh, face, box10);
                  Range_t &box11  = boxRanges[(i) * sliceSize + (j - 1) * nZ2 + k];
                  CheckBox(mesh, face, box11);
                  Range_t &box12  = boxRanges[(i + 1) * sliceSize + (j - 1) * nZ2 + k];
                  CheckBox(mesh, face, box12);
                  Range_t &box13  = boxRanges[(i + 1) * sliceSize + (j) * nZ2 + k];
                  CheckBox(mesh, face, box13);
                  Range_t &box14  = boxRanges[(i + 1) * sliceSize + (j + 1) * nZ2 + k];
                  CheckBox(mesh, face, box14);
                  Range_t &box15  = boxRanges[(i) * sliceSize + (j + 1) * nZ2 + k];
                  CheckBox(mesh, face, box15);
                  Range_t &box16  = boxRanges[(i - 1) * sliceSize + (j + 1) * nZ2 + k];
                  CheckBox(mesh, face, box16);
                  Range_t &box17  = boxRanges[(i - 1) * sliceSize + (j) * nZ2 + k];
                  CheckBox(mesh, face, box17);
                  Range_t &box18  = boxRanges[(i - 1) * sliceSize + (j - 1) * nZ2 + k + 1];
                  CheckBox(mesh, face, box18);
                  Range_t &box19  = boxRanges[(i) * sliceSize + (j - 1) * nZ2 + k + 1];
                  CheckBox(mesh, face, box19);
                  Range_t &box20  = boxRanges[(i + 1) * sliceSize + (j - 1) * nZ2 + k + 1];
                  CheckBox(mesh, face, box20);
                  Range_t &box21  = boxRanges[(i + 1) * sliceSize + (j) * nZ2 + k + 1];
                  CheckBox(mesh, face, box21);
                  Range_t &box22  = boxRanges[(i + 1) * sliceSize + (j + 1) * nZ2 + k + 1];
                  CheckBox(mesh, face, box22);
                  Range_t &box23  = boxRanges[(i) * sliceSize + (j + 1) * nZ2 + k + 1];
                  CheckBox(mesh, face, box23);
                  Range_t &box24  = boxRanges[(i - 1) * sliceSize + (j + 1) * nZ2 + k + 1];
                  CheckBox(mesh, face, box24);
                  Range_t &box25  = boxRanges[(i - 1) * sliceSize + (j) * nZ2 + k + 1];
                  CheckBox(mesh, face, box25);
                  Range_t &box26  = boxRanges[(i) * sliceSize + (j) * nZ2 + k + 1];
                  CheckBox(mesh, face, box26);
               }
            }
         }
      }
   }
   for (UInt_t i = 0, ei = mesh.size(); i < ei; ++i) {
      TriFace_t &face = mesh[i];
      if(face.fPerVertexNormals[0].X() || face.fPerVertexNormals[0].Y() || face.fPerVertexNormals[0].Z())
         face.fPerVertexNormals[0].Normalise();
      if(face.fPerVertexNormals[1].X() || face.fPerVertexNormals[1].Y() || face.fPerVertexNormals[1].Z())
         face.fPerVertexNormals[1].Normalise();
      if(face.fPerVertexNormals[2].X() || face.fPerVertexNormals[2].Y() || face.fPerVertexNormals[2].Z())
         face.fPerVertexNormals[2].Normalise();
   }
}
void TGLIsoPainter::DrawMesh(const Mesh_t &mesh, Int_t level)const
{
   
   if (!fSelectionPass)
      SetSurfaceColor(level);
   if (!fBoxCut.IsActive()) {
      glBegin(GL_TRIANGLES);
      if (!fSelectionPass) {
         for (UInt_t i = 0, e = mesh.fMesh.size(); i < e; ++i) {
            glNormal3dv(mesh.fMesh[i].fPerVertexNormals[0].CArr());
            glVertex3dv(mesh.fMesh[i].fXYZ[0].CArr());
            glNormal3dv(mesh.fMesh[i].fPerVertexNormals[1].CArr());
            glVertex3dv(mesh.fMesh[i].fXYZ[1].CArr());
            glNormal3dv(mesh.fMesh[i].fPerVertexNormals[2].CArr());
            glVertex3dv(mesh.fMesh[i].fXYZ[2].CArr());
         }
      } else {
         Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
         for (UInt_t i = 0, e = mesh.fMesh.size(); i < e; ++i) {
            glVertex3dv(mesh.fMesh[i].fXYZ[0].CArr());
            glVertex3dv(mesh.fMesh[i].fXYZ[1].CArr());
            glVertex3dv(mesh.fMesh[i].fXYZ[2].CArr());
         }
      }
      glEnd();
   } else {
      glBegin(GL_TRIANGLES);
      if (!fSelectionPass) {
         for (UInt_t i = 0, e = mesh.fMesh.size(); i < e; ++i) {
            const TriFace_t &tri = mesh.fMesh[i];
            const Double_t xMin = TMath::Min(TMath::Min(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t xMax = TMath::Max(TMath::Max(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t yMin = TMath::Min(TMath::Min(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t yMax = TMath::Max(TMath::Max(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t zMin = TMath::Min(TMath::Min(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            const Double_t zMax = TMath::Max(TMath::Max(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
               continue;
            glNormal3dv(tri.fPerVertexNormals[0].CArr());
            glVertex3dv(tri.fXYZ[0].CArr());
            glNormal3dv(tri.fPerVertexNormals[1].CArr());
            glVertex3dv(tri.fXYZ[1].CArr());
            glNormal3dv(tri.fPerVertexNormals[2].CArr());
            glVertex3dv(tri.fXYZ[2].CArr());
         }
      } else {
         Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
         for (UInt_t i = 0, e = mesh.fMesh.size(); i < e; ++i) {
            const TriFace_t &tri = mesh.fMesh[i];
            const Double_t xMin = TMath::Min(TMath::Min(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t xMax = TMath::Max(TMath::Max(tri.fXYZ[0].X(), tri.fXYZ[1].X()), tri.fXYZ[2].X());
            const Double_t yMin = TMath::Min(TMath::Min(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t yMax = TMath::Max(TMath::Max(tri.fXYZ[0].Y(), tri.fXYZ[1].Y()), tri.fXYZ[2].Y());
            const Double_t zMin = TMath::Min(TMath::Min(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            const Double_t zMax = TMath::Max(TMath::Max(tri.fXYZ[0].Z(), tri.fXYZ[1].Z()), tri.fXYZ[2].Z());
            if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
               continue;
            glVertex3dv(tri.fXYZ[0].CArr());
            glVertex3dv(tri.fXYZ[1].CArr());
            glVertex3dv(tri.fXYZ[2].CArr());
         }
      }
      glEnd();
   }
}
void TGLIsoPainter::CheckBox(const std::vector<TriFace_t> &mesh, TriFace_t &face, const Range_t &box)
{
   
   
   if (box.fFirst == -1)
      return;
   const TGLVertex3 &v0 = face.fXYZ[0];
   const TGLVertex3 &v1 = face.fXYZ[1];
   const TGLVertex3 &v2 = face.fXYZ[2];
   for (Int_t tri1 = box.fFirst; tri1 < box.fLast; ++tri1) {
      const TriFace_t &testFace = mesh[tri1];
      if (Eq(v0, testFace.fXYZ[0]))
         face.fPerVertexNormals[0] += testFace.fNormal;
      if (Eq(v0, testFace.fXYZ[1]))
         face.fPerVertexNormals[0] += testFace.fNormal;
      if (Eq(v0, testFace.fXYZ[2]))
         face.fPerVertexNormals[0] += testFace.fNormal;
      if (Eq(v1, testFace.fXYZ[0]))
         face.fPerVertexNormals[1] += testFace.fNormal;
      if (Eq(v1, testFace.fXYZ[1]))
         face.fPerVertexNormals[1] += testFace.fNormal;
      if (Eq(v1, testFace.fXYZ[2]))
         face.fPerVertexNormals[1] += testFace.fNormal;
      if (Eq(v2, testFace.fXYZ[0]))
         face.fPerVertexNormals[2] += testFace.fNormal;
      if (Eq(v2, testFace.fXYZ[1]))
         face.fPerVertexNormals[2] += testFace.fNormal;
      if (Eq(v2, testFace.fXYZ[2]))
         face.fPerVertexNormals[2] += testFace.fNormal;
   }
}
void TGLIsoPainter::FindMinMax()
{
   
   fMinMax.first  = fHist->GetBinContent(fXAxis->GetFirst(), fYAxis->GetFirst(), fZAxis->GetFirst());
   fMinMax.second = fMinMax.first;
   for (Int_t i = fXAxis->GetFirst(), ei = fXAxis->GetLast(); i <= ei; ++i) {
      for (Int_t j = fYAxis->GetFirst(), ej = fYAxis->GetLast(); j <= ej; ++j) {
         for (Int_t k = fZAxis->GetFirst(), ek = fZAxis->GetLast(); k <= ek; ++k) {
            const Double_t binContent = fHist->GetBinContent(i, j, k);
            fMinMax.first  = TMath::Min(binContent, fMinMax.first);
            fMinMax.second = TMath::Max(binContent, fMinMax.second);
         }
      }
   }
}
namespace {
   
   
   
   const Double_t gA2VertexOffset[8][3] =
   {
      {0., 0., 0.}, {1., 0., 0.}, {1., 1., 0.},
      {0., 1., 0.}, {0., 0., 1.}, {1., 0., 1.},
      {1., 1., 1.}, {0., 1., 1.}
   };
   
   const Int_t gA2EdgeConnection[12][2] =
   {
      {0, 1}, {1, 2}, {2, 3}, {3, 0},
      {4, 5}, {5, 6}, {6, 7}, {7, 4},
      {0,4}, {1,5}, {2,6}, {3,7}
   };
   
   const Double_t gA2EdgeDirection[12][3] =
   {
      {1., 0., 0.}, {0., 1., 0.}, {-1., 0., 0.},
      {0., -1., 0.}, {1., 0., 0.}, {0., 1., 0.},
      {-1., 0., 0.}, {0., -1., 0.}, {0., 0., 1.},
      {0., 0., 1.}, { 0., 0., 1.}, {0., 0., 1.}
   };
   const Float_t gTargetValue = 0.2f;
   
   
   Double_t GetOffset(Double_t val1, Double_t val2, Double_t valDesired)
   {
      Double_t delta = val2 - val1;
      if (!delta)
         return 0.5;
      return (valDesired - val1) / delta;
   }
   
   void GetColor(Double_t *rfColor, const TGLVector3 &normal)
   {
      Double_t x = normal.X();
      Double_t y = normal.Y();
      Double_t z = normal.Z();
      rfColor[0] = (x > 0. ? x : 0.) + (y < 0. ? -0.5 * y : 0.) + (z < 0. ? -0.5 * z : 0.);
      rfColor[1] = (y > 0. ? y : 0.) + (z < 0. ? -0.5 * z : 0.) + (x < 0. ? -0.5 * x : 0.);
      rfColor[2] = (z > 0. ? z : 0.) + (x < 0. ? -0.5 * x : 0.) + (y < 0. ? -0.5 * y : 0.);
   }
   void GetNormal(TGLVector3 &normal, Double_t x, Double_t y, Double_t z, const TF3 *fun)
   {
      normal.X() = fun->Eval(x - 0.01, y, z) - fun->Eval(x + 0.01, y, z);
      normal.Y() = fun->Eval(x, y - 0.01, z) - fun->Eval(x, y + 0.01, z);
      normal.Z() = fun->Eval(x, y, z - 0.01) - fun->Eval(x, y, z + 0.01);
      normal.Normalise();
   }
   void GetNormal(TGLIsoPainter::TriFace_t &face)
   {
      TMath::Normal2Plane(face.fXYZ[0].CArr(), face.fXYZ[1].CArr(), face.fXYZ[2].CArr(), face.fNormal.Arr());
   }
   extern Int_t gCubeEdgeFlags[256];
   extern Int_t gTriangleConnectionTable[256][16];
   
   void MarchingCube(Double_t x, Double_t y, Double_t z, Double_t stepX, Double_t stepY,
                     Double_t stepZ, Double_t scaleX, Double_t scaleY, Double_t scaleZ,
                     const TF3 *fun, std::vector<TGLTF3Painter::TriFace_t> &mesh,
                     Rgl::Range_t &minMax)
   {
      Double_t afCubeValue[8] = {0.};
      TGLVector3 asEdgeVertex[12];
      TGLVector3 asEdgeNorm[12];
      
      for (Int_t iVertex = 0; iVertex < 8; ++iVertex) {
         afCubeValue[iVertex] = fun->Eval(x + gA2VertexOffset[iVertex][0] * stepX,
                                          y + gA2VertexOffset[iVertex][1] * stepY,
                                          z + gA2VertexOffset[iVertex][2] * stepZ);
         minMax.first  = TMath::Min(minMax.first,  afCubeValue[iVertex]);
         minMax.second = TMath::Max(minMax.second, afCubeValue[iVertex]);
      }
      
      Int_t iFlagIndex = 0;
      for (Int_t iVertexTest = 0; iVertexTest < 8; ++iVertexTest) {
         if(afCubeValue[iVertexTest] <= gTargetValue)
            iFlagIndex |= 1<<iVertexTest;
      }
      
      Int_t iEdgeFlags = gCubeEdgeFlags[iFlagIndex];
      
      if (!iEdgeFlags) return;
      
      
      for (Int_t iEdge = 0; iEdge < 12; ++iEdge) {
         
         if (iEdgeFlags & (1<<iEdge)) {
            Double_t offset = GetOffset(afCubeValue[ gA2EdgeConnection[iEdge][0] ],
                                       afCubeValue[ gA2EdgeConnection[iEdge][1] ],
                                       gTargetValue);
            asEdgeVertex[iEdge].X() = x + (gA2VertexOffset[ gA2EdgeConnection[iEdge][0] ][0]  +  offset * gA2EdgeDirection[iEdge][0]) * stepX;
            asEdgeVertex[iEdge].Y() = y + (gA2VertexOffset[ gA2EdgeConnection[iEdge][0] ][1]  +  offset * gA2EdgeDirection[iEdge][1]) * stepY;
            asEdgeVertex[iEdge].Z() = z + (gA2VertexOffset[ gA2EdgeConnection[iEdge][0] ][2]  +  offset * gA2EdgeDirection[iEdge][2]) * stepZ;
            GetNormal(asEdgeNorm[iEdge], asEdgeVertex[iEdge].X(), asEdgeVertex[iEdge].Y(), asEdgeVertex[iEdge].Z(), fun);
         }
      }
      
      for (Int_t iTriangle = 0; iTriangle < 5; iTriangle++) {
         if(gTriangleConnectionTable[iFlagIndex][3 * iTriangle] < 0)
            break;
         TGLTF3Painter::TriFace_t newTri;
         for (Int_t iCorner = 2; iCorner >= 0; --iCorner) {
            Int_t iVertex = gTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];
            newTri.fXYZ[iCorner].X() = asEdgeVertex[iVertex].X() * scaleX;
            newTri.fXYZ[iCorner].Y() = asEdgeVertex[iVertex].Y() * scaleY;
            newTri.fXYZ[iCorner].Z() = asEdgeVertex[iVertex].Z() * scaleZ;
            newTri.fNormals[iCorner] = asEdgeNorm[iVertex];
         }
         mesh.push_back(newTri);
      }
   }
   
   void MarchingCube(Double_t x, Double_t y, Double_t z, Double_t stepX, Double_t stepY,
                     Double_t stepZ, Double_t scaleX, Double_t scaleY, Double_t scaleZ,
                     const Double_t *cube, std::vector<TGLIsoPainter::TriFace_t> &mesh, Double_t isoValue)
   {
      TGLVector3 asEdgeVertex[12];
      
      Int_t iFlagIndex = 0;
      for (Int_t iVertexTest = 0; iVertexTest < 8; ++iVertexTest) {
         if(cube[iVertexTest] <= isoValue)
            iFlagIndex |= 1 << iVertexTest;
      }
      
      Int_t iEdgeFlags = gCubeEdgeFlags[iFlagIndex];
      
      if (!iEdgeFlags)
         return;
      
      
      for (Int_t iEdge = 0; iEdge < 12; ++iEdge) {
         
         if (iEdgeFlags & (1<<iEdge)) {
            Double_t offset = GetOffset(cube[gA2EdgeConnection[iEdge][0]], cube[gA2EdgeConnection[iEdge][1]], isoValue);
            asEdgeVertex[iEdge].X() = x + (gA2VertexOffset[gA2EdgeConnection[iEdge][0]][0] + offset * gA2EdgeDirection[iEdge][0]) * stepX;
            asEdgeVertex[iEdge].Y() = y + (gA2VertexOffset[gA2EdgeConnection[iEdge][0]][1] + offset * gA2EdgeDirection[iEdge][1]) * stepY;
            asEdgeVertex[iEdge].Z() = z + (gA2VertexOffset[gA2EdgeConnection[iEdge][0]][2] + offset * gA2EdgeDirection[iEdge][2]) * stepZ;
         }
      }
      
      for (Int_t iTriangle = 0; iTriangle < 5; iTriangle++) {
         if(gTriangleConnectionTable[iFlagIndex][3 * iTriangle] < 0)
            break;
         TGLIsoPainter::TriFace_t newTri;
         for (Int_t iCorner = 2; iCorner >= 0; --iCorner) {
            Int_t iVertex = gTriangleConnectionTable[iFlagIndex][3 * iTriangle + iCorner];
            newTri.fXYZ[iCorner].X() = asEdgeVertex[iVertex].X() * scaleX;
            newTri.fXYZ[iCorner].Y() = asEdgeVertex[iVertex].Y() * scaleY;
            newTri.fXYZ[iCorner].Z() = asEdgeVertex[iVertex].Z() * scaleZ;
         }
         GetNormal(newTri);
         mesh.push_back(newTri);
      }
   }
   
   
   
   
   
   
   Int_t gCubeEdgeFlags[256]=
   {
      0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
      0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
      0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
      0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
      0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
      0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
      0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
      0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
      0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
      0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
      0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
      0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
      0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
      0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
      0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
      0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
   };
   
   
   
   
   
   
   
   GLint gTriangleConnectionTable[256][16] =
   {
      {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
      {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
      {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
      {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
      {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
      {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
      {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
      {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
      {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
      {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
      {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
      {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
      {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
      {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
      {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
      {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
      {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
      {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
      {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
      {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
      {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
      {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
      {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
      {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
      {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
      {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
      {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
      {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
      {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
      {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
      {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
      {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
      {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
      {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
      {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
      {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
      {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
      {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
      {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
      {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
      {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
      {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
      {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
      {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
      {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
      {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
      {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
      {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
      {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
      {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
      {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
      {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
      {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
      {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
      {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
      {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
      {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
      {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
      {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
      {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
      {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
      {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
      {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
      {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
      {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
      {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
      {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
      {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
      {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
      {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
      {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
      {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
      {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
      {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
      {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
      {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
      {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
      {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
      {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
      {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
      {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
      {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
      {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
      {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
      {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
      {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
      {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
      {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
      {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
      {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
      {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
      {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
      {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
      {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
      {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
      {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
      {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
      {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
      {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
      {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
      {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
      {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
      {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
      {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
      {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
      {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
      {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
      {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
      {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
      {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
      {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
      {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
      {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
      {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
      {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
      {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
      {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
      {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
      {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
      {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
      {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
      {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
      {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
      {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
      {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
      {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
      {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
      {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
      {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
      {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
      {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
      {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
      {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
      {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
      {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
      {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
      {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
      {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
      {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
      {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
      {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
      {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
      {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
      {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
      {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
      {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
      {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
      {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
      {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
      {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
      {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
      {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
      {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
      {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
      {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
      {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
      {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
      {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
      {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
      {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
      {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
      {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
      {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
      {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
      {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
      {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
      {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
      {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
      {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
      {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
      {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
      {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
      {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
      {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
      {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
      {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
      {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
      {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
      {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
      {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
      {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
   };
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.