#include "TGLClip.h"
#include "TGLIncludes.h"
#include "TGLRnrCtx.h"
#include "TGLManipSet.h"
#include "TGLFaceSet.h"
#include "TBuffer3D.h"
#include "TBuffer3DTypes.h"
namespace
{
class TGLClipPlaneLogical : public TGLLogicalShape
{
protected:
virtual void DirectDraw(TGLRnrCtx & rnrCtx) const
{
glBegin(rnrCtx.IsDrawPassFilled() ? GL_QUADS : GL_LINE_LOOP);
glNormal3d (0.0, 0.0, 1.0);
glVertex3dv(fBoundingBox[4].CArr());
glVertex3dv(fBoundingBox[7].CArr());
glVertex3dv(fBoundingBox[6].CArr());
glVertex3dv(fBoundingBox[5].CArr());
glEnd();
}
public:
TGLClipPlaneLogical() : TGLLogicalShape() { fDLCache = kFALSE; }
virtual ~TGLClipPlaneLogical() {}
void Resize(Double_t ext)
{
fBoundingBox.SetAligned(TGLVertex3(-ext, -ext, 0),
TGLVertex3( ext, ext, 0));
UpdateBoundingBoxesOfPhysicals();
}
};
class TGLClipBoxLogical : public TGLLogicalShape
{
protected:
virtual void DirectDraw(TGLRnrCtx & rnrCtx) const
{
glEnable(GL_NORMALIZE);
fBoundingBox.Draw(rnrCtx.IsDrawPassFilled());
glDisable(GL_NORMALIZE);
}
public:
TGLClipBoxLogical() : TGLLogicalShape() { fDLCache = kFALSE; }
virtual ~TGLClipBoxLogical() {}
void Resize(const TGLVertex3 & lowVertex, const TGLVertex3 & highVertex)
{
fBoundingBox.SetAligned(lowVertex, highVertex);
UpdateBoundingBoxesOfPhysicals();
}
};
}
ClassImp(TGLClip);
TGLClip::TGLClip(const TGLLogicalShape & logical, const TGLMatrix & transform, const float color[4]) :
TGLPhysicalShape(0, logical, transform, kTRUE, color),
fMode (kInside),
fTimeStamp (1),
fValid (kFALSE)
{
logical.StrongRef(kTRUE);
}
TGLClip::~TGLClip()
{
}
void TGLClip::Setup(const TGLVector3&, const TGLVector3&)
{
Warning("TGLClip::Setup", "Called on base-class -- should be re-implemented in derived class.");
}
void TGLClip::Draw(TGLRnrCtx & rnrCtx) const
{
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
TGLPhysicalShape::Draw(rnrCtx);
glPolygonMode(GL_FRONT, GL_FILL);
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
}
ClassImp(TGLClipPlane);
const float TGLClipPlane::fgColor[4] = { 1.0, 0.6, 0.2, 0.5 };
TGLClipPlane::TGLClipPlane() :
TGLClip(* new TGLClipPlaneLogical, TGLMatrix(), fgColor)
{
SetManip(EManip(kTranslateAll | kRotateX | kRotateY));
TGLPlane plane(0.0, -1.0, 0.0, 0.0);
Set(plane);
fValid = kFALSE;
}
TGLClipPlane::~TGLClipPlane()
{
}
void TGLClipPlane::Setup(const TGLBoundingBox & bbox)
{
Double_t extents = bbox.Extents().Mag();
TGLClipPlaneLogical* cpl = (TGLClipPlaneLogical*) GetLogical();
cpl->Resize(extents);
if (!fValid) {
SetTransform(TGLMatrix(bbox.Center(), BoundingBox().GetNearPlane().Norm()));
}
IncTimeStamp();
fValid = kTRUE;
}
void TGLClipPlane::Setup(const TGLVector3& point, const TGLVector3& normal)
{
TGLVector3 n(normal);
Double_t extents = n.Mag();
if (extents > 0)
{
n /= extents;
TGLClipPlaneLogical* cpl = (TGLClipPlaneLogical*) GetLogical();
cpl->Resize(extents);
SetTransform(TGLMatrix(point, n));
IncTimeStamp();
fValid = kTRUE;
}
else
{
Warning("TGLClipPlane::Setup", "Normal with zero length passed.");
}
}
void TGLClipPlane::Set(const TGLPlane& plane)
{
TGLVertex3 oldCenter = BoundingBox().Center();
TGLVertex3 newCenter = plane.NearestOn(oldCenter);
SetTransform(TGLMatrix(newCenter, plane.Norm()));
IncTimeStamp();
fValid = kTRUE;
}
void TGLClipPlane::PlaneSet(TGLPlaneSet_t& set) const
{
set.resize(1);
set[0] = BoundingBox().GetNearPlane();
set[0].Negate();
}
ClassImp(TGLClipBox);
const float TGLClipBox::fgColor[4] = { 1.0, 0.6, 0.2, 0.3 };
TGLClipBox::TGLClipBox() :
TGLClip(* new TGLClipBoxLogical, TGLMatrix(), fgColor)
{
}
TGLClipBox::~TGLClipBox()
{
}
void TGLClipBox::Setup(const TGLBoundingBox& bbox)
{
TGLVector3 halfLengths = bbox.Extents() * 0.2501;
TGLVertex3 center = bbox.Center() + halfLengths;
TGLClipBoxLogical* cbl = (TGLClipBoxLogical*) GetLogical();
cbl->Resize(center - halfLengths, center + halfLengths);
IncTimeStamp();
fValid = kTRUE;
}
void TGLClipBox::Setup(const TGLVector3& min_point, const TGLVector3& max_point)
{
TGLClipBoxLogical* cbl = (TGLClipBoxLogical*) GetLogical();
cbl->Resize(min_point, max_point);
IncTimeStamp();
fValid = kTRUE;
}
void TGLClipBox::PlaneSet(TGLPlaneSet_t& set) const
{
BoundingBox().PlaneSet(set);
TGLPlaneSet_i i = set.begin();
while (i != set.end()) {
i->Negate();
++i;
}
}
ClassImp(TGLClipSet);
TGLClipSet::TGLClipSet() :
fClipPlane (new TGLClipPlane),
fClipBox (new TGLClipBox),
fCurrentClip (0),
fShowClip (kFALSE),
fShowManip (kFALSE),
fManip (new TGLManipSet)
{
}
TGLClipSet::~TGLClipSet()
{
delete fClipPlane;
delete fClipBox;
delete fManip;
}
Bool_t TGLClipSet::MouseEnter(TGLOvlSelectRecord& selRec)
{
return fManip->MouseEnter(selRec);
}
Bool_t TGLClipSet::MouseStillInside(TGLOvlSelectRecord& selRec)
{
return fManip->MouseStillInside(selRec);
}
Bool_t TGLClipSet::Handle(TGLRnrCtx& rnrCtx, TGLOvlSelectRecord& selRec,
Event_t* event)
{
return fManip->Handle(rnrCtx, selRec, event);
}
void TGLClipSet::MouseLeave()
{
return fManip->MouseLeave();
}
void TGLClipSet::Render(TGLRnrCtx& rnrCtx)
{
if (!fCurrentClip) return;
rnrCtx.SetShapeLOD(TGLRnrCtx::kLODHigh);
rnrCtx.SetDrawPass(TGLRnrCtx::kPassFill);
if (fShowClip && ! rnrCtx.Selection())
{
fCurrentClip->Draw(rnrCtx);
}
if (fShowManip)
{
fManip->Render(rnrCtx);
}
}
void TGLClipSet::FillPlaneSet(TGLPlaneSet_t& set) const
{
if (fCurrentClip)
fCurrentClip->PlaneSet(set);
}
void TGLClipSet::SetupClips(const TGLBoundingBox& sceneBBox)
{
fLastBBox = sceneBBox;
fClipPlane->Setup(sceneBBox);
fClipBox ->Setup(sceneBBox);
}
void TGLClipSet::SetupCurrentClip(const TGLBoundingBox& sceneBBox)
{
fLastBBox = sceneBBox;
if (fCurrentClip)
fCurrentClip->Setup(sceneBBox);
}
void TGLClipSet::SetupCurrentClipIfInvalid(const TGLBoundingBox& sceneBBox)
{
fLastBBox = sceneBBox;
if (fCurrentClip && ! fCurrentClip->IsValid())
fCurrentClip->Setup(sceneBBox);
}
void TGLClipSet::InvalidateClips()
{
fClipPlane->Invalidate();
fClipBox ->Invalidate();
}
void TGLClipSet::InvalidateCurrentClip()
{
if (fCurrentClip)
fCurrentClip->Invalidate();
}
void TGLClipSet::GetClipState(EClipType type, Double_t data[6]) const
{
switch (type)
{
case kClipNone:
break;
case kClipPlane:
{
if (!fClipPlane->IsValid())
fClipPlane->Setup(fLastBBox);
TGLPlaneSet_t planes;
fClipPlane->PlaneSet(planes);
data[0] = planes[0].A();
data[1] = planes[0].B();
data[2] = planes[0].C();
data[3] = planes[0].D();
break;
}
case kClipBox:
{
if (!fClipBox->IsValid())
fClipBox->Setup(fLastBBox);
const TGLBoundingBox & box = fClipBox->BoundingBox();
TGLVector3 ext = box.Extents();
data[0] = box.Center().X();
data[1] = box.Center().Y();
data[2] = box.Center().Z();
data[3] = box.Extents().X();
data[4] = box.Extents().Y();
data[5] = box.Extents().Z();
break;
}
default:
Error("TGLClipSet::GetClipState", "invalid clip type '%d'.", type);
break;
}
}
void TGLClipSet::SetClipState(EClipType type, const Double_t data[6])
{
switch (type) {
case kClipNone: {
break;
}
case kClipPlane: {
TGLPlane newPlane(-data[0], -data[1], -data[2], -data[3]);
fClipPlane->Set(newPlane);
break;
}
case kClipBox: {
const TGLBoundingBox & currentBox = fClipBox->BoundingBox();
TGLVector3 shift(data[0] - currentBox.Center().X(),
data[1] - currentBox.Center().Y(),
data[2] - currentBox.Center().Z());
fClipBox->Translate(shift);
TGLVector3 currentScale = fClipBox->GetScale();
TGLVector3 newScale(data[3] / currentBox.Extents().X() * currentScale.X(),
data[4] / currentBox.Extents().Y() * currentScale.Y(),
data[5] / currentBox.Extents().Z() * currentScale.Z());
fClipBox->Scale(newScale);
break;
}
}
}
EClipType TGLClipSet::GetClipType() const
{
EClipType type;
if (fCurrentClip == 0) {
type = kClipNone;
} else if (fCurrentClip == fClipPlane) {
type = kClipPlane;
} else if (fCurrentClip == fClipBox) {
type = kClipBox;
} else {
Error("TGLClipSet::GetClipType" , "Unknown clip type");
type = kClipNone;
}
return type;
}
void TGLClipSet::SetClipType(EClipType type)
{
switch (type) {
case kClipNone: {
fCurrentClip = 0;
break;
}
case kClipPlane: {
fCurrentClip = fClipPlane;
break;
}
case kClipBox: {
fCurrentClip = fClipBox;
break;
}
default: {
Error("TGLClipSet::SetClipType" , "Unknown clip type");
break;
}
}
fManip->SetPShape(fCurrentClip);
}