#include <algorithm>
#include <string>
#include <map>
#include "THLimitsFinder.h"
#include "TVirtualPad.h"
#include "TVirtualX.h"
#include "Riostream.h"
#include "TStyle.h"
#include "TGaxis.h"
#include "TColor.h"
#include "TError.h"
#include "TH1.h"
#include "TMath.h"
#include "TROOT.h"
#include "TClass.h"
#include "TGLBoundingBox.h"
#include "TGLCamera.h"
#include "TGLPlotPainter.h"
#include "TGLIncludes.h"
#include "TGLQuadric.h"
#include "TGLUtil.h"
ClassImp(TGLVertex3);
TGLVertex3::TGLVertex3()
{
Fill(0.0);
}
TGLVertex3::TGLVertex3(Double_t x, Double_t y, Double_t z)
{
Set(x,y,z);
}
TGLVertex3::TGLVertex3(Double_t* v)
{
Set(v[0], v[1], v[2]);
}
TGLVertex3::TGLVertex3(const TGLVertex3 & other)
{
Set(other);
}
TGLVertex3::~TGLVertex3()
{
}
void TGLVertex3::Shift(TGLVector3 & shift)
{
fVals[0] += shift[0];
fVals[1] += shift[1];
fVals[2] += shift[2];
}
void TGLVertex3::Shift(Double_t xDelta, Double_t yDelta, Double_t zDelta)
{
fVals[0] += xDelta;
fVals[1] += yDelta;
fVals[2] += zDelta;
}
void TGLVertex3::Minimum(const TGLVertex3 & other)
{
fVals[0] = TMath::Min(fVals[0], other.fVals[0]);
fVals[1] = TMath::Min(fVals[1], other.fVals[1]);
fVals[2] = TMath::Min(fVals[2], other.fVals[2]);
}
void TGLVertex3::Maximum(const TGLVertex3 & other)
{
fVals[0] = TMath::Max(fVals[0], other.fVals[0]);
fVals[1] = TMath::Max(fVals[1], other.fVals[1]);
fVals[2] = TMath::Max(fVals[2], other.fVals[2]);
}
void TGLVertex3::Dump() const
{
std::cout << "(" << fVals[0] << "," << fVals[1] << "," << fVals[2] << ")" << std::endl;
}
ClassImp(TGLVector3);
TGLVector3::TGLVector3() :
TGLVertex3()
{
}
TGLVector3::TGLVector3(Double_t x, Double_t y, Double_t z) :
TGLVertex3(x, y, z)
{
}
TGLVector3::TGLVector3(const TGLVector3 & other) :
TGLVertex3(other.fVals[0], other.fVals[1], other.fVals[2])
{
}
TGLVector3::TGLVector3(const Double_t *src) :
TGLVertex3(src[0], src[1], src[2])
{
}
TGLVector3::~TGLVector3()
{
}
ClassImp(TGLLine3);
TGLLine3::TGLLine3(const TGLVertex3 & start, const TGLVertex3 & end) :
fVertex(start), fVector(end - start)
{
}
TGLLine3::TGLLine3(const TGLVertex3 & start, const TGLVector3 & vect) :
fVertex(start), fVector(vect)
{
}
TGLLine3::~TGLLine3()
{
}
void TGLLine3::Set(const TGLVertex3 & start, const TGLVertex3 & end)
{
fVertex = start;
fVector = end - start;
}
void TGLLine3::Set(const TGLVertex3 & start, const TGLVector3 & vect)
{
fVertex = start;
fVector = vect;
}
void TGLLine3::Draw() const
{
glBegin(GL_LINE_LOOP);
glVertex3dv(fVertex.CArr());
glVertex3dv(End().CArr());
glEnd();
}
ClassImp(TGLRect);
TGLRect::TGLRect() :
fX(0), fY(0), fWidth(0), fHeight(0)
{
}
TGLRect::TGLRect(Int_t x, Int_t y, Int_t width, Int_t height) :
fX(x), fY(y), fWidth(width), fHeight(height)
{
}
TGLRect::TGLRect(Int_t x, Int_t y, UInt_t width, UInt_t height) :
fX(x), fY(y), fWidth(width), fHeight(height)
{
}
TGLRect::~TGLRect()
{
}
EOverlap TGLRect::Overlap(const TGLRect & other) const
{
if ((fX <= other.fX) && (fX + fWidth >= other.fX + other.fWidth) &&
(fY <= other.fY) && (fY +fHeight >= other.fY + other.fHeight)) {
return kInside;
}
else if ((fX >= other.fX + static_cast<Int_t>(other.fWidth)) ||
(fX + static_cast<Int_t>(fWidth) <= other.fX) ||
(fY >= other.fY + static_cast<Int_t>(other.fHeight)) ||
(fY + static_cast<Int_t>(fHeight) <= other.fY)) {
return kOutside;
} else {
return kPartial;
}
}
ClassImp(TGLPlane);
TGLPlane::TGLPlane()
{
Set(1.0, 1.0, 1.0, 0.0);
}
TGLPlane::TGLPlane(const TGLPlane & other)
{
Set(other);
}
TGLPlane::TGLPlane(Double_t a, Double_t b, Double_t c, Double_t d)
{
Set(a, b, c, d);
}
TGLPlane::TGLPlane(Double_t eq[4])
{
Set(eq);
}
TGLPlane::TGLPlane(const TGLVertex3 & p1, const TGLVertex3 & p2,
const TGLVertex3 & p3)
{
Set(p1, p2, p3);
}
TGLPlane::TGLPlane(const TGLVector3 & v, const TGLVertex3 & p)
{
Set(v, p);
}
TGLPlane::~TGLPlane()
{
}
void TGLPlane::Normalise()
{
Double_t mag = sqrt(fVals[0]*fVals[0] + fVals[1]*fVals[1] + fVals[2]*fVals[2]);
if (mag == 0.0 ) {
Error("TGLPlane::Normalise", "trying to normalise plane with zero magnitude normal");
return;
}
mag = 1.0 / mag;
fVals[0] *= mag;
fVals[1] *= mag;
fVals[2] *= mag;
fVals[3] *= mag;
}
void TGLPlane::Dump() const
{
std::cout.precision(6);
std::cout << "Plane : " << fVals[0] << "x + " << fVals[1] << "y + " << fVals[2] << "z + " << fVals[3] << std::endl;
}
void TGLPlane::Set(const TGLPlane & other)
{
fVals[0] = other.fVals[0];
fVals[1] = other.fVals[1];
fVals[2] = other.fVals[2];
fVals[3] = other.fVals[3];
}
void TGLPlane::Set(Double_t a, Double_t b, Double_t c, Double_t d)
{
fVals[0] = a;
fVals[1] = b;
fVals[2] = c;
fVals[3] = d;
Normalise();
}
void TGLPlane::Set(Double_t eq[4])
{
fVals[0] = eq[0];
fVals[1] = eq[1];
fVals[2] = eq[2];
fVals[3] = eq[3];
Normalise();
}
void TGLPlane::Set(const TGLVector3 & norm, const TGLVertex3 & point)
{
fVals[0] = norm[0];
fVals[1] = norm[1];
fVals[2] = norm[2];
fVals[3] = -(fVals[0]*point[0] + fVals[1]*point[1] + fVals[2]*point[2]);
Normalise();
}
void TGLPlane::Set(const TGLVertex3 & p1, const TGLVertex3 & p2, const TGLVertex3 & p3)
{
TGLVector3 norm = Cross(p2 - p1, p3 - p1);
Set(norm, p2);
}
void TGLPlane::Negate()
{
fVals[0] = -fVals[0];
fVals[1] = -fVals[1];
fVals[2] = -fVals[2];
fVals[3] = -fVals[3];
}
Double_t TGLPlane::DistanceTo(const TGLVertex3 & vertex) const
{
return (fVals[0]*vertex[0] + fVals[1]*vertex[1] + fVals[2]*vertex[2] + fVals[3]);
}
TGLVertex3 TGLPlane::NearestOn(const TGLVertex3 & point) const
{
TGLVector3 o = Norm() * (Dot(Norm(), TGLVector3(point[0], point[1], point[2])) + D() / Dot(Norm(), Norm()));
TGLVertex3 v = point - o;
return v;
}
std::pair<Bool_t, TGLLine3> Intersection(const TGLPlane & p1, const TGLPlane & p2)
{
TGLVector3 lineDir = Cross(p1.Norm(), p2.Norm());
if (lineDir.Mag() == 0.0) {
return std::make_pair(kFALSE, TGLLine3(TGLVertex3(0.0, 0.0, 0.0),
TGLVector3(0.0, 0.0, 0.0)));
}
TGLVertex3 linePoint = Cross((p1.Norm()*p2.D() - p2.Norm()*p1.D()), lineDir) /
Dot(lineDir, lineDir);
return std::make_pair(kTRUE, TGLLine3(linePoint, lineDir));
}
std::pair<Bool_t, TGLVertex3> Intersection(const TGLPlane & p1, const TGLPlane & p2, const TGLPlane & p3)
{
Double_t denom = Dot(p1.Norm(), Cross(p2.Norm(), p3.Norm()));
if (denom == 0.0) {
return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
}
TGLVector3 vect = ((Cross(p2.Norm(),p3.Norm())* -p1.D()) -
(Cross(p3.Norm(),p1.Norm())*p2.D()) -
(Cross(p1.Norm(),p2.Norm())*p3.D())) / denom;
TGLVertex3 interVert(vect.X(), vect.Y(), vect.Z());
return std::make_pair(kTRUE, interVert);
}
std::pair<Bool_t, TGLVertex3> Intersection(const TGLPlane & plane, const TGLLine3 & line, Bool_t extend)
{
Double_t denom = -(plane.A()*line.Vector().X() +
plane.B()*line.Vector().Y() +
plane.C()*line.Vector().Z());
if (denom == 0.0) {
return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
}
Double_t num = plane.A()*line.Start().X() + plane.B()*line.Start().Y() +
plane.C()*line.Start().Z() + plane.D();
Double_t factor = num/denom;
if (!extend && (factor < 0.0 || factor > 1.0)) {
return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
}
TGLVector3 toPlane = line.Vector() * factor;
return std::make_pair(kTRUE, line.Start() + toPlane);
}
ClassImp(TGLMatrix);
TGLMatrix::TGLMatrix()
{
SetIdentity();
}
TGLMatrix::TGLMatrix(Double_t x, Double_t y, Double_t z)
{
SetIdentity();
SetTranslation(x, y, z);
}
TGLMatrix::TGLMatrix(const TGLVertex3 & translation)
{
SetIdentity();
SetTranslation(translation);
}
TGLMatrix::TGLMatrix(const TGLVertex3 & origin, const TGLVector3 & zAxis)
{
SetIdentity();
TGLVector3 zAxisInt(zAxis);
zAxisInt.Normalise();
TGLVector3 arbAxis;
if (TMath::Abs(zAxisInt.X()) <= TMath::Abs(zAxisInt.Y()) && TMath::Abs(zAxisInt.X()) <= TMath::Abs(zAxisInt.Z())) {
arbAxis.Set(1.0, 0.0, 0.0);
} else if (TMath::Abs(zAxisInt.Y()) <= TMath::Abs(zAxisInt.X()) && TMath::Abs(zAxisInt.Y()) <= TMath::Abs(zAxisInt.Z())) {
arbAxis.Set(0.0, 1.0, 0.0);
} else {
arbAxis.Set(0.0, 0.0, 1.0);
}
Set(origin, zAxis, Cross(zAxisInt, arbAxis));
}
TGLMatrix::TGLMatrix(const TGLVertex3 & origin, const TGLVector3 & zAxis, const TGLVector3 & xAxis)
{
SetIdentity();
Set(origin, zAxis, xAxis);
}
TGLMatrix::TGLMatrix(const Double_t vals[16])
{
Set(vals);
}
TGLMatrix::TGLMatrix(const TGLMatrix & other)
{
*this = other;
}
TGLMatrix::~TGLMatrix()
{
}
void TGLMatrix::MultRight(const TGLMatrix & rhs)
{
Double_t B[4];
Double_t* C = fVals;
for(int r=0; r<4; ++r, ++C)
{
const Double_t* T = rhs.fVals;
for(int c=0; c<4; ++c, T+=4)
B[c] = C[0]*T[0] + C[4]*T[1] + C[8]*T[2] + C[12]*T[3];
C[0] = B[0]; C[4] = B[1]; C[8] = B[2]; C[12] = B[3];
}
}
void TGLMatrix::MultLeft (const TGLMatrix & lhs)
{
Double_t B[4];
Double_t* C = fVals;
for (int c=0; c<4; ++c, C+=4)
{
const Double_t* T = lhs.fVals;
for(int r=0; r<4; ++r, ++T)
B[r] = T[0]*C[0] + T[4]*C[1] + T[8]*C[2] + T[12]*C[3];
C[0] = B[0]; C[1] = B[1]; C[2] = B[2]; C[3] = B[3];
}
}
void TGLMatrix::Set(const TGLVertex3 & origin, const TGLVector3 & zAxis, const TGLVector3 & xAxis)
{
TGLVector3 zAxisInt(zAxis);
zAxisInt.Normalise();
TGLVector3 xAxisInt(xAxis);
xAxisInt.Normalise();
TGLVector3 yAxisInt = Cross(zAxisInt, xAxisInt);
fVals[0] = xAxisInt.X(); fVals[4] = yAxisInt.X(); fVals[8 ] = zAxisInt.X(); fVals[12] = origin.X();
fVals[1] = xAxisInt.Y(); fVals[5] = yAxisInt.Y(); fVals[9 ] = zAxisInt.Y(); fVals[13] = origin.Y();
fVals[2] = xAxisInt.Z(); fVals[6] = yAxisInt.Z(); fVals[10] = zAxisInt.Z(); fVals[14] = origin.Z();
fVals[3] = 0.0; fVals[7] = 0.0; fVals[11] = 0.0; fVals[15] = 1.0;
}
void TGLMatrix::Set(const Double_t vals[16])
{
for (UInt_t i=0; i < 16; i++) {
fVals[i] = vals[i];
}
}
void TGLMatrix::SetIdentity()
{
fVals[0] = 1.0; fVals[4] = 0.0; fVals[8 ] = 0.0; fVals[12] = 0.0;
fVals[1] = 0.0; fVals[5] = 1.0; fVals[9 ] = 0.0; fVals[13] = 0.0;
fVals[2] = 0.0; fVals[6] = 0.0; fVals[10] = 1.0; fVals[14] = 0.0;
fVals[3] = 0.0; fVals[7] = 0.0; fVals[11] = 0.0; fVals[15] = 1.0;
}
void TGLMatrix::SetTranslation(Double_t x, Double_t y, Double_t z)
{
SetTranslation(TGLVertex3(x,y,z));
}
void TGLMatrix::SetTranslation(const TGLVertex3 & translation)
{
fVals[12] = translation[0];
fVals[13] = translation[1];
fVals[14] = translation[2];
}
TGLVector3 TGLMatrix::GetTranslation() const
{
return TGLVector3(fVals[12], fVals[13], fVals[14]);
}
void TGLMatrix::Translate(const TGLVector3 & vect)
{
fVals[12] += vect[0];
fVals[13] += vect[1];
fVals[14] += vect[2];
}
void TGLMatrix::MoveLF(Int_t ai, Double_t amount)
{
const Double_t *C = fVals + 4*--ai;
fVals[12] += amount*C[0]; fVals[13] += amount*C[1]; fVals[14] += amount*C[2];
}
void TGLMatrix::Move3LF(Double_t x, Double_t y, Double_t z)
{
fVals[12] += x*fVals[0] + y*fVals[4] + z*fVals[8];
fVals[13] += x*fVals[1] + y*fVals[5] + z*fVals[9];
fVals[14] += x*fVals[2] + y*fVals[6] + z*fVals[10];
}
void TGLMatrix::Scale(const TGLVector3 & scale)
{
TGLVector3 currentScale = GetScale();
if (currentScale[0] != 0.0) {
fVals[0] *= scale[0]/currentScale[0];
fVals[1] *= scale[0]/currentScale[0];
fVals[2] *= scale[0]/currentScale[0];
} else {
Error("TGLMatrix::Scale()", "zero scale div by zero");
}
if (currentScale[1] != 0.0) {
fVals[4] *= scale[1]/currentScale[1];
fVals[5] *= scale[1]/currentScale[1];
fVals[6] *= scale[1]/currentScale[1];
} else {
Error("TGLMatrix::Scale()", "zero scale div by zero");
}
if (currentScale[2] != 0.0) {
fVals[8] *= scale[2]/currentScale[2];
fVals[9] *= scale[2]/currentScale[2];
fVals[10] *= scale[2]/currentScale[2];
} else {
Error("TGLMatrix::Scale()", "zero scale div by zero");
}
}
void TGLMatrix::Rotate(const TGLVertex3 & pivot, const TGLVector3 & axis, Double_t angle)
{
TGLVector3 nAxis = axis;
nAxis.Normalise();
Double_t x = nAxis.X();
Double_t y = nAxis.Y();
Double_t z = nAxis.Z();
Double_t c = TMath::Cos(angle);
Double_t s = TMath::Sin(angle);
TGLMatrix rotMat;
rotMat[ 0] = x*x*(1-c) + c; rotMat[ 4] = x*y*(1-c) - z*s; rotMat[ 8] = x*z*(1-c) + y*s; rotMat[12] = pivot[0];
rotMat[ 1] = y*x*(1-c) + z*s; rotMat[ 5] = y*y*(1-c) + c; rotMat[ 9] = y*z*(1-c) - x*s; rotMat[13] = pivot[1];
rotMat[ 2] = x*z*(1-c) - y*s; rotMat[ 6] = y*z*(1-c) + x*s; rotMat[10] = z*z*(1-c) + c; rotMat[14] = pivot[2];
rotMat[ 3] = 0.0; rotMat[ 7] = 0.0; rotMat[11] = 0.0; rotMat[15] = 1.0;
TGLMatrix localToWorld(-pivot);
*this = rotMat * localToWorld * (*this);
}
void TGLMatrix::RotateLF(Int_t i1, Int_t i2, Double_t amount)
{
if(i1 == i2) return;
const Double_t cos = TMath::Cos(amount), sin = TMath::Sin(amount);
Double_t b1, b2;
Double_t* c = fVals;
--i1 <<= 2; --i2 <<= 2;
for(int r=0; r<4; ++r, ++c) {
b1 = cos*c[i1] + sin*c[i2];
b2 = cos*c[i2] - sin*c[i1];
c[i1] = b1; c[i2] = b2;
}
}
void TGLMatrix::RotatePF(Int_t i1, Int_t i2, Double_t amount)
{
if(i1 == i2) return;
const Double_t cos = TMath::Cos(amount), sin = TMath::Sin(amount);
Double_t b1, b2;
Double_t* C = fVals;
--i1; --i2;
for(int c=0; c<4; ++c, C+=4) {
b1 = cos*C[i1] - sin*C[i2];
b2 = cos*C[i2] + sin*C[i1];
C[i1] = b1; C[i2] = b2;
}
}
void TGLMatrix::TransformVertex(TGLVertex3 & vertex) const
{
TGLVertex3 orig = vertex;
for (UInt_t i = 0; i < 3; i++) {
vertex[i] = orig[0] * fVals[0+i] + orig[1] * fVals[4+i] +
orig[2] * fVals[8+i] + fVals[12+i];
}
}
void TGLMatrix::Transpose3x3()
{
Double_t temp = fVals[4];
fVals[4] = fVals[1];
fVals[1] = temp;
temp = fVals[8];
fVals[8] = fVals[2];
fVals[2] = temp;
temp = fVals[9];
fVals[9] = fVals[6];
fVals[6] = temp;
}
Double_t TGLMatrix::Invert()
{
Double_t* M = fVals;
const Double_t det2_12_01 = M[1]*M[6] - M[5]*M[2];
const Double_t det2_12_02 = M[1]*M[10] - M[9]*M[2];
const Double_t det2_12_03 = M[1]*M[14] - M[13]*M[2];
const Double_t det2_12_13 = M[5]*M[14] - M[13]*M[6];
const Double_t det2_12_23 = M[9]*M[14] - M[13]*M[10];
const Double_t det2_12_12 = M[5]*M[10] - M[9]*M[6];
const Double_t det2_13_01 = M[1]*M[7] - M[5]*M[3];
const Double_t det2_13_02 = M[1]*M[11] - M[9]*M[3];
const Double_t det2_13_03 = M[1]*M[15] - M[13]*M[3];
const Double_t det2_13_12 = M[5]*M[11] - M[9]*M[7];
const Double_t det2_13_13 = M[5]*M[15] - M[13]*M[7];
const Double_t det2_13_23 = M[9]*M[15] - M[13]*M[11];
const Double_t det2_23_01 = M[2]*M[7] - M[6]*M[3];
const Double_t det2_23_02 = M[2]*M[11] - M[10]*M[3];
const Double_t det2_23_03 = M[2]*M[15] - M[14]*M[3];
const Double_t det2_23_12 = M[6]*M[11] - M[10]*M[7];
const Double_t det2_23_13 = M[6]*M[15] - M[14]*M[7];
const Double_t det2_23_23 = M[10]*M[15] - M[14]*M[11];
const Double_t det3_012_012 = M[0]*det2_12_12 - M[4]*det2_12_02 + M[8]*det2_12_01;
const Double_t det3_012_013 = M[0]*det2_12_13 - M[4]*det2_12_03 + M[12]*det2_12_01;
const Double_t det3_012_023 = M[0]*det2_12_23 - M[8]*det2_12_03 + M[12]*det2_12_02;
const Double_t det3_012_123 = M[4]*det2_12_23 - M[8]*det2_12_13 + M[12]*det2_12_12;
const Double_t det3_013_012 = M[0]*det2_13_12 - M[4]*det2_13_02 + M[8]*det2_13_01;
const Double_t det3_013_013 = M[0]*det2_13_13 - M[4]*det2_13_03 + M[12]*det2_13_01;
const Double_t det3_013_023 = M[0]*det2_13_23 - M[8]*det2_13_03 + M[12]*det2_13_02;
const Double_t det3_013_123 = M[4]*det2_13_23 - M[8]*det2_13_13 + M[12]*det2_13_12;
const Double_t det3_023_012 = M[0]*det2_23_12 - M[4]*det2_23_02 + M[8]*det2_23_01;
const Double_t det3_023_013 = M[0]*det2_23_13 - M[4]*det2_23_03 + M[12]*det2_23_01;
const Double_t det3_023_023 = M[0]*det2_23_23 - M[8]*det2_23_03 + M[12]*det2_23_02;
const Double_t det3_023_123 = M[4]*det2_23_23 - M[8]*det2_23_13 + M[12]*det2_23_12;
const Double_t det3_123_012 = M[1]*det2_23_12 - M[5]*det2_23_02 + M[9]*det2_23_01;
const Double_t det3_123_013 = M[1]*det2_23_13 - M[5]*det2_23_03 + M[13]*det2_23_01;
const Double_t det3_123_023 = M[1]*det2_23_23 - M[9]*det2_23_03 + M[13]*det2_23_02;
const Double_t det3_123_123 = M[5]*det2_23_23 - M[9]*det2_23_13 + M[13]*det2_23_12;
const Double_t det = M[0]*det3_123_123 - M[4]*det3_123_023 +
M[8]*det3_123_013 - M[12]*det3_123_012;
if(det == 0) {
Warning("TGLMatrix::Invert", "matrix is singular.");
return 0;
}
const Double_t oneOverDet = 1.0/det;
const Double_t mn1OverDet = - oneOverDet;
M[0] = det3_123_123 * oneOverDet;
M[4] = det3_023_123 * mn1OverDet;
M[8] = det3_013_123 * oneOverDet;
M[12] = det3_012_123 * mn1OverDet;
M[1] = det3_123_023 * mn1OverDet;
M[5] = det3_023_023 * oneOverDet;
M[9] = det3_013_023 * mn1OverDet;
M[13] = det3_012_023 * oneOverDet;
M[2] = det3_123_013 * oneOverDet;
M[6] = det3_023_013 * mn1OverDet;
M[10] = det3_013_013 * oneOverDet;
M[14] = det3_012_013 * mn1OverDet;
M[3] = det3_123_012 * mn1OverDet;
M[7] = det3_023_012 * oneOverDet;
M[11] = det3_013_012 * mn1OverDet;
M[15] = det3_012_012 * oneOverDet;
return det;
}
TGLVector3 TGLMatrix::Multiply(const TGLVector3& v, Double_t w) const
{
const Double_t* M = fVals;
TGLVector3 r;
r.X() = M[0]*v[0] + M[4]*v[1] + M[8]*v[2] + M[12]*w;
r.Y() = M[1]*v[0] + M[5]*v[1] + M[9]*v[2] + M[13]*w;
r.Z() = M[2]*v[0] + M[6]*v[1] + M[10]*v[2] + M[14]*w;
return r;
}
TGLVector3 TGLMatrix::Rotate(const TGLVector3& v) const
{
const Double_t* M = fVals;
TGLVector3 r;
r.X() = M[0]*v[0] + M[4]*v[1] + M[8]*v[2];
r.Y() = M[1]*v[0] + M[5]*v[1] + M[9]*v[2];
r.Z() = M[2]*v[0] + M[6]*v[1] + M[10]*v[2];
return r;
}
void TGLMatrix::MultiplyIP(TGLVector3& v, Double_t w) const
{
const Double_t* M = fVals;
Double_t r[3] = { v[0], v[1], v[2] };
v.X() = M[0]*r[0] + M[4]*r[1] + M[8]*r[2] + M[12]*w;
v.Y() = M[1]*r[0] + M[5]*r[1] + M[9]*r[2] + M[13]*w;
v.Z() = M[2]*r[0] + M[6]*r[1] + M[10]*r[2] + M[14]*w;
}
void TGLMatrix::RotateIP(TGLVector3& v) const
{
const Double_t* M = fVals;
Double_t r[3] = { v[0], v[1], v[2] };
v.X() = M[0]*r[0] + M[4]*r[1] + M[8]*r[2];
v.Y() = M[1]*r[0] + M[5]*r[1] + M[9]*r[2];
v.Z() = M[2]*r[0] + M[6]*r[1] + M[10]*r[2];
}
TGLVector3 TGLMatrix::GetScale() const
{
TGLVector3 x(fVals[0], fVals[1], fVals[2]);
TGLVector3 y(fVals[4], fVals[5], fVals[6]);
TGLVector3 z(fVals[8], fVals[9], fVals[10]);
return TGLVector3(x.Mag(), y.Mag(), z.Mag());
}
void TGLMatrix::Dump() const
{
std::cout.precision(6);
for (Int_t x = 0; x < 4; x++) {
std::cout << "[ ";
for (Int_t y = 0; y < 4; y++) {
std::cout << fVals[y*4 + x] << " ";
}
std::cout << "]" << std::endl;
}
}
ClassImp(TGLColor);
TGLColor::TGLColor()
{
fRGBA[0] = fRGBA[1] = fRGBA[2] = 0;
fRGBA[3] = 255;
fIndex = -1;
}
TGLColor::TGLColor(Int_t r, Int_t g, Int_t b, Int_t a)
{
SetColor(r, g, b, a);
}
TGLColor::TGLColor(Float_t r, Float_t g, Float_t b, Float_t a)
{
SetColor(r, g, b, a);
}
TGLColor::TGLColor(Color_t color_index, Char_t transparency)
{
SetColor(color_index, transparency);
}
TGLColor::~TGLColor()
{
}
TGLColor& TGLColor::operator=(const TGLColor& c)
{
fRGBA[0] = c.fRGBA[0];
fRGBA[1] = c.fRGBA[1];
fRGBA[2] = c.fRGBA[2];
fRGBA[3] = c.fRGBA[3];
fIndex = c.fIndex;
return *this;
}
Color_t TGLColor::GetColorIndex() const
{
if (fIndex == -1)
fIndex = TColor::GetColor(fRGBA[0], fRGBA[1], fRGBA[2]);
return fIndex;
}
Char_t TGLColor::GetTransparency() const
{
return TMath::Nint(100.0*(1.0 - fRGBA[3]/255.0));
}
void TGLColor::SetColor(Int_t r, Int_t g, Int_t b, Int_t a)
{
fRGBA[0] = r;
fRGBA[1] = g;
fRGBA[2] = b;
fRGBA[3] = a;
fIndex = -1;
}
void TGLColor::SetColor(Float_t r, Float_t g, Float_t b, Float_t a)
{
fRGBA[0] = (UChar_t)(255*r);
fRGBA[1] = (UChar_t)(255*g);
fRGBA[2] = (UChar_t)(255*b);
fRGBA[3] = (UChar_t)(255*a);
fIndex = -1;
}
void TGLColor::SetColor(Color_t color_index)
{
TColor* c = gROOT->GetColor(color_index);
if (c)
{
fRGBA[0] = (UChar_t)(255*c->GetRed());
fRGBA[1] = (UChar_t)(255*c->GetGreen());
fRGBA[2] = (UChar_t)(255*c->GetBlue());
fIndex = color_index;
}
else
{
fRGBA[0] = 255;
fRGBA[1] = 0;
fRGBA[2] = 255;
fIndex = -1;
}
}
void TGLColor::SetColor(Color_t color_index, Char_t transparency)
{
UChar_t alpha = (255*(100 - transparency))/100;
TColor* c = gROOT->GetColor(color_index);
if (c)
{
fRGBA[0] = (UChar_t)(255*c->GetRed());
fRGBA[1] = (UChar_t)(255*c->GetGreen());
fRGBA[2] = (UChar_t)(255*c->GetBlue());
fRGBA[3] = alpha;
fIndex = color_index;
}
else
{
fRGBA[0] = 255;
fRGBA[1] = 0;
fRGBA[2] = 255;
fRGBA[3] = alpha;
fIndex = -1;
return;
}
}
void TGLColor::SetTransparency(Char_t transparency)
{
fRGBA[3] = (255*(100 - transparency))/100;
}
TString TGLColor::AsString() const
{
return TString::Format("rgba:%02hhx/%02hhx/%02hhx/%02hhx",
fRGBA[0], fRGBA[1], fRGBA[2], fRGBA[3]);
}
ClassImp(TGLColorSet);
TGLColorSet::TGLColorSet()
{
StdDarkBackground();
}
TGLColorSet::~TGLColorSet()
{
}
TGLColorSet& TGLColorSet::operator=(const TGLColorSet& s)
{
fBackground = s.fBackground;
fForeground = s.fForeground;
fOutline = s.fOutline;
fMarkup = s.fMarkup;
for (Int_t i = 0; i < 5; ++i)
fSelection[i] = s.fSelection[i];
return *this;
}
void TGLColorSet::StdDarkBackground()
{
fBackground .SetColor(0, 0, 0);
fForeground .SetColor(255, 255, 255);
fOutline .SetColor(240, 255, 240);
fMarkup .SetColor(200, 200, 200);
fSelection[0].SetColor( 0, 0, 0);
fSelection[1].SetColor(255, 220, 220);
fSelection[2].SetColor(255, 220, 220);
fSelection[3].SetColor(200, 200, 255);
fSelection[4].SetColor(200, 200, 255);
}
void TGLColorSet::StdLightBackground()
{
fBackground .SetColor(255, 255, 255);
fForeground .SetColor(0, 0, 0);
fOutline .SetColor(0, 0, 0);
fMarkup .SetColor(55, 55, 55);
fSelection[0].SetColor(0, 0, 0);
fSelection[1].SetColor(200, 100, 100);
fSelection[2].SetColor(200, 100, 100);
fSelection[3].SetColor(100, 100, 200);
fSelection[4].SetColor(100, 100, 200);
}
ClassImp(TGLUtil);
UInt_t TGLUtil::fgDefaultDrawQuality = 10;
UInt_t TGLUtil::fgDrawQuality = fgDefaultDrawQuality;
UInt_t TGLUtil::fgColorLockCount = 0;
Float_t TGLUtil::fgPointSize = 1.0f;
Float_t TGLUtil::fgLineWidth = 1.0f;
Float_t TGLUtil::fgPointSizeScale = 1.0f;
Float_t TGLUtil::fgLineWidthScale = 1.0f;
#ifndef CALLBACK
#define CALLBACK
#endif
extern "C" {
#if defined(__APPLE_CC__) && __APPLE_CC__ > 4000 && __APPLE_CC__ < 5450 && !defined(__INTEL_COMPILER)
typedef GLvoid (*tessfuncptr_t)(...);
#elif defined( __mips ) || defined( __linux__ ) || defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __sun ) || defined (__CYGWIN__) || defined (__APPLE__)
typedef GLvoid (*tessfuncptr_t)();
#elif defined ( WIN32)
typedef GLvoid (CALLBACK *tessfuncptr_t)( );
#else
#error "Error - need to define type tessfuncptr_t for this platform/compiler"
#endif
}
namespace
{
class TGLTesselatorWrap
{
protected:
public:
GLUtesselator *fTess;
TGLTesselatorWrap(tessfuncptr_t vertex_func) : fTess(0)
{
fTess = gluNewTess();
if (!fTess)
throw std::bad_alloc();
gluTessCallback(fTess, (GLenum)GLU_BEGIN, (tessfuncptr_t) glBegin);
gluTessCallback(fTess, (GLenum)GLU_END, (tessfuncptr_t) glEnd);
gluTessCallback(fTess, (GLenum)GLU_VERTEX, vertex_func);
}
virtual ~TGLTesselatorWrap()
{
if (fTess)
gluDeleteTess(fTess);
}
};
}
GLUtesselator* TGLUtil::GetDrawTesselator3fv()
{
static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3fv);
return singleton.fTess;
}
GLUtesselator* TGLUtil::GetDrawTesselator4fv()
{
static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4fv);
return singleton.fTess;
}
GLUtesselator* TGLUtil::GetDrawTesselator3dv()
{
static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3dv);
return singleton.fTess;
}
GLUtesselator* TGLUtil::GetDrawTesselator4dv()
{
static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4dv);
return singleton.fTess;
}
UInt_t TGLUtil::GetDrawQuality()
{
return fgDrawQuality;
}
void TGLUtil::SetDrawQuality(UInt_t dq)
{
fgDrawQuality = dq;
}
void TGLUtil::ResetDrawQuality()
{
fgDrawQuality = fgDefaultDrawQuality;
}
UInt_t TGLUtil::GetDefaultDrawQuality()
{
return fgDefaultDrawQuality;
}
void TGLUtil::SetDefaultDrawQuality(UInt_t dq)
{
fgDefaultDrawQuality = dq;
}
void TGLUtil::CheckError(const char * loc)
{
GLenum errCode;
const GLubyte *errString;
if ((errCode = glGetError()) != GL_NO_ERROR) {
errString = gluErrorString(errCode);
if (loc) {
Error(loc, "GL Error %s", (const char *)errString);
} else {
Error("TGLUtil::CheckError", "GL Error %s", (const char *)errString);
}
}
}
UInt_t TGLUtil::LockColor()
{
return ++fgColorLockCount;
}
UInt_t TGLUtil::UnlockColor()
{
if (fgColorLockCount)
--fgColorLockCount;
else
Error("TGLUtil::UnlockColor", "fgColorLockCount already 0.");
return fgColorLockCount;
}
Bool_t TGLUtil::IsColorLocked()
{
return fgColorLockCount > 0;
}
void TGLUtil::Color(const TGLColor& color)
{
if (fgColorLockCount == 0) glColor4ubv(color.CArr());
}
void TGLUtil::Color(const TGLColor& color, UChar_t alpha)
{
if (fgColorLockCount == 0)
{
glColor4ub(color.GetRed(), color.GetGreen(), color.GetBlue(), alpha);
}
}
void TGLUtil::Color(const TGLColor& color, Float_t alpha)
{
if (fgColorLockCount == 0)
{
glColor4ub(color.GetRed(), color.GetGreen(), color.GetBlue(), (UChar_t)(255*alpha));
}
}
void TGLUtil::Color(Color_t color_index, Float_t alpha)
{
if (fgColorLockCount == 0) {
if (color_index < 0)
color_index = 1;
TColor* c = gROOT->GetColor(color_index);
if (c)
glColor4f(c->GetRed(), c->GetGreen(), c->GetBlue(), alpha);
}
}
void TGLUtil::ColorTransparency(Color_t color_index, Char_t transparency)
{
if (fgColorLockCount == 0) {
if (color_index < 0)
color_index = 1;
TColor* c = gROOT->GetColor(color_index);
if (c)
glColor4f(c->GetRed(), c->GetGreen(), c->GetBlue(), 1.0f - 0.01f*transparency);
}
}
void TGLUtil::Color3ub(UChar_t r, UChar_t g, UChar_t b)
{
if (fgColorLockCount == 0) glColor3ub(r, g, b);
}
void TGLUtil::Color4ub(UChar_t r, UChar_t g, UChar_t b, UChar_t a)
{
if (fgColorLockCount == 0) glColor4ub(r, g, b, a);
}
void TGLUtil::Color3ubv(const UChar_t* rgb)
{
if (fgColorLockCount == 0) glColor3ubv(rgb);
}
void TGLUtil::Color4ubv(const UChar_t* rgba)
{
if (fgColorLockCount == 0) glColor4ubv(rgba);
}
void TGLUtil::Color3f(Float_t r, Float_t g, Float_t b)
{
if (fgColorLockCount == 0) glColor3f(r, g, b);
}
void TGLUtil::Color4f(Float_t r, Float_t g, Float_t b, Float_t a)
{
if (fgColorLockCount == 0) glColor4f(r, g, b, a);
}
void TGLUtil::Color3fv(const Float_t* rgb)
{
if (fgColorLockCount == 0) glColor3fv(rgb);
}
void TGLUtil::Color4fv(const Float_t* rgba)
{
if (fgColorLockCount == 0) glColor4fv(rgba);
}
Float_t TGLUtil::GetPointSizeScale()
{
return fgPointSizeScale;
}
void TGLUtil::SetPointSizeScale(Float_t scale)
{
fgPointSizeScale = scale;
}
Float_t TGLUtil::GetLineWidthScale()
{
return fgLineWidthScale;
}
void TGLUtil::SetLineWidthScale(Float_t scale)
{
fgLineWidthScale = scale;
}
void TGLUtil::PointSize(Float_t point_size)
{
fgPointSize = point_size * fgPointSizeScale;
glPointSize(fgPointSize);
}
void TGLUtil::LineWidth(Float_t line_width)
{
fgLineWidth = line_width * fgLineWidthScale;
glLineWidth(fgLineWidth);
}
Float_t TGLUtil::PointSize()
{
return fgPointSize;
}
Float_t TGLUtil::LineWidth()
{
return fgLineWidth;
}
void TGLUtil::BeginExtendPickRegion(Float_t scale)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
Float_t pm[16];
glGetFloatv(GL_PROJECTION_MATRIX, pm);
for (Int_t i=0; i<=12; i+=4) {
pm[i] *= scale; pm[i+1] *= scale;
}
glLoadMatrixf(pm);
glMatrixMode(GL_MODELVIEW);
}
void TGLUtil::EndExtendPickRegion()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void TGLUtil::RenderPolyMarkers(const TAttMarker& marker, Float_t* p, Int_t n,
Int_t pick_radius, Bool_t selection,
Bool_t sec_selection)
{
if (n == 0) return;
glPushAttrib(GL_ENABLE_BIT | GL_POINT_BIT | GL_LINE_BIT);
glDisable(GL_LIGHTING);
TGLUtil::Color(marker.GetMarkerColor());
Int_t s = marker.GetMarkerStyle();
if (s == 2 || s == 3 || s == 5 || s == 28)
RenderCrosses(marker, p, n, sec_selection);
else
RenderPoints(marker, p, n, pick_radius, selection, sec_selection);
glPopAttrib();
}
void TGLUtil::RenderPoints(const TAttMarker& marker, Float_t* op, Int_t n,
Int_t pick_radius, Bool_t selection,
Bool_t sec_selection)
{
Int_t style = marker.GetMarkerStyle();
Float_t size = 5*marker.GetMarkerSize();
if (style == 4 || style == 20 || style == 24)
{
glEnable(GL_POINT_SMOOTH);
if (style == 4 || style == 24) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
}
}
else
{
glDisable(GL_POINT_SMOOTH);
if (style == 1) size = 1;
else if (style == 6) size = 2;
else if (style == 7) size = 3;
}
TGLUtil::PointSize(size);
Bool_t changePM = selection && PointSize() > pick_radius;
if (changePM)
BeginExtendPickRegion((Float_t) pick_radius / PointSize());
Float_t* p = op;
if (sec_selection)
{
glPushName(0);
for (Int_t i=0; i<n; ++i, p+=3)
{
glLoadName(i);
glBegin(GL_POINTS);
glVertex3fv(p);
glEnd();
}
glPopName();
}
else
{
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glVertexPointer(3, GL_FLOAT, 0, p);
glEnableClientState(GL_VERTEX_ARRAY);
{
Int_t nleft = n;
Int_t ndone = 0;
const Int_t maxChunk = 8192;
while (nleft > maxChunk)
{
glDrawArrays(GL_POINTS, ndone, maxChunk);
nleft -= maxChunk;
ndone += maxChunk;
}
glDrawArrays(GL_POINTS, ndone, nleft);
}
glPopClientAttrib();
}
if (changePM)
EndExtendPickRegion();
}
void TGLUtil::RenderCrosses(const TAttMarker& marker, Float_t* op, Int_t n,
Bool_t sec_selection)
{
if (marker.GetMarkerStyle() == 28)
{
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
TGLUtil::LineWidth(2);
}
else
{
glDisable(GL_LINE_SMOOTH);
TGLUtil::LineWidth(1);
}
const Float_t d = 2*marker.GetMarkerSize();
Float_t* p = op;
if (sec_selection)
{
glPushName(0);
for (Int_t i=0; i<n; ++i, p+=3)
{
glLoadName(i);
glBegin(GL_LINES);
glVertex3f(p[0]-d, p[1], p[2]); glVertex3f(p[0]+d, p[1], p[2]);
glVertex3f(p[0], p[1]-d, p[2]); glVertex3f(p[0], p[1]+d, p[2]);
glVertex3f(p[0], p[1], p[2]-d); glVertex3f(p[0], p[1], p[2]+d);
glEnd();
}
glPopName();
}
else
{
glBegin(GL_LINES);
for (Int_t i=0; i<n; ++i, p+=3)
{
glVertex3f(p[0]-d, p[1], p[2]); glVertex3f(p[0]+d, p[1], p[2]);
glVertex3f(p[0], p[1]-d, p[2]); glVertex3f(p[0], p[1]+d, p[2]);
glVertex3f(p[0], p[1], p[2]-d); glVertex3f(p[0], p[1], p[2]+d);
}
glEnd();
}
{
glDisable(GL_POINT_SMOOTH);
TGLUtil::PointSize(1);
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glVertexPointer(3, GL_FLOAT, 0, op);
glEnableClientState(GL_VERTEX_ARRAY);
{
Int_t nleft = n;
Int_t ndone = 0;
const Int_t maxChunk = 8192;
while (nleft > maxChunk)
{
glDrawArrays(GL_POINTS, ndone, maxChunk);
nleft -= maxChunk;
ndone += maxChunk;
}
glDrawArrays(GL_POINTS, ndone, nleft);
}
glPopClientAttrib();
}
}
void TGLUtil::RenderPolyLine(const TAttLine& aline, Float_t* p, Int_t n,
Int_t pick_radius, Bool_t selection)
{
if (n == 0) return;
BeginAttLine(aline, pick_radius, selection);
Float_t* tp = p;
glBegin(GL_LINE_STRIP);
for (Int_t i=0; i<n; ++i, tp+=3)
glVertex3fv(tp);
glEnd();
EndAttLine(pick_radius, selection);
}
void TGLUtil::BeginAttLine(const TAttLine& aline, Int_t pick_radius, Bool_t selection)
{
glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
glDisable(GL_LIGHTING);
TGLUtil::Color(aline.GetLineColor());
TGLUtil::LineWidth(aline.GetLineWidth());
if (aline.GetLineStyle() > 1)
{
Int_t fac = 1;
UShort_t pat = 0xffff;
switch (aline.GetLineStyle()) {
case 2: pat = 0x3333; break;
case 3: pat = 0x5555; break;
case 4: pat = 0xf040; break;
case 5: pat = 0xf4f4; break;
case 6: pat = 0xf111; break;
case 7: pat = 0xf0f0; break;
case 8: pat = 0xff11; break;
case 9: pat = 0x3fff; break;
case 10: pat = 0x08ff; fac = 2; break;
}
glLineStipple(1, pat);
glEnable(GL_LINE_STIPPLE);
}
if (selection && TGLUtil::LineWidth() > pick_radius)
BeginExtendPickRegion((Float_t) pick_radius / TGLUtil::LineWidth());
}
void TGLUtil::EndAttLine(Int_t pick_radius, Bool_t selection)
{
if (selection && TGLUtil::LineWidth() > pick_radius)
EndExtendPickRegion();
glPopAttrib();
}
void TGLUtil::SetDrawColors(const Float_t rgba[4])
{
static Float_t ambient[4] = {0.0, 0.0, 0.0, 1.0};
static Float_t specular[4] = {0.6, 0.6, 0.6, 1.0};
Float_t emission[4] = {rgba[0]/4.f, rgba[1]/4.f, rgba[2]/4.f, rgba[3]};
glColor4fv(rgba);
glMaterialfv(GL_FRONT, GL_DIFFUSE, rgba);
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialfv(GL_FRONT, GL_EMISSION, emission);
glMaterialf(GL_FRONT, GL_SHININESS, 60.0);
}
void TGLUtil::DrawSphere(const TGLVertex3 & position, Double_t radius,
const Float_t rgba[4])
{
static TGLQuadric quad;
SetDrawColors(rgba);
glPushMatrix();
glTranslated(position.X(), position.Y(), position.Z());
gluSphere(quad.Get(), radius, fgDrawQuality, fgDrawQuality);
glPopMatrix();
}
void TGLUtil::DrawLine(const TGLLine3 & line, ELineHeadShape head, Double_t size,
const Float_t rgba[4])
{
DrawLine(line.Start(), line.Vector(), head, size, rgba);
}
void TGLUtil::DrawLine(const TGLVertex3 & start, const TGLVector3 & vector,
ELineHeadShape head, Double_t size, const Float_t rgba[4])
{
static TGLQuadric quad;
SetDrawColors(rgba);
glPushMatrix();
TGLMatrix local(start, vector);
glMultMatrixd(local.CArr());
Double_t headHeight=0;
if (head == kLineHeadNone) {
headHeight = 0.0;
} else if (head == kLineHeadArrow) {
headHeight = size*2.0;
} else if (head == kLineHeadBox) {
headHeight = size*1.4;
}
gluCylinder(quad.Get(), 0.25*size, 0.25*size, vector.Mag() - headHeight, fgDrawQuality, 1);
gluQuadricOrientation(quad.Get(), (GLenum)GLU_INSIDE);
gluDisk(quad.Get(), 0.0, 0.25*size, fgDrawQuality, 1);
glTranslated(0.0, 0.0, vector.Mag() - headHeight);
if (head == kLineHeadNone) {
gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
gluDisk(quad.Get(), 0.0, size/4.0, fgDrawQuality, 1);
}
else if (head == kLineHeadArrow) {
gluDisk(quad.Get(), 0.0, size, fgDrawQuality, 1);
gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
gluCylinder(quad.Get(), size, 0.0, headHeight, fgDrawQuality, 1);
} else if (head == kLineHeadBox) {
gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
TGLBoundingBox box(TGLVertex3(-size*.7, -size*.7, 0.0),
TGLVertex3(size*.7, size*.7, headHeight));
box.Draw(kTRUE);
}
glPopMatrix();
}
void TGLUtil::DrawRing(const TGLVertex3 & center, const TGLVector3 & normal,
Double_t radius, const Float_t rgba[4])
{
static TGLQuadric quad;
TGLUtil::SetDrawColors(rgba);
Double_t outer = radius;
Double_t width = radius*0.05;
Double_t inner = outer - width;
glPushMatrix();
TGLMatrix local(center, normal);
glMultMatrixd(local.CArr());
glTranslated(0.0, 0.0, -width/2.0);
gluCylinder(quad.Get(), inner, inner, width, fgDrawQuality, 1);
gluCylinder(quad.Get(), outer, outer, width, fgDrawQuality, 1);
gluQuadricOrientation(quad.Get(), (GLenum)GLU_INSIDE);
gluDisk(quad.Get(), inner, outer, fgDrawQuality, 1);
glTranslated(0.0, 0.0, width);
gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
gluDisk(quad.Get(), inner, outer, fgDrawQuality, 1);
glPopMatrix();
}
void TGLUtil::DrawReferenceMarker(const TGLCamera & camera,
const TGLVertex3 & pos,
Float_t radius,
const Float_t * rgba)
{
static const Float_t defColor[4] = { 0.98, 0.45, 0.0, 1.0 };
radius = camera.ViewportDeltaToWorld(pos, radius, radius).Mag();
DrawSphere(pos, radius, rgba ? rgba : defColor);
}
void TGLUtil::DrawSimpleAxes(const TGLCamera & camera,
const TGLBoundingBox & bbox,
Int_t axesType)
{
if (axesType == kAxesNone)
return;
static const Float_t axesColors[][4] = {
{0.5, 0.0, 0.0, 1.0},
{1.0, 0.0, 0.0, 1.0},
{0.0, 0.5, 0.0, 1.0},
{0.0, 1.0, 0.0, 1.0},
{0.0, 0.0, 0.5, 1.0},
{0.0, 0.0, 1.0, 1.0}
};
static const UChar_t xyz[][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}
};
TGLVector3 pixelVector = camera.ViewportDeltaToWorld(bbox.Center(), 1, 1);
Double_t pixelSize = pixelVector.Mag();
Double_t min[3] = { bbox.XMin(), bbox.YMin(), bbox.ZMin() };
Double_t max[3] = { bbox.XMax(), bbox.YMax(), bbox.ZMax() };
for (UInt_t i = 0; i < 3; i++) {
TGLVertex3 start;
TGLVector3 vector;
if (axesType == kAxesOrigin) {
start[(i+1)%3] = 0.0;
start[(i+2)%3] = 0.0;
} else {
start[(i+1)%3] = min[(i+1)%3];
start[(i+2)%3] = min[(i+2)%3];
}
vector[(i+1)%3] = 0.0;
vector[(i+2)%3] = 0.0;
if (min[i] < 0.0) {
if (max[i] > 0.0) {
start[i] = 0.0;
vector[i] = min[i];
} else {
start[i] = max[i];
vector[i] = min[i] - max[i];
}
DrawLine(start, vector, kLineHeadNone, pixelSize*2.5, axesColors[i*2]);
}
if (max[i] > 0.0) {
if (min[i] < 0.0) {
start[i] = 0.0;
vector[i] = max[i];
} else {
start[i] = min[i];
vector[i] = max[i] - min[i];
}
DrawLine(start, vector, kLineHeadNone, pixelSize*2.5, axesColors[i*2 + 1]);
}
}
if (axesType == kAxesOrigin) {
Float_t white[4] = { 1.0, 1.0, 1.0, 1.0 };
DrawSphere(TGLVertex3(0.0, 0.0, 0.0), pixelSize*2.0, white);
} else {
for (UInt_t j = 0; j < 3; j++) {
if (min[j] <= 0.0 && max[j] >= 0.0) {
TGLVertex3 zero;
zero[j] = 0.0;
zero[(j+1)%3] = min[(j+1)%3];
zero[(j+2)%3] = min[(j+2)%3];
DrawSphere(zero, pixelSize*2.0, axesColors[j*2 + 1]);
}
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
Double_t padPixels = 25.0;
glDisable(GL_LIGHTING);
for (UInt_t k = 0; k < 3; k++) {
SetDrawColors(axesColors[k*2+1]);
TGLVertex3 minPos, maxPos;
if (axesType == kAxesOrigin) {
minPos[(k+1)%3] = 0.0;
minPos[(k+2)%3] = 0.0;
} else {
minPos[(k+1)%3] = min[(k+1)%3];
minPos[(k+2)%3] = min[(k+2)%3];
}
maxPos = minPos;
minPos[k] = min[k];
maxPos[k] = max[k];
TGLVector3 axis = maxPos - minPos;
TGLVector3 axisViewport = camera.WorldDeltaToViewport(minPos, axis);
if (axisViewport.Mag() < 1) {
continue;
}
minPos -= camera.ViewportDeltaToWorld(minPos, padPixels*axisViewport.X()/axisViewport.Mag(),
padPixels*axisViewport.Y()/axisViewport.Mag());
axisViewport = camera.WorldDeltaToViewport(maxPos, -axis);
maxPos -= camera.ViewportDeltaToWorld(maxPos, padPixels*axisViewport.X()/axisViewport.Mag(),
padPixels*axisViewport.Y()/axisViewport.Mag());
DrawNumber(Form("%.0f", min[k]), minPos, kTRUE);
DrawNumber(Form("%.0f", max[k]), maxPos, kTRUE);
TGLVertex3 namePos = maxPos -
camera.ViewportDeltaToWorld(maxPos, padPixels*axisViewport.X()/axisViewport.Mag(),
padPixels*axisViewport.Y()/axisViewport.Mag());
glRasterPos3dv(namePos.CArr());
glBitmap(8, 8, 0.0, 4.0, 0.0, 0.0, xyz[k]);
}
}
void TGLUtil::DrawNumber(const TString & num,
const TGLVertex3 & pos,
Bool_t center)
{
static const UChar_t digits[][8] = {
{0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38},
{0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x10, 0x10},
{0x7c, 0x44, 0x20, 0x18, 0x04, 0x04, 0x44, 0x38},
{0x38, 0x44, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38},
{0x04, 0x04, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x44},
{0x7c, 0x44, 0x04, 0x04, 0x7c, 0x40, 0x40, 0x7c},
{0x7c, 0x44, 0x44, 0x44, 0x7c, 0x40, 0x40, 0x7c},
{0x20, 0x20, 0x20, 0x10, 0x08, 0x04, 0x44, 0x7c},
{0x38, 0x44, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38},
{0x7c, 0x44, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x7c},
{0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
Double_t xOffset = 0, yOffset = 0;
if (center)
{
xOffset = 3.5 * num.Length();
yOffset = 4.0;
}
glRasterPos3dv(pos.CArr());
for (Ssiz_t i = 0, e = num.Length(); i < e; ++i) {
if (num[i] == '.') {
glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[10]);
} else if (num[i] == '-') {
glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[11]);
} else if (num[i] == ' ') {
glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[12]);
} else if (num[i] >= '0' && num[i] <= '9') {
glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[num[i] - '0']);
}
}
}
TGLCapabilitySwitch::TGLCapabilitySwitch(Int_t what, Bool_t state) :
fWhat(what)
{
fState = glIsEnabled(fWhat);
fFlip = (fState != state);
if (fFlip)
SetState(state);
}
TGLCapabilitySwitch::~TGLCapabilitySwitch()
{
if (fFlip)
SetState(fState);
}
void TGLCapabilitySwitch::SetState(Bool_t s)
{
if (s)
glEnable (fWhat);
else
glDisable(fWhat);
}
TGLFloatHolder::TGLFloatHolder(Int_t what, Float_t state, void (*foo)(Float_t)) :
fWhat(what), fState(0), fFlip(kFALSE), fFoo(foo)
{
glGetFloatv(fWhat, &fState);
fFlip = (fState != state);
if (fFlip) fFoo(state);
}
TGLFloatHolder::~TGLFloatHolder()
{
if (fFlip) fFoo(fState);
}
TGLEnableGuard::TGLEnableGuard(Int_t cap)
: fCap(cap)
{
glEnable(GLenum(fCap));
}
TGLEnableGuard::~TGLEnableGuard()
{
glDisable(GLenum(fCap));
}
TGLDisableGuard::TGLDisableGuard(Int_t cap)
: fCap(cap)
{
glDisable(GLenum(fCap));
}
TGLDisableGuard::~TGLDisableGuard()
{
glEnable(GLenum(fCap));
}
ClassImp(TGLSelectionBuffer);
TGLSelectionBuffer::TGLSelectionBuffer()
: fWidth(0), fHeight(0)
{
}
TGLSelectionBuffer::~TGLSelectionBuffer()
{
}
void TGLSelectionBuffer::ReadColorBuffer(Int_t w, Int_t h)
{
fWidth = w;
fHeight = h;
fBuffer.resize(w * h * 4);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &fBuffer[0]);
}
void TGLSelectionBuffer::ReadColorBuffer(Int_t x, Int_t y, Int_t w, Int_t h)
{
fWidth = w;
fHeight = h;
fBuffer.resize(w * h * 4);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &fBuffer[0]);
}
const UChar_t *TGLSelectionBuffer::GetPixelColor(Int_t px, Int_t py)const
{
if (px < 0)
px = 0;
if (py < 0)
py = 0;
if (UInt_t(px * fWidth * 4 + py * 4) > fBuffer.size())
return &fBuffer[0];
return &fBuffer[px * fWidth * 4 + py * 4];
}
namespace Rgl {
const Float_t gRedEmission[] = {1.f, 0.f, 0.f, 1.f};
const Float_t gGreenEmission[] = {0.f, 1.f, 0.f, 1.f};
const Float_t gBlueEmission[] = {0.f, 0.f, 1.f, 1.f};
const Float_t gOrangeEmission[] = {1.f, 0.4f, 0.f, 1.f};
const Float_t gWhiteEmission[] = {1.f, 1.f, 1.f, 1.f};
const Float_t gGrayEmission[] = {0.3f,0.3f, 0.3f,1.f};
const Float_t gNullEmission[] = {0.f, 0.f, 0.f, 1.f};
namespace {
struct RGB_t {
Int_t fRGB[3];
};
RGB_t gColorTriplets[] = {{{255, 0, 0}},
{{0, 255, 0}},
{{0, 0, 255}},
{{255, 255, 0}},
{{255, 0, 255}},
{{0, 255, 255}},
{{255, 255, 255}}};
Bool_t operator < (const RGB_t &lhs, const RGB_t &rhs)
{
if (lhs.fRGB[0] < rhs.fRGB[0])
return kTRUE;
else if (lhs.fRGB[0] > rhs.fRGB[0])
return kFALSE;
else if (lhs.fRGB[1] < rhs.fRGB[1])
return kTRUE;
else if (lhs.fRGB[1] > rhs.fRGB[1])
return kFALSE;
else if (lhs.fRGB[2] < rhs.fRGB[2])
return kTRUE;
return kFALSE;
}
typedef std::map<Int_t, RGB_t> ColorLookupTable_t;
typedef ColorLookupTable_t::const_iterator CLTCI_t;
ColorLookupTable_t gObjectIDToColor;
typedef std::map<RGB_t, Int_t> ObjectLookupTable_t;
typedef ObjectLookupTable_t::const_iterator OLTCI_t;
ObjectLookupTable_t gColorToObjectID;
}
void ObjectIDToColor(Int_t objectID, Bool_t highColor)
{
if (!highColor)
glColor3ub(objectID & 0xff, (objectID & 0xff00) >> 8, (objectID & 0xff0000) >> 16);
else {
if (!gObjectIDToColor.size()) {
for (Int_t i = 0, id = 1; i < Int_t(sizeof gColorTriplets / sizeof(RGB_t)); ++i, ++id)
gObjectIDToColor[id] = gColorTriplets[i];
for (Int_t i = 0, id = 1; i < Int_t(sizeof gColorTriplets / sizeof(RGB_t)); ++i, ++id)
gColorToObjectID[gColorTriplets[i]] = id;
}
CLTCI_t it = gObjectIDToColor.find(objectID);
if (it != gObjectIDToColor.end())
glColor3ub(it->second.fRGB[0], it->second.fRGB[1], it->second.fRGB[2]);
else {
Error("ObjectIDToColor", "No color for such object ID: %d", objectID);
glColor3ub(0, 0, 0);
}
}
}
Int_t ColorToObjectID(const UChar_t *pixel, Bool_t highColor)
{
if (!highColor)
return pixel[0] | (pixel[1] << 8) | (pixel[2] << 16);
else {
if (!gObjectIDToColor.size())
return 0;
RGB_t triplet = {{pixel[0], pixel[1], pixel[2]}};
OLTCI_t it = gColorToObjectID.find(triplet);
if (it != gColorToObjectID.end())
return it->second;
else
return 0;
}
}
void DrawQuadOutline(const TGLVertex3 &v1, const TGLVertex3 &v2,
const TGLVertex3 &v3, const TGLVertex3 &v4)
{
glBegin(GL_LINE_LOOP);
glVertex3dv(v1.CArr());
glVertex3dv(v2.CArr());
glVertex3dv(v3.CArr());
glVertex3dv(v4.CArr());
glEnd();
}
void DrawQuadFilled(const TGLVertex3 &v0, const TGLVertex3 &v1, const TGLVertex3 &v2,
const TGLVertex3 &v3, const TGLVector3 &normal)
{
glBegin(GL_POLYGON);
glNormal3dv(normal.CArr());
glVertex3dv(v0.CArr());
glVertex3dv(v1.CArr());
glVertex3dv(v2.CArr());
glVertex3dv(v3.CArr());
glEnd();
}
void DrawSmoothFace(const TGLVertex3 &v1, const TGLVertex3 &v2, const TGLVertex3 &v3,
const TGLVector3 &norm1, const TGLVector3 &norm2, const TGLVector3 &norm3)
{
glBegin(GL_POLYGON);
glNormal3dv(norm1.CArr());
glVertex3dv(v1.CArr());
glNormal3dv(norm2.CArr());
glVertex3dv(v2.CArr());
glNormal3dv(norm3.CArr());
glVertex3dv(v3.CArr());
glEnd();
}
const Int_t gBoxFrontQuads[][4] = {{0, 1, 2, 3}, {4, 0, 3, 5}, {4, 5, 6, 7}, {7, 6, 2, 1}};
const Double_t gBoxFrontNormals[][3] = {{-1., 0., 0.}, {0., -1., 0.}, {1., 0., 0.}, {0., 1., 0.}};
const Int_t gBoxFrontPlanes[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}};
void DrawBoxFront(Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax,
Double_t zMin, Double_t zMax, Int_t fp)
{
if (zMax < zMin)
std::swap(zMax, zMin);
glBegin(GL_POLYGON);
glNormal3d(0., 0., -1.);
glVertex3d(xMax, yMin, zMin);
glVertex3d(xMin, yMin, zMin);
glVertex3d(xMin, yMax, zMin);
glVertex3d(xMax, yMax, zMin);
glEnd();
const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
{xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
const Int_t *verts = gBoxFrontQuads[gBoxFrontPlanes[fp][0]];
glBegin(GL_POLYGON);
glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][0]]);
glVertex3dv(box[verts[0]]);
glVertex3dv(box[verts[1]]);
glVertex3dv(box[verts[2]]);
glVertex3dv(box[verts[3]]);
glEnd();
verts = gBoxFrontQuads[gBoxFrontPlanes[fp][1]];
glBegin(GL_POLYGON);
glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][1]]);
glVertex3dv(box[verts[0]]);
glVertex3dv(box[verts[1]]);
glVertex3dv(box[verts[2]]);
glVertex3dv(box[verts[3]]);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(0., 0., 1.);
glVertex3d(xMax, yMin, zMax);
glVertex3d(xMax, yMax, zMax);
glVertex3d(xMin, yMax, zMax);
glVertex3d(xMin, yMin, zMax);
glEnd();
}
void DrawBoxFrontTextured(Double_t xMin, Double_t xMax, Double_t yMin,
Double_t yMax, Double_t zMin, Double_t zMax,
Double_t texMin, Double_t texMax, Int_t fp)
{
if (zMax < zMin) {
std::swap(zMax, zMin);
std::swap(texMax, texMin);
}
glBegin(GL_POLYGON);
glNormal3d(0., 0., 1.);
glTexCoord1d(texMax);
glVertex3d(xMax, yMin, zMax);
glVertex3d(xMax, yMax, zMax);
glVertex3d(xMin, yMax, zMax);
glVertex3d(xMin, yMin, zMax);
glEnd();
glBegin(GL_POLYGON);
glTexCoord1d(texMin);
glNormal3d(0., 0., -1.);
glVertex3d(xMax, yMin, zMin);
glVertex3d(xMin, yMin, zMin);
glVertex3d(xMin, yMax, zMin);
glVertex3d(xMax, yMax, zMin);
glEnd();
const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
{xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
const Double_t tex[] = {texMax, texMax, texMin, texMin, texMax, texMin, texMin, texMax};
const Int_t *verts = gBoxFrontQuads[gBoxFrontPlanes[fp][0]];
glBegin(GL_POLYGON);
glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][0]]);
glTexCoord1d(tex[verts[0]]);
glVertex3dv(box[verts[0]]);
glTexCoord1d(tex[verts[1]]);
glVertex3dv(box[verts[1]]);
glTexCoord1d(tex[verts[2]]);
glVertex3dv(box[verts[2]]);
glTexCoord1d(tex[verts[3]]);
glVertex3dv(box[verts[3]]);
glEnd();
verts = gBoxFrontQuads[gBoxFrontPlanes[fp][1]];
glBegin(GL_POLYGON);
glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][1]]);
glTexCoord1d(tex[verts[0]]);
glVertex3dv(box[verts[0]]);
glTexCoord1d(tex[verts[1]]);
glVertex3dv(box[verts[1]]);
glTexCoord1d(tex[verts[2]]);
glVertex3dv(box[verts[2]]);
glTexCoord1d(tex[verts[3]]);
glVertex3dv(box[verts[3]]);
glEnd();
}
void DrawCylinder(TGLQuadric *quadric, Double_t xMin, Double_t xMax, Double_t yMin,
Double_t yMax, Double_t zMin, Double_t zMax)
{
GLUquadric *quad = quadric->Get();
if (quad) {
if (zMin > zMax)
std::swap(zMin, zMax);
const Double_t xCenter = xMin + (xMax - xMin) / 2;
const Double_t yCenter = yMin + (yMax - yMin) / 2;
const Double_t radius = TMath::Min((xMax - xMin) / 2, (yMax - yMin) / 2);
glPushMatrix();
glTranslated(xCenter, yCenter, zMin);
gluCylinder(quad, radius, radius, zMax - zMin, 40, 1);
glPopMatrix();
glPushMatrix();
glTranslated(xCenter, yCenter, zMax);
gluDisk(quad, 0., radius, 40, 1);
glPopMatrix();
glPushMatrix();
glTranslated(xCenter, yCenter, zMin);
glRotated(180., 0., 1., 0.);
gluDisk(quad, 0., radius, 40, 1);
glPopMatrix();
}
}
void DrawSphere(TGLQuadric *quadric, Double_t xMin, Double_t xMax, Double_t yMin,
Double_t yMax, Double_t zMin, Double_t zMax)
{
GLUquadric *quad = quadric->Get();
if (quad) {
const Double_t xCenter = xMin + (xMax - xMin) / 2;
const Double_t yCenter = yMin + (yMax - yMin) / 2;
const Double_t zCenter = zMin + (zMax - zMin) / 2;
const Double_t radius = TMath::Min((zMax - zMin) / 2,
TMath::Min((xMax - xMin) / 2, (yMax - yMin) / 2));
glPushMatrix();
glTranslated(xCenter, yCenter, zCenter);
gluSphere(quad, radius, 10, 10);
glPopMatrix();
}
}
void DrawError(Double_t xMin, Double_t xMax, Double_t yMin,
Double_t yMax, Double_t zMin, Double_t zMax)
{
const Double_t xWid = xMax - xMin;
const Double_t yWid = yMax - yMin;
glBegin(GL_LINES);
glVertex3d(xMin + xWid / 2, yMin + yWid / 2, zMin);
glVertex3d(xMin + xWid / 2, yMin + yWid / 2, zMax);
glEnd();
glBegin(GL_LINES);
glVertex3d(xMin + xWid / 2, yMin, zMin);
glVertex3d(xMin + xWid / 2, yMax, zMin);
glEnd();
glBegin(GL_LINES);
glVertex3d(xMin, yMin + yWid / 2, zMin);
glVertex3d(xMax, yMin + yWid / 2, zMin);
glEnd();
}
void CylindricalNormal(const Double_t *v, Double_t *normal)
{
const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1]);
if (n > 0.) {
normal[0] = v[0] / n;
normal[1] = v[1] / n;
normal[2] = 0.;
} else {
normal[0] = v[0];
normal[1] = v[1];
normal[2] = 0.;
}
}
void CylindricalNormalInv(const Double_t *v, Double_t *normal)
{
const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1]);
if (n > 0.) {
normal[0] = -v[0] / n;
normal[1] = -v[1] / n;
normal[2] = 0.;
} else {
normal[0] = -v[0];
normal[1] = -v[1];
normal[2] = 0.;
}
}
void DrawTrapezoid(const Double_t ver[][2], Double_t zMin, Double_t zMax, Bool_t color)
{
if (zMin > zMax)
std::swap(zMin, zMax);
glBegin(GL_POLYGON);
glNormal3d(0., 0., 1.);
glVertex3d(ver[0][0], ver[0][1], zMax);
glVertex3d(ver[1][0], ver[1][1], zMax);
glVertex3d(ver[2][0], ver[2][1], zMax);
glVertex3d(ver[3][0], ver[3][1], zMax);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(0., 0., -1.);
glVertex3d(ver[0][0], ver[0][1], zMin);
glVertex3d(ver[3][0], ver[3][1], zMin);
glVertex3d(ver[2][0], ver[2][1], zMin);
glVertex3d(ver[1][0], ver[1][1], zMin);
glEnd();
Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
{ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
{ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
{ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
Double_t normal[3] = {0.};
glBegin(GL_POLYGON);
CylindricalNormal(trapezoid[1], normal), glNormal3dv(normal), glVertex3dv(trapezoid[1]);
CylindricalNormal(trapezoid[2], normal), glNormal3dv(normal), glVertex3dv(trapezoid[2]);
CylindricalNormal(trapezoid[6], normal), glNormal3dv(normal), glVertex3dv(trapezoid[6]);
CylindricalNormal(trapezoid[5], normal), glNormal3dv(normal), glVertex3dv(trapezoid[5]);
glEnd();
glBegin(GL_POLYGON);
CylindricalNormalInv(trapezoid[0], normal), glNormal3dv(normal), glVertex3dv(trapezoid[0]);
CylindricalNormalInv(trapezoid[4], normal), glNormal3dv(normal), glVertex3dv(trapezoid[4]);
CylindricalNormalInv(trapezoid[7], normal), glNormal3dv(normal), glVertex3dv(trapezoid[7]);
CylindricalNormalInv(trapezoid[3], normal), glNormal3dv(normal), glVertex3dv(trapezoid[3]);
glEnd();
glBegin(GL_POLYGON);
if (color) {
TMath::Normal2Plane(trapezoid[0], trapezoid[1], trapezoid[5], normal);
glNormal3dv(normal);
}
glVertex3dv(trapezoid[0]);
glVertex3dv(trapezoid[1]);
glVertex3dv(trapezoid[5]);
glVertex3dv(trapezoid[4]);
glEnd();
glBegin(GL_POLYGON);
if (color) {
TMath::Normal2Plane(trapezoid[3], trapezoid[7], trapezoid[6], normal);
glNormal3dv(normal);
}
glVertex3dv(trapezoid[3]);
glVertex3dv(trapezoid[7]);
glVertex3dv(trapezoid[6]);
glVertex3dv(trapezoid[2]);
glEnd();
}
void DrawTrapezoidTextured(const Double_t ver[][2], Double_t zMin, Double_t zMax,
Double_t texMin, Double_t texMax)
{
if (zMin > zMax) {
std::swap(zMin, zMax);
std::swap(texMin, texMax);
}
glBegin(GL_POLYGON);
glNormal3d(0., 0., 1.);
glTexCoord1d(texMax);
glVertex3d(ver[0][0], ver[0][1], zMax);
glVertex3d(ver[1][0], ver[1][1], zMax);
glVertex3d(ver[2][0], ver[2][1], zMax);
glVertex3d(ver[3][0], ver[3][1], zMax);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(0., 0., -1.);
glTexCoord1d(texMin);
glVertex3d(ver[0][0], ver[0][1], zMin);
glVertex3d(ver[3][0], ver[3][1], zMin);
glVertex3d(ver[2][0], ver[2][1], zMin);
glVertex3d(ver[1][0], ver[1][1], zMin);
glEnd();
Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
{ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
{ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
{ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
Double_t normal[3] = {0.};
glBegin(GL_POLYGON);
CylindricalNormal(trapezoid[1], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[1]);
CylindricalNormal(trapezoid[2], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[2]);
CylindricalNormal(trapezoid[6], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[6]);
CylindricalNormal(trapezoid[5], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[5]);
glEnd();
glBegin(GL_POLYGON);
CylindricalNormalInv(trapezoid[0], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[0]);
CylindricalNormalInv(trapezoid[4], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[4]);
CylindricalNormalInv(trapezoid[7], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[7]);
CylindricalNormalInv(trapezoid[3], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[3]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(trapezoid[0], trapezoid[1], trapezoid[5], normal);
glNormal3dv(normal);
glTexCoord1d(texMin);
glVertex3dv(trapezoid[0]);
glTexCoord1d(texMin);
glVertex3dv(trapezoid[1]);
glTexCoord1d(texMax);
glVertex3dv(trapezoid[5]);
glTexCoord1d(texMax);
glVertex3dv(trapezoid[4]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(trapezoid[3], trapezoid[7], trapezoid[6], normal);
glNormal3dv(normal);
glTexCoord1d(texMin);
glVertex3dv(trapezoid[3]);
glTexCoord1d(texMax);
glVertex3dv(trapezoid[7]);
glTexCoord1d(texMax);
glVertex3dv(trapezoid[6]);
glTexCoord1d(texMin);
glVertex3dv(trapezoid[2]);
glEnd();
}
void DrawTrapezoidTextured2(const Double_t ver[][2], Double_t zMin, Double_t zMax,
Double_t texMin, Double_t texMax)
{
if (zMin > zMax)
std::swap(zMin, zMax);
const Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
{ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
{ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
{ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
const Double_t tex[] = {texMin, texMax, texMax, texMin, texMin, texMax, texMax, texMin};
glBegin(GL_POLYGON);
glNormal3d(0., 0., 1.);
glTexCoord1d(tex[4]), glVertex3dv(trapezoid[4]);
glTexCoord1d(tex[5]), glVertex3dv(trapezoid[5]);
glTexCoord1d(tex[6]), glVertex3dv(trapezoid[6]);
glTexCoord1d(tex[7]), glVertex3dv(trapezoid[7]);
glEnd();
glBegin(GL_POLYGON);
glNormal3d(0., 0., -1.);
glTexCoord1d(tex[0]), glVertex3dv(trapezoid[0]);
glTexCoord1d(tex[3]), glVertex3dv(trapezoid[3]);
glTexCoord1d(tex[2]), glVertex3dv(trapezoid[2]);
glTexCoord1d(tex[1]), glVertex3dv(trapezoid[1]);
glEnd();
glBegin(GL_POLYGON);
Double_t normal[3] = {};
CylindricalNormal(trapezoid[1], normal), glNormal3dv(normal), glTexCoord1d(tex[1]), glVertex3dv(trapezoid[1]);
CylindricalNormal(trapezoid[2], normal), glNormal3dv(normal), glTexCoord1d(tex[2]), glVertex3dv(trapezoid[2]);
CylindricalNormal(trapezoid[6], normal), glNormal3dv(normal), glTexCoord1d(tex[6]), glVertex3dv(trapezoid[6]);
CylindricalNormal(trapezoid[5], normal), glNormal3dv(normal), glTexCoord1d(tex[5]), glVertex3dv(trapezoid[5]);
glEnd();
glBegin(GL_POLYGON);
CylindricalNormalInv(trapezoid[0], normal), glNormal3dv(normal), glTexCoord1d(tex[0]), glVertex3dv(trapezoid[0]);
CylindricalNormalInv(trapezoid[4], normal), glNormal3dv(normal), glTexCoord1d(tex[4]), glVertex3dv(trapezoid[4]);
CylindricalNormalInv(trapezoid[7], normal), glNormal3dv(normal), glTexCoord1d(tex[7]), glVertex3dv(trapezoid[7]);
CylindricalNormalInv(trapezoid[3], normal), glNormal3dv(normal), glTexCoord1d(tex[3]), glVertex3dv(trapezoid[3]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(trapezoid[0], trapezoid[1], trapezoid[5], normal);
glNormal3dv(normal);
glTexCoord1d(tex[0]), glVertex3dv(trapezoid[0]);
glTexCoord1d(tex[1]), glVertex3dv(trapezoid[1]);
glTexCoord1d(tex[5]), glVertex3dv(trapezoid[5]);
glTexCoord1d(tex[4]), glVertex3dv(trapezoid[4]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(trapezoid[3], trapezoid[7], trapezoid[6], normal);
glNormal3dv(normal);
glTexCoord1d(tex[3]), glVertex3dv(trapezoid[3]);
glTexCoord1d(tex[7]), glVertex3dv(trapezoid[7]);
glTexCoord1d(tex[6]), glVertex3dv(trapezoid[6]);
glTexCoord1d(tex[2]), glVertex3dv(trapezoid[2]);
glEnd();
}
void SphericalNormal(const Double_t *v, Double_t *normal)
{
const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
if (n > 0.) {
normal[0] = v[0] / n;
normal[1] = v[1] / n;
normal[2] = v[2] / n;
} else {
normal[0] = v[0];
normal[1] = v[1];
normal[2] = v[2];
}
}
void SphericalNormalInv(const Double_t *v, Double_t *normal)
{
const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
if (n > 0.) {
normal[0] = -v[0] / n;
normal[1] = -v[1] / n;
normal[2] = -v[2] / n;
} else {
normal[0] = -v[0];
normal[1] = -v[1];
normal[2] = -v[2];
}
}
void DrawTrapezoid(const Double_t ver[][3])
{
Double_t normal[3] = {0.};
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[1], ver[2], ver[3], normal);
glNormal3dv(normal);
glVertex3dv(ver[0]);
glVertex3dv(ver[1]);
glVertex3dv(ver[2]);
glVertex3dv(ver[3]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[4], ver[7], ver[6], normal);
glNormal3dv(normal);
glVertex3dv(ver[4]);
glVertex3dv(ver[7]);
glVertex3dv(ver[6]);
glVertex3dv(ver[5]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[0], ver[3], ver[7], normal);
glNormal3dv(normal);
glVertex3dv(ver[0]);
glVertex3dv(ver[3]);
glVertex3dv(ver[7]);
glVertex3dv(ver[4]);
glEnd();
glBegin(GL_POLYGON);
SphericalNormal(ver[3], normal), glNormal3dv(normal), glVertex3dv(ver[3]);
SphericalNormal(ver[2], normal), glNormal3dv(normal), glVertex3dv(ver[2]);
SphericalNormal(ver[6], normal), glNormal3dv(normal), glVertex3dv(ver[6]);
SphericalNormal(ver[7], normal), glNormal3dv(normal), glVertex3dv(ver[7]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[5], ver[6], ver[2], normal);
glNormal3dv(normal);
glVertex3dv(ver[5]);
glVertex3dv(ver[6]);
glVertex3dv(ver[2]);
glVertex3dv(ver[1]);
glEnd();
glBegin(GL_POLYGON);
SphericalNormalInv(ver[0], normal), glNormal3dv(normal), glVertex3dv(ver[0]);
SphericalNormalInv(ver[4], normal), glNormal3dv(normal), glVertex3dv(ver[4]);
SphericalNormalInv(ver[5], normal), glNormal3dv(normal), glVertex3dv(ver[5]);
SphericalNormalInv(ver[1], normal), glNormal3dv(normal), glVertex3dv(ver[1]);
glEnd();
}
void DrawTrapezoidTextured(const Double_t ver[][3], Double_t texMin, Double_t texMax)
{
Double_t normal[3] = {};
if (texMin > texMax)
std::swap(texMin, texMax);
const Double_t tex[] = {texMin, texMin, texMax, texMax, texMin, texMin, texMax, texMax};
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[0], ver[1], ver[2], normal);
glNormal3dv(normal);
glTexCoord1d(tex[0]), glVertex3dv(ver[0]);
glTexCoord1d(tex[1]), glVertex3dv(ver[1]);
glTexCoord1d(tex[2]), glVertex3dv(ver[2]);
glTexCoord1d(tex[3]), glVertex3dv(ver[3]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[4], ver[7], ver[6], normal);
glNormal3dv(normal);
glTexCoord1d(tex[4]), glVertex3dv(ver[4]);
glTexCoord1d(tex[7]), glVertex3dv(ver[7]);
glTexCoord1d(tex[6]), glVertex3dv(ver[6]);
glTexCoord1d(tex[5]), glVertex3dv(ver[5]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[0], ver[3], ver[7], normal);
glNormal3dv(normal);
glTexCoord1d(tex[0]), glVertex3dv(ver[0]);
glTexCoord1d(tex[3]), glVertex3dv(ver[3]);
glTexCoord1d(tex[7]), glVertex3dv(ver[7]);
glTexCoord1d(tex[4]), glVertex3dv(ver[4]);
glEnd();
glBegin(GL_POLYGON);
SphericalNormal(ver[3], normal), glNormal3dv(normal), glTexCoord1d(tex[3]), glVertex3dv(ver[3]);
SphericalNormal(ver[2], normal), glNormal3dv(normal), glTexCoord1d(tex[2]), glVertex3dv(ver[2]);
SphericalNormal(ver[6], normal), glNormal3dv(normal), glTexCoord1d(tex[6]), glVertex3dv(ver[6]);
SphericalNormal(ver[7], normal), glNormal3dv(normal), glTexCoord1d(tex[7]), glVertex3dv(ver[7]);
glEnd();
glBegin(GL_POLYGON);
TMath::Normal2Plane(ver[5], ver[6], ver[2], normal);
glNormal3dv(normal);
glTexCoord1d(tex[5]), glVertex3dv(ver[5]);
glTexCoord1d(tex[6]), glVertex3dv(ver[6]);
glTexCoord1d(tex[2]), glVertex3dv(ver[2]);
glTexCoord1d(tex[1]), glVertex3dv(ver[1]);
glEnd();
glBegin(GL_POLYGON);
SphericalNormalInv(ver[0], normal), glNormal3dv(normal), glTexCoord1d(tex[0]), glVertex3dv(ver[0]);
SphericalNormalInv(ver[4], normal), glNormal3dv(normal), glTexCoord1d(tex[4]), glVertex3dv(ver[4]);
SphericalNormalInv(ver[5], normal), glNormal3dv(normal), glTexCoord1d(tex[5]), glVertex3dv(ver[5]);
SphericalNormalInv(ver[1], normal), glNormal3dv(normal), glTexCoord1d(tex[1]), glVertex3dv(ver[1]);
glEnd();
}
void Draw2DAxis(TAxis *axis, Double_t xMin, Double_t yMin, Double_t xMax, Double_t yMax,
Double_t min, Double_t max, Bool_t log, Bool_t z = kFALSE)
{
std::string option;
option.reserve(20);
if (xMin > xMax || z) option += "SDH=+";
else option += "SDH=-";
if (log) option += 'G';
Int_t nDiv = axis->GetNdivisions();
if (nDiv < 0) {
option += 'N';
nDiv = -nDiv;
}
TGaxis axisPainter;
axisPainter.SetLineWidth(1);
static const Double_t zero = 0.001;
if (TMath::Abs(xMax - xMin) >= zero || TMath::Abs(yMax - yMin) >= zero) {
axisPainter.ImportAxisAttributes(axis);
axisPainter.SetLabelOffset(axis->GetLabelOffset() + axis->GetTickLength());
if (log) {
min = TMath::Power(10, min);
max = TMath::Power(10, max);
}
if (axis->GetTimeDisplay()) {
option += 't';
if (!strlen(axis->GetTimeFormatOnly()))
axisPainter.SetTimeFormat(axis->ChooseTimeFormat(max - min));
else
axisPainter.SetTimeFormat(axis->GetTimeFormat());
}
axisPainter.SetOption(option.c_str());
axisPainter.PaintAxis(xMin, yMin, xMax, yMax, min, max, nDiv, option.c_str());
}
}
const Int_t gFramePoints[][2] = {{3, 1}, {0, 2}, {1, 3}, {2, 0}};
const Int_t gAxisType[][2] = {{1, 0}, {0, 1}, {1, 0}, {0, 1}};
void DrawAxes(Int_t fp, const Int_t *vp, const TGLVertex3 *box, const TGLPlotCoordinates *coord,
TAxis *xAxis, TAxis *yAxis, TAxis *zAxis)
{
const Int_t left = gFramePoints[fp][0];
const Int_t right = gFramePoints[fp][1];
const Double_t xLeft = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
+ box[left].X() - vp[0]));
const Double_t yLeft = gPad->AbsPixeltoY(Int_t(vp[3] - box[left].Y()
+ (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
* gPad->GetWh() + vp[1]));
const Double_t xMid = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
+ box[fp].X() - vp[0]));
const Double_t yMid = gPad->AbsPixeltoY(Int_t(vp[3] - box[fp].Y()
+ (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
* gPad->GetWh() + vp[1]));
const Double_t xRight = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC()
* gPad->GetWw() + box[right].X() - vp[0]));
const Double_t yRight = gPad->AbsPixeltoY(Int_t(vp[3] - box[right].Y()
+ (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
* gPad->GetWh() + vp[1]));
const Double_t points[][2] = {{coord->GetXRange().first, coord->GetYRange().first },
{coord->GetXRange().second, coord->GetYRange().first },
{coord->GetXRange().second, coord->GetYRange().second},
{coord->GetXRange().first, coord->GetYRange().second}};
const Int_t leftType = gAxisType[fp][0];
const Int_t rightType = gAxisType[fp][1];
const Double_t leftLabel = points[left][leftType];
const Double_t leftMidLabel = points[fp][leftType];
const Double_t rightMidLabel = points[fp][rightType];
const Double_t rightLabel = points[right][rightType];
if (xLeft - xMid || yLeft - yMid) {
TAxis *axis = leftType ? yAxis : xAxis;
if (leftLabel < leftMidLabel)
Draw2DAxis(axis, xLeft, yLeft, xMid, yMid, leftLabel, leftMidLabel,
leftType ? coord->GetYLog() : coord->GetXLog());
else
Draw2DAxis(axis, xMid, yMid, xLeft, yLeft, leftMidLabel, leftLabel,
leftType ? coord->GetYLog() : coord->GetXLog());
}
if (xRight - xMid || yRight - yMid) {
TAxis *axis = rightType ? yAxis : xAxis;
if (rightMidLabel < rightLabel)
Draw2DAxis(axis, xMid, yMid, xRight, yRight, rightMidLabel, rightLabel,
rightType ? coord->GetYLog() : coord->GetXLog());
else
Draw2DAxis(axis, xRight, yRight, xMid, yMid, rightLabel, rightMidLabel,
rightType ? coord->GetYLog() : coord->GetXLog());
}
const Double_t xUp = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
+ box[left + 4].X() - vp[0]));
const Double_t yUp = gPad->AbsPixeltoY(Int_t(vp[3] - box[left + 4].Y()
+ (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
* gPad->GetWh() + vp[1]));
Draw2DAxis(zAxis, xLeft, yLeft, xUp, yUp, coord->GetZRange().first,
coord->GetZRange().second, coord->GetZLog(), kTRUE);
}
void SetZLevels(TAxis *zAxis, Double_t zMin, Double_t zMax,
Double_t zScale, std::vector<Double_t> &zLevels)
{
Int_t nDiv = zAxis->GetNdivisions() % 100;
Int_t nBins = 0;
Double_t binLow = 0., binHigh = 0., binWidth = 0.;
THLimitsFinder::Optimize(zMin, zMax, nDiv, binLow, binHigh, nBins, binWidth, " ");
zLevels.resize(nBins + 1);
for (Int_t i = 0; i < nBins + 1; ++i)
zLevels[i] = (binLow + i * binWidth) * zScale;
}
void DrawFaceTextured(const TGLVertex3 &v1, const TGLVertex3 &v2, const TGLVertex3 &v3,
Double_t t1, Double_t t2, Double_t t3, const TGLVector3 &norm1,
const TGLVector3 &norm2, const TGLVector3 &norm3)
{
glBegin(GL_POLYGON);
glNormal3dv(norm1.CArr());
glTexCoord1d(t1);
glVertex3dv(v1.CArr());
glNormal3dv(norm2.CArr());
glTexCoord1d(t2);
glVertex3dv(v2.CArr());
glNormal3dv(norm3.CArr());
glTexCoord1d(t3);
glVertex3dv(v3.CArr());
glEnd();
}
void DrawFaceTextured(const TGLVertex3 &v1, const TGLVertex3 &v2, const TGLVertex3 &v3,
Double_t t1, Double_t t2, Double_t t3, Double_t z,
const TGLVector3 &normal)
{
glBegin(GL_POLYGON);
glNormal3dv(normal.CArr());
glTexCoord1d(t1);
glVertex3d(v1.X(), v1.Y(), z);
glTexCoord1d(t2);
glVertex3d(v2.X(), v2.Y(), z);
glTexCoord1d(t3);
glVertex3d(v3.X(), v3.Y(), z);
glEnd();
}
void GetColor(Float_t v, Float_t vmin, Float_t vmax, Int_t type, Float_t *rgba)
{
Float_t dv,vmid;
Float_t c1[3] = {}, c2[3] = {}, c3[3] = {};
Float_t ratio ;
rgba[3] = 1.f;
if (v < vmin)
v = vmin;
if (v > vmax)
v = vmax;
dv = vmax - vmin;
switch (type) {
case 0:
rgba[0] = 1.f;
rgba[1] = 1.f;
rgba[2] = 1.f;
break;
case 1:
if (v < (vmin + 0.25 * dv)) {
rgba[0] = 0;
rgba[1] = 4 * (v - vmin) / dv;
rgba[2] = 1;
} else if (v < (vmin + 0.5 * dv)) {
rgba[0] = 0;
rgba[1] = 1;
rgba[2] = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
} else if (v < (vmin + 0.75 * dv)) {
rgba[0] = 4 * (v - vmin - 0.5 * dv) / dv;
rgba[1] = 1;
rgba[2] = 0;
} else {
rgba[0] = 1;
rgba[1] = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
rgba[2] = 0;
}
break;
case 2:
rgba[0] = (v - vmin) / dv;
rgba[1] = 0;
rgba[2] = (vmax - v) / dv;
break;
case 3:
rgba[0] = (v - vmin) / dv;
rgba[1] = rgba[0];
rgba[2] = rgba[0];
break;
case 4:
if (v < (vmin + dv / 6.0)) {
rgba[0] = 1;
rgba[1] = 6 * (v - vmin) / dv;
rgba[2] = 0;
} else if (v < (vmin + 2.0 * dv / 6.0)) {
rgba[0] = 1 + 6 * (vmin + dv / 6.0 - v) / dv;
rgba[1] = 1;
rgba[2] = 0;
} else if (v < (vmin + 3.0 * dv / 6.0)) {
rgba[0] = 0;
rgba[1] = 1;
rgba[2] = 6 * (v - vmin - 2.0 * dv / 6.0) / dv;
} else if (v < (vmin + 4.0 * dv / 6.0)) {
rgba[0] = 0;
rgba[1] = 1 + 6 * (vmin + 3.0 * dv / 6.0 - v) / dv;
rgba[2] = 1;
} else if (v < (vmin + 5.0 * dv / 6.0)) {
rgba[0] = 6 * (v - vmin - 4.0 * dv / 6.0) / dv;
rgba[1] = 0;
rgba[2] = 1;
} else {
rgba[0] = 1;
rgba[1] = 0;
rgba[2] = 1 + 6 * (vmin + 5.0 * dv / 6.0 - v) / dv;
}
break;
case 5:
rgba[0] = (v - vmin) / (vmax - vmin);
rgba[1] = 1;
rgba[2] = 0;
break;
case 6:
rgba[0] = (v - vmin) / (vmax - vmin);
rgba[1] = (vmax - v) / (vmax - vmin);
rgba[2] = rgba[0];
break;
case 7:
if (v < (vmin + 0.25 * dv)) {
rgba[0] = 0;
rgba[1] = 4 * (v - vmin) / dv;
rgba[2] = 1 - rgba[1];
} else if (v < (vmin + 0.5 * dv)) {
rgba[0] = 4 * (v - vmin - 0.25 * dv) / dv;
rgba[1] = 1 - rgba[0];
rgba[2] = 0;
} else if (v < (vmin + 0.75 * dv)) {
rgba[1] = 4 * (v - vmin - 0.5 * dv) / dv;
rgba[0] = 1 - rgba[1];
rgba[2] = 0;
} else {
rgba[0] = 0;
rgba[2] = 4 * (v - vmin - 0.75 * dv) / dv;
rgba[1] = 1 - rgba[2];
}
break;
case 8:
if (v < (vmin + 0.5 * dv)) {
rgba[0] = 2 * (v - vmin) / dv;
rgba[1] = rgba[0];
rgba[2] = rgba[0];
} else {
rgba[0] = 1 - 2 * (v - vmin - 0.5 * dv) / dv;
rgba[1] = rgba[0];
rgba[2] = rgba[0];
}
break;
case 9:
if (v < (vmin + dv / 3)) {
rgba[2] = 3 * (v - vmin) / dv;
rgba[1] = 0;
rgba[0] = 1 - rgba[2];
} else if (v < (vmin + 2 * dv / 3)) {
rgba[0] = 0;
rgba[1] = 3 * (v - vmin - dv / 3) / dv;
rgba[2] = 1;
} else {
rgba[0] = 3 * (v - vmin - 2 * dv / 3) / dv;
rgba[1] = 1 - rgba[0];
rgba[2] = 1;
}
break;
case 10:
if (v < (vmin + 0.2 * dv)) {
rgba[0] = 0;
rgba[1] = 5 * (v - vmin) / dv;
rgba[2] = 1;
} else if (v < (vmin + 0.4 * dv)) {
rgba[0] = 0;
rgba[1] = 1;
rgba[2] = 1 + 5 * (vmin + 0.2 * dv - v) / dv;
} else if (v < (vmin + 0.6 * dv)) {
rgba[0] = 5 * (v - vmin - 0.4 * dv) / dv;
rgba[1] = 1;
rgba[2] = 0;
} else if (v < (vmin + 0.8 * dv)) {
rgba[0] = 1;
rgba[1] = 1 - 5 * (v - vmin - 0.6 * dv) / dv;
rgba[2] = 0;
} else {
rgba[0] = 1;
rgba[1] = 5 * (v - vmin - 0.8 * dv) / dv;
rgba[2] = 5 * (v - vmin - 0.8 * dv) / dv;
}
break;
case 11:
c1[0] = 200 / 255.0; c1[1] = 60 / 255.0; c1[2] = 0 / 255.0;
c2[0] = 250 / 255.0; c2[1] = 160 / 255.0; c2[2] = 110 / 255.0;
rgba[0] = (c2[0] - c1[0]) * (v - vmin) / dv + c1[0];
rgba[1] = (c2[1] - c1[1]) * (v - vmin) / dv + c1[1];
rgba[2] = (c2[2] - c1[2]) * (v - vmin) / dv + c1[2];
break;
case 12:
c1[0] = 55 / 255.0; c1[1] = 55 / 255.0; c1[2] = 45 / 255.0;
c2[0] = 200 / 255.0; c2[1] = 60 / 255.0; c2[2] = 0 / 255.0;
c3[0] = 250 / 255.0; c3[1] = 160 / 255.0; c3[2] = 110 / 255.0;
ratio = 0.4;
vmid = vmin + ratio * dv;
if (v < vmid) {
rgba[0] = (c2[0] - c1[0]) * (v - vmin) / (ratio*dv) + c1[0];
rgba[1] = (c2[1] - c1[1]) * (v - vmin) / (ratio*dv) + c1[1];
rgba[2] = (c2[2] - c1[2]) * (v - vmin) / (ratio*dv) + c1[2];
} else {
rgba[0] = (c3[0] - c2[0]) * (v - vmid) / ((1-ratio)*dv) + c2[0];
rgba[1] = (c3[1] - c2[1]) * (v - vmid) / ((1-ratio)*dv) + c2[1];
rgba[2] = (c3[2] - c2[2]) * (v - vmid) / ((1-ratio)*dv) + c2[2];
}
break;
case 13:
c1[0] = 0 / 255.0; c1[1] = 255 / 255.0; c1[2] = 0 / 255.0;
c2[0] = 255 / 255.0; c2[1] = 150 / 255.0; c2[2] = 0 / 255.0;
c3[0] = 255 / 255.0; c3[1] = 250 / 255.0; c3[2] = 240 / 255.0;
ratio = 0.3;
vmid = vmin + ratio * dv;
if (v < vmid) {
rgba[0] = (c2[0] - c1[0]) * (v - vmin) / (ratio*dv) + c1[0];
rgba[1] = (c2[1] - c1[1]) * (v - vmin) / (ratio*dv) + c1[1];
rgba[2] = (c2[2] - c1[2]) * (v - vmin) / (ratio*dv) + c1[2];
} else {
rgba[0] = (c3[0] - c2[0]) * (v - vmid) / ((1-ratio)*dv) + c2[0];
rgba[1] = (c3[1] - c2[1]) * (v - vmid) / ((1-ratio)*dv) + c2[1];
rgba[2] = (c3[2] - c2[2]) * (v - vmid) / ((1-ratio)*dv) + c2[2];
}
break;
case 14:
rgba[0] = 1;
rgba[1] = 1 - (v - vmin) / dv;
rgba[2] = 0;
break;
case 15:
if (v < (vmin + 0.25 * dv)) {
rgba[0] = 0;
rgba[1] = 4 * (v - vmin) / dv;
rgba[2] = 1;
} else if (v < (vmin + 0.5 * dv)) {
rgba[0] = 0;
rgba[1] = 1;
rgba[2] = 1 - 4 * (v - vmin - 0.25 * dv) / dv;
} else if (v < (vmin + 0.75 * dv)) {
rgba[0] = 4 * (v - vmin - 0.5 * dv) / dv;
rgba[1] = 1;
rgba[2] = 0;
} else {
rgba[0] = 1;
rgba[1] = 1;
rgba[2] = 4 * (v - vmin - 0.75 * dv) / dv;
}
break;
case 16:
if (v < (vmin + 0.5 * dv)) {
rgba[0] = 0.0;
rgba[1] = 2 * (v - vmin) / dv;
rgba[2] = 1 - 2 * (v - vmin) / dv;
} else {
rgba[0] = 2 * (v - vmin - 0.5 * dv) / dv;
rgba[1] = 1 - 2 * (v - vmin - 0.5 * dv) / dv;
rgba[2] = 0.0;
}
break;
case 17:
if (v < (vmin + 0.5 * dv)) {
rgba[0] = 1.0;
rgba[1] = 1 - 2 * (v - vmin) / dv;
rgba[2] = 2 * (v - vmin) / dv;
} else {
rgba[0] = 1 - 2 * (v - vmin - 0.5 * dv) / dv;
rgba[1] = 2 * (v - vmin - 0.5 * dv) / dv;
rgba[2] = 1.0;
}
break;
case 18:
rgba[0] = 0;
rgba[1] = (v - vmin) / (vmax - vmin);
rgba[2] = 1;
break;
case 19:
rgba[0] = (v - vmin) / (vmax - vmin);
rgba[1] = rgba[0];
rgba[2] = 1;
break;
case 20:
c1[0] = 0 / 255.0; c1[1] = 160 / 255.0; c1[2] = 0 / 255.0;
c2[0] = 180 / 255.0; c2[1] = 220 / 255.0; c2[2] = 0 / 255.0;
c3[0] = 250 / 255.0; c3[1] = 220 / 255.0; c3[2] = 170 / 255.0;
ratio = 0.3;
vmid = vmin + ratio * dv;
if (v < vmid) {
rgba[0] = (c2[0] - c1[0]) * (v - vmin) / (ratio*dv) + c1[0];
rgba[1] = (c2[1] - c1[1]) * (v - vmin) / (ratio*dv) + c1[1];
rgba[2] = (c2[2] - c1[2]) * (v - vmin) / (ratio*dv) + c1[2];
} else {
rgba[0] = (c3[0] - c2[0]) * (v - vmid) / ((1-ratio)*dv) + c2[0];
rgba[1] = (c3[1] - c2[1]) * (v - vmid) / ((1-ratio)*dv) + c2[1];
rgba[2] = (c3[2] - c2[2]) * (v - vmid) / ((1-ratio)*dv) + c2[2];
}
break;
}
}
}
TGLLevelPalette::TGLLevelPalette()
: fContours(0),
fPaletteSize(0),
fTexture(0),
fMaxPaletteSize(0)
{
}
Bool_t TGLLevelPalette::GeneratePalette(UInt_t paletteSize, const Rgl::Range_t &zRange, Bool_t check)
{
if (!fMaxPaletteSize && check)
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxPaletteSize);
if (!(zRange.second - zRange.first))
return kFALSE;
if (check && paletteSize > UInt_t(fMaxPaletteSize)) {
Error("TGLLevelPalette::GeneratePalette",
"Number of contours %d is too big for GL 1D texture, try to reduce it to %d",
paletteSize, fMaxPaletteSize);
return kFALSE;
}
UInt_t nearestPow2 = 2;
while (nearestPow2 < paletteSize)
nearestPow2 <<= 1;
fTexels.resize(4 * nearestPow2);
fPaletteSize = paletteSize;
const Int_t nColors = gStyle->GetNumberOfColors();
for (UInt_t i = 0; i < paletteSize; ++i) {
Int_t paletteInd = Int_t(nColors / Double_t(paletteSize) * i);
if (paletteInd > nColors - 1)
paletteInd = nColors - 1;
Int_t colorInd = gStyle->GetColorPalette(paletteInd);
if (const TColor *c = gROOT->GetColor(colorInd)) {
Float_t rgb[3] = {};
c->GetRGB(rgb[0], rgb[1], rgb[2]);
fTexels[i * 4] = UChar_t(rgb[0] * 255);
fTexels[i * 4 + 1] = UChar_t(rgb[1] * 255);
fTexels[i * 4 + 2] = UChar_t(rgb[2] * 255);
fTexels[i * 4 + 3] = 200;
}
}
fZRange = zRange;
return kTRUE;
}
void TGLLevelPalette::SetContours(const std::vector<Double_t> *cont)
{
fContours = cont;
}
void TGLLevelPalette::EnableTexture(Int_t mode)const
{
glEnable(GL_TEXTURE_1D);
glGenTextures(1, &fTexture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_1D, fTexture);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, fTexels.size() / 4, 0,
GL_RGBA, GL_UNSIGNED_BYTE, &fTexels[0]);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GLint(mode));
}
void TGLLevelPalette::DisableTexture()const
{
glDeleteTextures(1, &fTexture);
glDisable(GL_TEXTURE_1D);
}
Int_t TGLLevelPalette::GetPaletteSize()const
{
return Int_t(fPaletteSize);
}
Double_t TGLLevelPalette::GetTexCoord(Double_t z)const
{
if (!fContours)
return (z - fZRange.first) / (fZRange.second - fZRange.first) * fPaletteSize / (fTexels.size() / 4);
return 1.;
}
const UChar_t *TGLLevelPalette::GetColour(Double_t z)const
{
const Int_t ind = Int_t((z - fZRange.first) / (fZRange.second - fZRange.first) * fPaletteSize);
return &fTexels[ind * 4];
}
const UChar_t *TGLLevelPalette::GetColour(Int_t ind)const
{
return &fTexels[ind * 4];
}