47 ClassImp(TGLScenePad);
51 TGLScenePad::TGLScenePad(TVirtualPad* pad) :
56 fInternalPIDs (kFALSE),
59 fAcceptedPhysicals (0),
62 fSmartRefresh (kFALSE)
75 void TGLScenePad::AddHistoPhysical(TGLLogicalShape* log,
const Float_t *histoColor)
77 Double_t how = ((Double_t) gPad->GetWh()) / gPad->GetWw();
79 Double_t lw = gPad->GetAbsWNDC();
80 Double_t lh = gPad->GetAbsHNDC() * how;
81 Double_t lm = TMath::Min(lw, lh);
83 const TGLBoundingBox& bb = log->BoundingBox();
86 Double_t size = TMath::Sqrt(3) * (bb.XMax() - bb.XMin());
87 Double_t scale = lm / size;
88 TGLVector3 scaleVec(scale, scale, scale);
90 Double_t tx = gPad->GetAbsXlowNDC() + lw;
91 Double_t ty = gPad->GetAbsYlowNDC() * how + lh;
92 TGLVector3 transVec(0, ty, tx);
109 mat.Translate(transVec);
110 mat.RotateLF(3, 2, TMath::PiOver2());
111 mat.RotateLF(1, 3, TMath::DegToRad()*gPad->GetTheta());
112 mat.RotateLF(1, 2, TMath::DegToRad()*(gPad->GetPhi() - 90));
113 Float_t rgba[4] = {1.f, 1.f, 1.f, 1.f};
115 rgba[0] = histoColor[0];
116 rgba[1] = histoColor[1];
117 rgba[2] = histoColor[2];
118 rgba[3] = histoColor[3];
120 TGLPhysicalShape* phys =
new TGLPhysicalShape(fNextInternalPID++, *log, mat,
false, rgba);
121 AdoptPhysical(*phys);
137 Bool_t HasPolymarkerAndFrame(
const TList *lst)
139 Bool_t gotEmptyTH3 = kFALSE;
140 Bool_t gotMarker = kFALSE;
142 TObjOptLink *lnk = lst ? (TObjOptLink*)lst->FirstLink() : 0;
143 for (; lnk; lnk = (TObjOptLink*)lnk->Next()) {
144 const TObject *obj = lnk->GetObject();
145 if (
const TH3 *th3 = dynamic_cast<const TH3*>(obj)) {
146 if(!th3->GetEntries())
148 }
else if (dynamic_cast<const TPolyMarker3D *>(obj))
152 return gotMarker && gotEmptyTH3;
162 void TGLScenePad::SubPadPaint(TVirtualPad* pad)
164 TVirtualPad *padsav = gPad;
165 TVirtualViewer3D *vv3dsav = pad->GetViewer3D();
167 pad->SetViewer3D(
this);
169 TList *prims = pad->GetListOfPrimitives();
171 if (HasPolymarkerAndFrame(prims)) {
172 ComposePolymarker(prims);
174 TObjOptLink *lnk = (prims) ? (TObjOptLink*)prims->FirstLink() : 0;
175 for (; lnk; lnk = (TObjOptLink*)lnk->Next())
176 ObjectPaint(lnk->GetObject(), lnk->GetOption());
179 pad->SetViewer3D(vv3dsav);
189 void TGLScenePad::ObjectPaint(TObject* obj, Option_t* opt)
191 TGLPlot3D* log = TGLPlot3D::CreatePlot(obj, opt, gPad);
195 AddHistoPhysical(log);
197 else if (obj->InheritsFrom(TAtt3D::Class()))
202 else if (obj->InheritsFrom(TVirtualPad::Class()))
204 SubPadPaint(dynamic_cast<TVirtualPad*>(obj));
217 void TGLScenePad::PadPaintFromViewer(TGLViewer* viewer)
219 Bool_t sr = fSmartRefresh;
220 fSmartRefresh = viewer->GetSmartRefresh();
233 void TGLScenePad::PadPaint(TVirtualPad* pad)
237 Error(
"TGLScenePad::PadPaint",
"Mismatch between pad argument and data-member!");
259 void TGLScenePad::BeginScene()
262 Info(
"TGLScenePad::BeginScene",
"entering.");
265 if ( ! BeginUpdate()) {
266 Error(
"TGLScenePad::BeginScene",
"could not take scene lock.");
270 UInt_t destroyedLogicals = 0;
271 UInt_t destroyedPhysicals = 0;
273 TGLStopwatch stopwatch;
281 destroyedPhysicals = DestroyPhysicals();
283 destroyedLogicals = BeginSmartRefresh();
285 destroyedLogicals = DestroyLogicals();
289 fInternalPIDs = kFALSE;
292 fNextInternalPID = 1;
296 fAcceptedPhysicals = 0;
299 Info(
"TGLScenePad::BeginScene",
"destroyed %d physicals %d logicals in %f msec",
300 destroyedPhysicals, destroyedLogicals, stopwatch.End());
310 void TGLScenePad::EndScene()
319 Info(
"TGLScenePad::EndScene",
"Accepted %d physicals", fAcceptedPhysicals);
329 Int_t TGLScenePad::AddObject(
const TBuffer3D& buffer, Bool_t* addChildren)
332 fInternalPIDs = kTRUE;
333 Int_t sections = AddObject(fNextInternalPID, buffer, addChildren);
342 Int_t TGLScenePad::AddObject(UInt_t physicalID,
const TBuffer3D& buffer, Bool_t* addChildren)
357 if (physicalID == 0) {
358 Error(
"TGLScenePad::AddObject",
"0 physical ID reserved");
359 return TBuffer3D::kNone;
363 if (fInternalPIDs && physicalID != fNextInternalPID) {
364 Error(
"TGLScenePad::AddObject",
"invalid next physical ID - mix of internal + external IDs?");
365 return TBuffer3D::kNone;
370 *addChildren = kTRUE;
373 if (CurrentLock() != kModifyLock) {
374 Error(
"TGLScenePad::AddObject",
"expected scene to be modify-locked.");
375 return TBuffer3D::kNone;
383 RootCsg::TBaseMesh *newMesh = RootCsg::ConvertToMesh(buffer);
385 fCSTokens.push_back(std::make_pair(static_cast<UInt_t>(TBuffer3D::kCSNoOp), newMesh));
386 return TBuffer3D::kNone;
390 TGLPhysicalShape *physical = FindPhysical(physicalID);
391 TGLLogicalShape *logical = 0;
397 logical = FindLogical(buffer.fID);
399 logical = AttemptDirectRenderer(buffer.fID);
403 if (physicalID != fLastPID)
411 Error(
"TGLScenePad::AddObject",
"cached physical with no associated cached logical");
419 return TBuffer3D::kNone;
423 Bool_t includeRaw = (logical == 0);
424 Int_t extraSections = ValidateObjectBuffer(buffer, includeRaw);
425 if (extraSections != TBuffer3D::kNone)
426 return extraSections;
428 fLastPID = physicalID;
431 if (fLastPID != physicalID) {
432 Error(
"TGLScenePad::AddObject",
"internal physical ID tracking error?");
437 Error(
"TGLScenePad::AddObject",
"expecting to require physical");
438 return TBuffer3D::kNone;
444 logical = CreateNewLogical(buffer);
446 Error(
"TGLScenePad::AddObject",
"failed to create logical");
447 return TBuffer3D::kNone;
450 AdoptLogical(*logical);
454 physical = CreateNewPhysical(physicalID, buffer, *logical);
458 AdoptPhysical(*physical);
459 buffer.fPhysicalID = physicalID;
460 ++fAcceptedPhysicals;
461 if (gDebug>3 && fAcceptedPhysicals%1000 == 0) {
462 Info(
"TGLScenePad::AddObject",
"added %d physicals", fAcceptedPhysicals);
467 Error(
"TGLScenePad::AddObject",
"failed to create physical");
474 return TBuffer3D::kNone;
482 Bool_t TGLScenePad::OpenComposite(
const TBuffer3D& buffer, Bool_t* addChildren)
485 Error(
"TGLScenePad::OpenComposite",
"composite already open");
488 UInt_t extraSections = AddObject(buffer, addChildren);
489 if (extraSections != TBuffer3D::kNone) {
490 Error(
"TGLScenePad::OpenComposite",
"expected top level composite to not require extra buffer sections");
507 void TGLScenePad::CloseComposite()
514 RootCsg::TBaseMesh *resultMesh = BuildComposite();
515 fComposite->SetFromMesh(resultMesh);
517 for (UInt_t i = 0; i < fCSTokens.size(); ++i)
delete fCSTokens[i].second;
528 void TGLScenePad::AddCompositeOp(UInt_t operation)
530 fCSTokens.push_back(std::make_pair(operation, (RootCsg::TBaseMesh *)0));
543 Int_t TGLScenePad::ValidateObjectBuffer(
const TBuffer3D& buffer, Bool_t includeRaw)
const
546 if (!buffer.SectionsValid(TBuffer3D::kCore)) {
547 Error(
"TGLScenePad::ValidateObjectBuffer",
"kCore section of buffer should be filled always");
548 return TBuffer3D::kNone;
553 return TBuffer3D::kNone;
557 Bool_t needRaw = kFALSE;
562 if (buffer.Type() != TBuffer3DTypes::kSphere &&
563 buffer.Type() != TBuffer3DTypes::kTube &&
564 buffer.Type() != TBuffer3DTypes::kTubeSeg &&
565 buffer.Type() != TBuffer3DTypes::kCutTube &&
566 buffer.Type() != TBuffer3DTypes::kComposite)
572 else if (buffer.Type() == TBuffer3DTypes::kSphere)
574 const TBuffer3DSphere * sphereBuffer =
dynamic_cast<const TBuffer3DSphere *
>(&buffer);
576 if (!sphereBuffer->IsSolidUncut()) {
580 Error(
"TGLScenePad::ValidateObjectBuffer",
"failed to cast buffer of type 'kSphere' to TBuffer3DSphere");
581 return TBuffer3D::kNone;
585 else if (!buffer.SectionsValid(TBuffer3D::kBoundingBox))
590 else if (!buffer.SectionsValid(TBuffer3D::kShapeSpecific) &&
591 buffer.Type() != TBuffer3DTypes::kComposite)
601 if (needRaw && !buffer.SectionsValid(TBuffer3D::kRawSizes|TBuffer3D::kRaw)) {
602 return TBuffer3D::kRawSizes|TBuffer3D::kRaw;
604 return TBuffer3D::kNone;
611 TGLLogicalShape* TGLScenePad::CreateNewLogical(
const TBuffer3D& buffer)
const
613 TGLLogicalShape * newLogical = 0;
615 if (buffer.fColor == 1)
616 const_cast<TBuffer3D&
>(buffer).fColor = 42;
618 switch (buffer.Type())
620 case TBuffer3DTypes::kLine:
621 newLogical =
new TGLPolyLine(buffer);
623 case TBuffer3DTypes::kMarker:
624 newLogical =
new TGLPolyMarker(buffer);
626 case TBuffer3DTypes::kSphere:
628 const TBuffer3DSphere * sphereBuffer =
dynamic_cast<const TBuffer3DSphere *
>(&buffer);
633 if (sphereBuffer->IsSolidUncut() && !buffer.SectionsValid(TBuffer3D::kRawSizes|TBuffer3D::kRaw))
635 newLogical =
new TGLSphere(*sphereBuffer);
637 newLogical =
new TGLFaceSet(buffer);
640 Error(
"TGLScenePad::CreateNewLogical",
"failed to cast buffer of type 'kSphere' to TBuffer3DSphere");
644 case TBuffer3DTypes::kTube:
645 case TBuffer3DTypes::kTubeSeg:
646 case TBuffer3DTypes::kCutTube:
648 const TBuffer3DTube * tubeBuffer =
dynamic_cast<const TBuffer3DTube *
>(&buffer);
652 if (!buffer.SectionsValid(TBuffer3D::kRawSizes|TBuffer3D::kRaw)) {
653 newLogical =
new TGLCylinder(*tubeBuffer);
655 newLogical =
new TGLFaceSet(buffer);
658 Error(
"TGLScenePad::CreateNewLogical",
"failed to cast buffer of type 'kTube/kTubeSeg/kCutTube' to TBuffer3DTube");
662 case TBuffer3DTypes::kComposite:
668 Error(
"TGLScenePad::CreateNewLogical",
"composite already open");
670 fComposite =
new TGLFaceSet(buffer);
671 newLogical = fComposite;
675 newLogical =
new TGLFaceSet(buffer);
688 TGLScenePad::CreateNewPhysical(UInt_t ID,
const TBuffer3D& buffer,
689 const TGLLogicalShape& logical)
const
693 Int_t colorIndex = buffer.fColor;
694 if (colorIndex < 0) colorIndex = 42;
696 TGLScene::RGBAFromColorIdx(rgba, colorIndex, buffer.fTransparency);
697 return new TGLPhysicalShape(ID, logical, buffer.fLocalMaster,
698 buffer.fReflection, rgba);
704 void TGLScenePad::ComposePolymarker(
const TList *lst)
706 TPolyMarker3D *pm = 0;
708 TObjOptLink *lnk = (TObjOptLink*)lst->FirstLink();
709 for (; lnk; lnk = (TObjOptLink*)lnk->Next()) {
710 TObject *obj = lnk->GetObject();
711 if (TPolyMarker3D *dPm = dynamic_cast<TPolyMarker3D*>(obj)) {
714 }
else if (TH3 *dTH3 = dynamic_cast<TH3*>(obj)) {
715 if(!th3 && !dTH3->GetEntries())
718 ObjectPaint(obj, lnk->GetOption());
722 TGLPlot3D* log = TGLPlot3D::CreatePlot(th3, pm);
726 const Color_t cInd = pm->GetMarkerColor();
727 if (TColor *c = gROOT->GetColor(cInd)) {
728 Float_t rgba[4] = {0.f, 0.f, 0.f, 1.};
729 c->GetRGB(rgba[0], rgba[1], rgba[2]);
730 AddHistoPhysical(log, rgba);
732 AddHistoPhysical(log);
744 RootCsg::TBaseMesh* TGLScenePad::BuildComposite()
746 const CSPart_t &currToken = fCSTokens[fCSLevel];
747 UInt_t opCode = currToken.first;
749 if (opCode != TBuffer3D::kCSNoOp) {
751 RootCsg::TBaseMesh *left = BuildComposite();
752 RootCsg::TBaseMesh *right = BuildComposite();
755 case TBuffer3D::kCSUnion:
756 return RootCsg::BuildUnion(left, right);
757 case TBuffer3D::kCSIntersection:
758 return RootCsg::BuildIntersection(left, right);
759 case TBuffer3D::kCSDifference:
760 return RootCsg::BuildDifference(left, right);
762 Error(
"BuildComposite",
"Wrong operation code %d\n", opCode);
765 }
else return fCSTokens[fCSLevel++].second;
773 TGLLogicalShape* TGLScenePad::AttemptDirectRenderer(TObject*
id)
775 TClass* cls = TGLObject::GetGLRenderer(id->IsA());
779 TGLObject* rnr =
reinterpret_cast<TGLObject*
>(cls->New());
784 status = rnr->SetModel(
id);
786 catch (std::exception&)
792 Warning(
"TGLScenePad::AttemptDirectRenderer",
"failed initializing direct rendering.");