// @(#)root/gl:$Name:  $:$Id: TGLRender.cxx,v 1.16 2004/11/24 14:48:02 brun Exp $
// Author:  Timur Pocheptsov  03/08/2004

/*************************************************************************
 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
#ifdef GDK_WIN32
#include "Windows4Root.h"
#endif

#include <algorithm>
#include <utility>
#include <vector>

#include <GL/gl.h>
#include <GL/glu.h>

#include "Rstrstream.h"
#include "TError.h"
#include "TGLSceneObject.h"
#include "TGLRender.h"
#include "TGLCamera.h"

ClassImp(TGLRender)

namespace std {} using namespace std;

const UChar_t gXyz[][8] = {{0x44, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0x44},
                           {0x10, 0x10, 0x10, 0x10, 0x10, 0x28, 0x44, 0x44},
                           {0x7c, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x7c}};

const UChar_t gDigits[][8] = {{0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38},//0
                              {0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x10, 0x10},//1
                              {0x7c, 0x44, 0x20, 0x18, 0x04, 0x04, 0x44, 0x38},//2
                              {0x38, 0x44, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38},//3
                              {0x04, 0x04, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x44},//4
                              {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x40, 0x40, 0x7c},//5
                              {0x7c, 0x44, 0x44, 0x44, 0x7c, 0x40, 0x40, 0x7c},//6
                              {0x20, 0x20, 0x20, 0x10, 0x08, 0x04, 0x44, 0x7c},//7
                              {0x38, 0x44, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38},//8
                              {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x7c},//9
                              {0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//.
                              {0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00}};//-

//______________________________________________________________________________
 TGLRender::TGLRender()
{
   fGLObjects.SetOwner(kTRUE);
   fGLCameras.SetOwner(kTRUE);

   fGLInit = kFALSE;
   fAllActive = kTRUE;
   fIsPicking = kFALSE;
   fBoxInList = kFALSE;
   fActiveCam = 0;
   fDList = 0;
   fPlaneEqn[0] = 1.;
   fPlaneEqn[1] = fPlaneEqn[2] = fPlaneEqn[3] = 0.;
   fClipping = kFALSE;
   fSelected = 0;

   fFirstT = 0;
   fSelectedObj = 0;
   fSelectionBox = 0;
   fPxs = kFALSE;
   fAxes = kFALSE;
}

//______________________________________________________________________________
 TGLRender::~TGLRender()
{
   if (fDList)
      glDeleteLists(fDList, 1);
}

//______________________________________________________________________________
 void TGLRender::Traverse()
{
   if (!fGLInit) {
      fGLInit = kTRUE;
      Init();
   }
   if (!fDList) {
      if (!(fDList = glGenLists(1))) {
         Error("TGLRender::Traverse", "could not create gl list");
         return;
      }
      BuildGLList();
   }

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   Int_t start = 0, end = fGLCameras.GetEntriesFast();

   if (!fAllActive) {
      start = fActiveCam;
      end = start + 1;
   }

   for (; start < end; ++start) {
      TGLCamera *currCam = (TGLCamera *)fGLCameras.At(start);
      currCam->TurnOn();

      if (fClipping) {
         glClipPlane(GL_CLIP_PLANE0, fPlaneEqn);
      }

      RunGLList();
      if (fSelectionBox) {
         fSelectionBox->DrawBox();
      }
      if(fAxes) DrawAxes();
   }
}

//______________________________________________________________________________
 void TGLRender::SetActive(UInt_t ncam)
{
   fActiveCam = ncam;
   fAllActive = kFALSE;
}

//______________________________________________________________________________
 void TGLRender::AddNewObject(TGLSceneObject *newobject)
{
   fGLObjects.AddLast(newobject);
}

//______________________________________________________________________________
 void TGLRender::AddNewCamera(TGLCamera *newcamera)
{
   fGLCameras.AddLast(newcamera);
}

//______________________________________________________________________________
 TGLSceneObject *TGLRender::SelectObject(Int_t x, Int_t y, Int_t cam)
{
   TGLCamera *actCam = (TGLCamera *)fGLCameras.At(cam);
   static std::vector<UInt_t>selectBuff(fGLObjects.GetEntriesFast() * 4);
   std::vector<std::pair<UInt_t, Int_t> >objNames;

   glSelectBuffer(selectBuff.size(), &selectBuff[0]);
   glRenderMode(GL_SELECT);
   glInitNames();
   glPushName(0);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   actCam->TurnOn(x, y);
   RunGLList();
   Int_t hits = glRenderMode(GL_RENDER);

   if (hits < 0) {
      Error("TGLRender::SelectObject", "selection buffer overflow");
   } else if (hits > 0) {
      objNames.resize(hits);
      for (Int_t i = 0; i < hits; ++i) {
         //object's "depth"
         objNames[i].first = selectBuff[i * 4 + 1];
         //object's name
         objNames[i].second = selectBuff[i * 4 + 3];
      }
      std::sort(objNames.begin(), objNames.end());
      UInt_t chosen = 0;
      TGLSceneObject *hitObject = 0;
      for (Int_t j = 0; j < hits; ++j) {
         chosen = objNames[j].second;
         hitObject = (TGLSceneObject *)fGLObjects.At(chosen - 1);
         if (!hitObject->IsTransparent())
            break;
      }
      if (hitObject->IsTransparent()) {
         chosen = objNames[0].second;
         hitObject = (TGLSceneObject *)fGLObjects.At(chosen - 1);
      }
      if (fSelected != chosen) {
         fSelected = chosen;
         fSelectedObj = hitObject;
         fSelectionBox = fSelectedObj->GetBox();
         Traverse();
      }
   } else if (fSelected) {
      fSelected = 0;
      fSelectedObj = 0;
      fSelectionBox = 0;
      Traverse();
   }

   return fSelectedObj;
}

//______________________________________________________________________________
 void TGLRender::MoveSelected(Double_t x, Double_t y, Double_t z)
{
   if (!fIsPicking) {
      fIsPicking = kTRUE;
   }
   fSelectedObj->Shift(x, y, z);
   fSelectionBox->Shift(x, y, z);
}

//______________________________________________________________________________
 void TGLRender::SetPlane(const Double_t *n)
{
   fPlaneEqn[0] = n[0];
   fPlaneEqn[1] = n[1];
   fPlaneEqn[2] = n[2];
   fPlaneEqn[3] = n[3];
}

//______________________________________________________________________________
 void TGLRender::EndMovement()
{
   if (fIsPicking) {
      fIsPicking = kFALSE;
      glDeleteLists(fDList, 1);
      if (!(fDList = glGenLists(1))) {
         Error("TGLSceneGraph::EndMovement", "could not create display list");
         return;
      }
      fFirstT = 0;
      BuildGLList();
   }
}

//______________________________________________________________________________
 void TGLRender::BuildGLList(Bool_t exec)
{
   glNewList(fDList, exec ? GL_COMPILE_AND_EXECUTE : GL_COMPILE);
   Bool_t isTr = kFALSE;
   if (fSelectedObj && !(isTr = fSelectedObj->IsTransparent())) {
      fSelectedObj->GLDraw();
   }

   for (Int_t i = 0, e = fGLObjects.GetEntriesFast(); i < e; ++i) {
      TGLSceneObject *currObj = (TGLSceneObject *)fGLObjects.At(i);
      if (currObj->IsTransparent() && currObj != fSelectedObj) {
         currObj->SetNextT(fFirstT);
         fFirstT = currObj;
      } else if (currObj != fSelectedObj) {
         currObj->GLDraw();
      }
   }

   if (isTr)
      fSelectedObj->GLDraw();

   while (fFirstT) {
      fFirstT->GLDraw();
      fFirstT = fFirstT->GetNextT();
   }

   glEndList();
}

//______________________________________________________________________________
 void TGLRender::RunGLList()
{
   glCallList(fDList);
}

//______________________________________________________________________________
 void TGLRender::Invalidate()
{
   if(fDList)
      glDeleteLists(fDList, 1);
   if (!(fDList = glGenLists(1))) {
      Error("TGLSceneGraph::EndMovement", "could not create display list");
      return;
   }
   fFirstT = 0;
   BuildGLList();
}

//______________________________________________________________________________
 void TGLRender::SetAxes(const PDD_t &x, const PDD_t &y, const PDD_t &z)
{
   fAxeD[0] = x;
   fAxeD[1] = y;
   fAxeD[2] = z;
}

//______________________________________________________________________________
void PrintNumber(Double_t x, Double_t y, Double_t z, Double_t num, Double_t ys)
{
#ifdef R__SSTREAM
   ostringstream ss;
#else
   ostrstream ss;
#endif
   ss<<num;
   std::string str(ss.str());
   glRasterPos3d(x, y, z);
   for (UInt_t i = 0, e = str.length(); i < e; ++i) {
      if (str[i] == '.') {
         glBitmap(8, 8, 0., ys, 7., 0., gDigits[10]);
         if (i + 1 < e)
            glBitmap(8, 8, 0., ys, 7., 0., gDigits[str[i + 1] - '0']);
         break;
      } else if (str[i] == '-') {
         glBitmap(8, 8, 0., ys, 7., 0., gDigits[11]);
      } else {
         glBitmap(8, 8, 0., ys, 7., 0., gDigits[str[i] - '0']);
      }
   }
}

//______________________________________________________________________________
 void TGLRender::DrawAxes()
{
   if (!fPxs) {
      fPxs = kTRUE;
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
   }
   glPushAttrib(GL_DEPTH_BUFFER_BIT);
   glDisable(GL_DEPTH_TEST);

   const Double_t axeColors[][3] = {{1., 0., 0.},
                                    {0., 1., 0.},
                                    {0., 0., 1.}};
   //white axes
   glDisable(GL_LIGHTING);
   glColor3dv(axeColors[3]);

   glBegin(GL_LINES);
   glColor3dv(axeColors[0]);
   glVertex3d(fAxeD[0].first, fAxeD[1].first, fAxeD[2].first);
   glVertex3d(fAxeD[0].second, fAxeD[1].first, fAxeD[2].first);
   glColor3dv(axeColors[1]);
   glVertex3d(fAxeD[0].first, fAxeD[1].first, fAxeD[2].first);
   glVertex3d(fAxeD[0].first, fAxeD[1].second, fAxeD[2].first);
   glColor3dv(axeColors[2]);
   glVertex3d(fAxeD[0].first, fAxeD[1].first, fAxeD[2].first);
   glVertex3d(fAxeD[0].first, fAxeD[1].first, fAxeD[2].second);
   glEnd();

   glColor3dv(axeColors[0]);
   glRasterPos3d(fAxeD[0].second, fAxeD[1].first + 12, fAxeD[2].first);
   glBitmap(8, 8, 0., 0., 0., 0., gXyz[0]);
   PrintNumber(fAxeD[0].second, fAxeD[1].first, fAxeD[2].first, fAxeD[0].second, 9.);
   PrintNumber(fAxeD[0].first, fAxeD[1].first, fAxeD[2].first, fAxeD[0].first, 0.);

   glColor3dv(axeColors[1]);
   glRasterPos3d(fAxeD[0].first, fAxeD[1].second + 12, fAxeD[2].first);
   glBitmap(8, 8, 0, 0, 12., 0, gXyz[1]);
   PrintNumber(fAxeD[0].first, fAxeD[1].second, fAxeD[2].first, fAxeD[1].second, 9.);
   PrintNumber(fAxeD[0].first, fAxeD[1].first, fAxeD[2].first, fAxeD[1].first, 9.);

   glColor3dv(axeColors[2]);
   glRasterPos3d(fAxeD[0].first, fAxeD[1].first, fAxeD[2].second);
   glBitmap(8, 8, 0, 0, 0., 0, gXyz[2]);
   PrintNumber(fAxeD[0].first, fAxeD[1].first, fAxeD[2].second, fAxeD[2].second, 9.);
   PrintNumber(fAxeD[0].first, fAxeD[1].first, fAxeD[2].first, fAxeD[2].first, -9.);

   glEnable(GL_LIGHTING);
   glPopAttrib();
}

 void TGLRender::SetFamilyColor(const Float_t *newColor)
{
   if (TObject *ro = fSelectedObj->GetRealObject()) {
      TString famName = ro->GetName();
      for (Int_t i = 0, e = fGLObjects.GetEntriesFast(); i < e; ++i) {
         TObject *obj = ((TGLSceneObject *)fGLObjects[i])->GetRealObject();
         if (obj && obj->GetName() == famName)
            ((TGLSceneObject *)fGLObjects[i])->SetColor(newColor);
      }
   } else fSelectedObj->SetColor(newColor);
}

 void TGLRender::Init()
{
   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
   Float_t lmodelAmb[] = {0.5f, 0.5f, 1.f, 1.f};
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodelAmb);
   glEnable(GL_LIGHTING);
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_CULL_FACE);
   glCullFace(GL_BACK);
   glClearColor(0., 0., 0., 0.);
   glClearDepth(1.);
}


ROOT page - Class index - Class Hierarchy - Top of the page

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.