#include "TGLPhysicalShape.h"
#include "TGLLogicalShape.h"
#include "TGLPShapeRef.h"
#include "TGLCamera.h"
#include "TGLRnrCtx.h"
#include "TGLIncludes.h"
#include "TGLScene.h"
#include "TColor.h"
#include "TROOT.h"
#include <cmath>
#include "TClass.h"
#include "TError.h"
ClassImp(TGLPhysicalShape)
TGLPhysicalShape::TGLPhysicalShape(UInt_t id, const TGLLogicalShape & logicalShape,
const TGLMatrix & transform, Bool_t invertedWind,
const Float_t rgba[4]) :
fLogicalShape (&logicalShape),
fNextPhysical (0),
fFirstPSRef (0),
fID (id),
fTransform (transform),
fSelected (0),
fInvertedWind (invertedWind),
fModified (kFALSE),
fManip (kManipAll)
{
fLogicalShape->AddRef(this);
UpdateBoundingBox();
InitColor(rgba);
}
TGLPhysicalShape::TGLPhysicalShape(UInt_t id, const TGLLogicalShape & logicalShape,
const Double_t * transform, Bool_t invertedWind,
const Float_t rgba[4]) :
fLogicalShape (&logicalShape),
fNextPhysical (0),
fFirstPSRef (0),
fID (id),
fTransform (transform),
fSelected (0),
fInvertedWind (invertedWind),
fModified (kFALSE),
fManip (kManipAll)
{
fLogicalShape->AddRef(this);
fTransform.Transpose3x3();
UpdateBoundingBox();
InitColor(rgba);
}
TGLPhysicalShape::~TGLPhysicalShape()
{
if (fLogicalShape) fLogicalShape->SubRef(this);
while (fFirstPSRef) {
fFirstPSRef->SetPShape(0);
}
}
void TGLPhysicalShape::AddReference(TGLPShapeRef* ref)
{
assert(ref != 0);
ref->fNextPSRef = fFirstPSRef;
fFirstPSRef = ref;
}
void TGLPhysicalShape::RemoveReference(TGLPShapeRef* ref)
{
assert(ref != 0);
Bool_t found = kFALSE;
if (fFirstPSRef == ref) {
fFirstPSRef = ref->fNextPSRef;
found = kTRUE;
} else {
TGLPShapeRef *shp1 = fFirstPSRef, *shp2;
while ((shp2 = shp1->fNextPSRef) != 0) {
if (shp2 == ref) {
shp1->fNextPSRef = shp2->fNextPSRef;
found = kTRUE;
break;
}
shp1 = shp2;
}
}
if (found) {
ref->fNextPSRef = 0;
} else {
Error("TGLPhysicalShape::RemoveReference", "Attempt to un-ref an unregistered shape-ref.");
}
}
void TGLPhysicalShape::Modified()
{
fModified = kTRUE;
TGLPShapeRef * ref = fFirstPSRef;
while (ref) {
ref->PShapeModified();
ref = ref->fNextPSRef;
}
}
void TGLPhysicalShape::UpdateBoundingBox()
{
fBoundingBox.Set(fLogicalShape->BoundingBox());
fBoundingBox.Transform(fTransform);
if (fLogicalShape->GetScene())
fLogicalShape->GetScene()->InvalidateBoundingBox();
}
void TGLPhysicalShape::InitColor(const Float_t rgba[4])
{
fColor[0] = rgba[0];
fColor[1] = rgba[1];
fColor[2] = rgba[2];
fColor[3] = rgba[3];
fColor[4] = fColor[5] = fColor[6] = 0.0f;
fColor[8] = fColor[9] = fColor[10] = 0.7f;
fColor[12] = fColor[13] = fColor[14] = 0.0f;
fColor[7] = fColor[11] = fColor[15] = 1.0f;
fColor[16] = 60.0f;
}
void TGLPhysicalShape::SetColor(const Float_t color[17])
{
for (UInt_t i = 0; i < 17; i++) {
fColor[i] = color[i];
}
Modified();
}
void TGLPhysicalShape::SetColorOnFamily(const Float_t color[17])
{
TGLPhysicalShape* pshp = const_cast<TGLPhysicalShape*>(fLogicalShape->GetFirstPhysical());
while (pshp)
{
pshp->SetColor(color);
pshp = pshp->fNextPhysical;
}
}
void TGLPhysicalShape::SetDiffuseColor(const Float_t rgba[4])
{
for (Int_t i=0; i<4; ++i)
fColor[i] = rgba[i];
Modified();
}
void TGLPhysicalShape::SetDiffuseColor(const UChar_t rgba[4])
{
for (Int_t i=0; i<4; ++i)
fColor[i] = rgba[i]/255.0f;
Modified();
}
void TGLPhysicalShape::SetDiffuseColor(Color_t ci, UChar_t transparency)
{
if (ci < 0) ci = 1;
TColor* c = gROOT->GetColor(ci);
if (c) {
fColor[0] = c->GetRed();
fColor[1] = c->GetGreen();
fColor[2] = c->GetBlue();
fColor[3] = 1.0f - 0.01*transparency;
}
Modified();
}
void TGLPhysicalShape::SetupGLColors(TGLRnrCtx & rnrCtx, const Float_t* color) const
{
if (color == 0) color = fColor;
switch (rnrCtx.DrawPass()) {
case TGLRnrCtx::kPassWireFrame:
{
glColor4fv(color);
break;
}
case TGLRnrCtx::kPassFill:
case TGLRnrCtx::kPassOutlineFill:
{
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
glMaterialfv(GL_FRONT, GL_AMBIENT, color + 4);
glMaterialfv(GL_FRONT, GL_SPECULAR, color + 8);
glMaterialfv(GL_FRONT, GL_EMISSION, color + 12);
glMaterialf(GL_FRONT, GL_SHININESS, color[16]);
glColor4fv(color);
break;
}
case TGLRnrCtx::kPassOutlineLine:
{
TGLUtil::Color(rnrCtx.ColorSet().Outline(), 0.5f*color[3]);
break;
}
default:
{
assert(kFALSE);
}
}
}
static const Float_t selColor[] =
{
1, 1, 1, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0.5, 0, 0, 1,
0
};
void TGLPhysicalShape::Draw(TGLRnrCtx & rnrCtx) const
{
if (gDebug > 4) {
Info("TGLPhysicalShape::Draw", "this %d (class %s) LOD %d",
this, IsA()->GetName(), rnrCtx.ShapeLOD());
}
if (rnrCtx.ShapeLOD() == TGLRnrCtx::kLODPixel)
{
if (!rnrCtx.IsDrawPassOutlineLine())
{
glColor4fv(fColor);
glBegin(GL_POINTS);
glVertex3dv(&fTransform.CArr()[12]);
glEnd();
}
return;
}
if (gDebug > 4) {
Info("TGLPhysicalShape::Draw", "this %d (class %s) LOD %d",
this, IsA()->GetName(), rnrCtx.ShapeLOD());
}
glPushMatrix();
glMultMatrixd(fTransform.CArr());
if (fInvertedWind) glFrontFace(GL_CW);
if (fSelected && !rnrCtx.Selection() && !rnrCtx.IsDrawPassOutlineLine())
{
const TGLRect& vp = rnrCtx.RefCamera().RefViewport();
Int_t inner[4][2] = { { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0} };
Int_t outer[8][2] = { {-1,-1}, { 1,-1}, { 1, 1}, {-1, 1},
{ 0,-2}, { 2, 0}, { 0, 2}, {-2, 0} };
rnrCtx.SetHighlight(kTRUE);
rnrCtx.SetHighlightOutline(kTRUE);
TGLUtil::LockColor();
Int_t first_outer = (rnrCtx.CombiLOD() == TGLRnrCtx::kLODHigh) ? 0 : 4;
for (int i = first_outer; i < 8; ++i)
{
glViewport(vp.X() + outer[i][0], vp.Y() + outer[i][1], vp.Width(), vp.Height());
glColor4ubv(rnrCtx.ColorSet().Selection(fSelected).CArr());
fLogicalShape->Draw(rnrCtx);
}
TGLUtil::UnlockColor();
rnrCtx.SetHighlightOutline(kFALSE);
SetupGLColors(rnrCtx);
for (int i = 0; i < 4; ++i)
{
glViewport(vp.X() + inner[i][0], vp.Y() + inner[i][1], vp.Width(), vp.Height());
glColor4fv(fColor);
fLogicalShape->Draw(rnrCtx);
}
glViewport(vp.X(), vp.Y(), vp.Width(), vp.Height());
rnrCtx.SetHighlight(kFALSE);
SetupGLColors(rnrCtx);
Float_t dr[2];
glGetFloatv(GL_DEPTH_RANGE,dr);
glDepthRange(dr[0], 0.5*dr[1]);
fLogicalShape->Draw(rnrCtx);
glDepthRange(dr[0], dr[1]);
}
else
{
SetupGLColors(rnrCtx);
if (rnrCtx.IsDrawPassOutlineLine())
TGLUtil::LockColor();
fLogicalShape->Draw(rnrCtx);
if (rnrCtx.IsDrawPassOutlineLine())
TGLUtil::UnlockColor();
}
if (fInvertedWind) glFrontFace(GL_CCW);
glPopMatrix();
}
void TGLPhysicalShape::CalculateShapeLOD(TGLRnrCtx& rnrCtx, Float_t& pixSize, Short_t& shapeLOD) const
{
TGLLogicalShape::ELODAxes lodAxes = fLogicalShape->SupportedLODAxes();
if (lodAxes == TGLLogicalShape::kLODAxesNone)
{
pixSize = 100;
shapeLOD = TGLRnrCtx::kLODHigh;
return;
}
std::vector <Double_t> boxViewportDiags;
const TGLBoundingBox & box = BoundingBox();
const TGLCamera & camera = rnrCtx.RefCamera();
if (lodAxes == TGLLogicalShape::kLODAxesAll) {
boxViewportDiags.push_back(camera.ViewportRect(box).Diagonal());
} else if (lodAxes == (TGLLogicalShape::kLODAxesY | TGLLogicalShape::kLODAxesZ)) {
boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceLowX).Diagonal());
boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceHighX).Diagonal());
} else if (lodAxes == (TGLLogicalShape::kLODAxesX | TGLLogicalShape::kLODAxesZ)) {
boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceLowY).Diagonal());
boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceHighY).Diagonal());
} else if (lodAxes == (TGLLogicalShape::kLODAxesX | TGLLogicalShape::kLODAxesY)) {
boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceLowZ).Diagonal());
boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceHighZ).Diagonal());
} else {
Error("TGLPhysicalShape::CalcPhysicalLOD", "LOD calculation for single axis not implemented presently");
shapeLOD = TGLRnrCtx::kLODMed;
return;
}
Double_t largestDiagonal = 0.0;
for (UInt_t i = 0; i < boxViewportDiags.size(); i++) {
if (boxViewportDiags[i] > largestDiagonal) {
largestDiagonal = boxViewportDiags[i];
}
}
pixSize = largestDiagonal;
if (largestDiagonal <= 1.0) {
shapeLOD = TGLRnrCtx::kLODPixel;
} else {
UInt_t lodApp = static_cast<UInt_t>(std::pow(largestDiagonal,0.4) * 100.0 / std::pow(2000.0,0.4));
if (lodApp > 1000) lodApp = 1000;
shapeLOD = (Short_t) lodApp;
}
}
void TGLPhysicalShape::QuantizeShapeLOD(Short_t shapeLOD, Short_t combiLOD, Short_t& quantLOD) const
{
quantLOD = fLogicalShape->QuantizeShapeLOD(shapeLOD, combiLOD);
}
void TGLPhysicalShape::InvokeContextMenu(TContextMenu & menu, UInt_t x, UInt_t y) const
{
fLogicalShape->InvokeContextMenu(menu, x, y);
}