00001 // @(#)root/base:$Id: TBuffer3D.cxx,v 1.00 00002 // Author: Olivier Couet 05/05/04 00003 00004 /************************************************************************* 00005 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. * 00006 * All rights reserved. * 00007 * * 00008 * For the licensing terms see $ROOTSYS/LICENSE. * 00009 * For the list of contributors see $ROOTSYS/README/CREDITS. * 00010 *************************************************************************/ 00011 00012 #include "TBuffer3D.h" 00013 #include "TBuffer3DTypes.h" 00014 00015 ////////////////////////////////////////////////////////////////////////// 00016 // // 00017 // TBuffer3D // 00018 // // 00019 // Generic 3D primitive description class - see TBuffer3DTypes for // 00020 // producer classes // 00021 ////////////////////////////////////////////////////////////////////////// 00022 //BEGIN_HTML <!-- 00023 /* --> 00024 <h4>Filling TBuffer3D and Adding to Viewer</h4> 00025 <p>The viewers behind the TVirtualViewer3D interface differ greatly in their 00026 capabilities e.g.</p> 00027 <ul> 00028 <li> Some know how to draw certain shapes natively (e.g. spheres/tubes in 00029 OpenGL) - others always require a raw tessellation description of points/lines/segments.</li> 00030 <li>Some 00031 need the 3D object positions in the global frame, others can cope with 00032 local frames + a translation matrix - which can give considerable performance 00033 benefits.</li> 00034 </ul> 00035 <p>To cope with these situations the object buffer is filled out in negotiation 00036 with the viewer. TBuffer3D classes are conceptually divided into enumerated 00037 sections Core, BoundingBox, Raw etc (see TBuffer3D.h for more details). </p> 00038 <p align="center"><img src="gif/TBuffer3D.gif" width="501" height="501"></p> 00039 <p>The<em> SectionsValid() / SetSectionsValid / ClearSectionsValid() </em>methods of TBuffer3D 00040 are used to test/set/clear these section valid flags.</p> 00041 <p>The sections found in TBuffer3D (<em>Core/BoundingBox/Raw Sizes/Raw</em>) 00042 are sufficient to describe any tessellated shape in a generic fashion. An additional <em>ShapeSpecific</em> section 00043 in derived shape specific classes allows a more abstract shape description 00044 ("a sphere of inner radius x, outer radius y"). This enables a viewer 00045 which knows how to draw (tessellate) the shape itself to do so, which can bring 00046 considerable performance and quality benefits, while providing a generic fallback 00047 suitable for all viewers.</p> 00048 <p>The rules for client negotiation with the viewer are:</p> 00049 <ul> 00050 <li> If suitable specialized TBuffer3D class exists, use it, otherwise use 00051 TBuffer3D.</li> 00052 <li>Complete the mandatory Core section.</li> 00053 <li>Complete the ShapeSpecific section 00054 if applicable.</li> 00055 <li>Complete the BoundingBox if you can.</li> 00056 <li>Pass this buffer to the viewer using 00057 one of the AddObject() methods - see below.</li> 00058 </ul> 00059 <p>If the viewer requires more sections to be completed (Raw/RawSizes) AddObject() 00060 will return flags indicating which ones, otherwise it returns kNone. You must 00061 fill the buffer and mark these sections valid, and pass the buffer again. A 00062 typical code snippet would be:</p> 00063 <pre>TBuffer3DSphere sphereBuffer; 00064 // Fill out kCore... 00065 // Fill out kBoundingBox... 00066 // Fill out kShapeSpecific for TBuffer3DSphere 00067 // Try first add to viewer 00068 Int_t reqSections = viewer->AddObject(buffer); 00069 if (reqSections != TBuffer3D::kNone) { 00070 if (reqSections & TBuffer3D::kRawSizes) { 00071 // Fill out kRawSizes... 00072 } 00073 if (reqSections & TBuffer3D::kRaw) { 00074 // Fill out kRaw... 00075 } 00076 // Add second time to viewer - ignore return cannot do more 00077 viewer->AddObject(buffer); 00078 } 00079 }</pre> 00080 <p><em>ShapeSpecific</em>: If the viewer can directly display the buffer without 00081 filling of the kRaw/kRawSizes section it will not need to request client side 00082 tessellation. 00083 Currently we provide the following various shape specific classes, which the 00084 OpenGL viewer can take advantage of (see TBuffer3D.h and TBuffer3DTypes.h)</p> 00085 <ul> 00086 <li>TBuffer3DSphere - solid, hollow and cut spheres*</li> 00087 <li>TBuffer3DTubeSeg - angle tube segment</li> 00088 <li>TBuffer3DCutTube - angle tube segment with plane cut ends.</li> 00089 </ul> 00090 <p>*OpenGL only supports solid spheres at present - cut/hollow ones will be 00091 requested tessellated.</p> 00092 <p>Anyone is free to add new TBuffer3D classes, but it should be clear that the 00093 viewers require updating to be able to take advantage of them. The number of 00094 native shapes in OpenGL will be expanded over time.</p> 00095 <p><em>BoundingBox: </em>You are not obliged to complete this, as any viewer 00096 requiring one internally (OpenGL) will build one for you if you do not provide. 00097 However 00098 to do this the viewer will force you to provide the raw tessellation, and the 00099 resulting box will be axis aligned with the overall scene, which is non-ideal 00100 for rotated shapes.</p> 00101 <p>As we need to support orientated (rotated) bounding boxes, TBuffer3D requires 00102 the 6 vertices of the box. We also provide a convenience function, SetAABoundingBox(), 00103 for simpler case of setting an axis aligned bounding box.</p> 00104 <h4> 00105 Master/Local Reference Frames</h4> 00106 The <em>Core</em> section of TBuffer3D contains two members relating to reference 00107 frames: 00108 <em>fLocalFrame</em> & <em>fLocalMaster</em>. <em>fLocalFrame</em> indicates 00109 if any positions in the buffer (bounding box and tessellation vertexes) are 00110 in local or master (world 00111 frame). <em>fLocalMaster</em> is a standard 4x4 translation matrix (OpenGL 00112 colum major ordering) for placing the object into the 3D master frame. 00113 <p>If <em>fLocalFrame</em> is kFALSE, <em>fLocalMaster</em> should contain an 00114 identity matrix. This is set by default, and can be reset using <em>SetLocalMasterIdentity()</em> function.<br> 00115 Logical & Physical Objects</p> 00116 <p>There are two cases of object addition:</p> 00117 <ul> 00118 <li> Add this object as a single independent entity in the world reference 00119 frame.</li> 00120 <li>Add 00121 a physical placement (copy) of this logical object (described in local 00122 reference frame).</li> 00123 </ul> 00124 <p>The second case is very typical in geometry packages, GEANT4, where we have 00125 very large number repeated placements of relatively few logical (unique) shapes. 00126 Some viewers (OpenGL only at present) are able to take advantage of this by 00127 identifying unique logical shapes from the <em>fID</em> logical ID member of 00128 TBuffer3D. If repeated addition of the same <em>fID</em> is found, the shape 00129 is cached already - and the costly tessellation does not need to be sent again. 00130 The viewer can 00131 also perform internal GL specific caching with considerable performance gains 00132 in these cases.</p> 00133 <p>For this to work correctly the logical object in must be described in TBuffer3D 00134 in the local reference frame, complete with the local/master translation. The 00135 viewer indicates this through the interface method</p> 00136 <pre>PreferLocalFrame()</pre> 00137 <p>If this returns kTRUE you can make repeated calls to AddObject(), with TBuffer3D 00138 containing the same fID, and different <em>fLocalMaster</em> placements.</p> 00139 <p>For viewers supporting logical/physical objects, the TBuffer3D content refers 00140 to the properties of logical object, with the <em>fLocalMaster</em> transform and the 00141 <em>fColor</em> and <em>fTransparency</em> attributes, which can be varied for each physical 00142 object.</p> 00143 <p>As a minimum requirement all clients must be capable of filling the raw tessellation 00144 of the object buffer, in the master reference frame. Conversely viewers must 00145 always be capable of displaying the object described by this buffer.</p> 00146 <h4> 00147 Scene Rebuilds</h4> 00148 <p>It should be understood that AddObject is not an explicit command to the viewer 00149 - it may for various reasons decide to ignore it:</p> 00150 <ul> 00151 <li> It already has the object internally cached .</li> 00152 <li>The object falls outside 00153 some 'interest' limits of the viewer camera.</li> 00154 <li>The object is too small to 00155 be worth drawing.</li> 00156 </ul> 00157 <p>In all these cases AddObject() returns kNone, as it does for successful addition, 00158 simply indicating it does not require you to provide further information about 00159 this object. You should 00160 not try to make any assumptions about what the viewer did with it.</p> 00161 <p>This enables the viewer to be connected to a client which sends potentially 00162 millions of objects, and only accept those that are of interest at a certain 00163 time, caching the relatively small number of CPU/memory costly logical shapes, 00164 and retaining/discarding the physical placements as required. The viewer may 00165 decide to force the client to rebuild (republish) the scene (via 00166 a TPad 00167 repaint 00168 at 00169 present), 00170 and 00171 thus 00172 collect 00173 these 00174 objects if 00175 the 00176 internal viewer state changes. It does this presently by forcing a repaint 00177 on the attached TPad object - hence the reason for putting all publishing to 00178 the viewer in the attached pad objects Paint() method. We will likely remove 00179 this requirement in the future, indicating the rebuild request via a normal 00180 ROOT signal, which the client can detect.</p> 00181 <h4> 00182 Physical IDs</h4> 00183 TVirtualViewer3D provides for two methods of object addition:virtual Int_t AddObject(const 00184 TBuffer3D & buffer, Bool_t * addChildren = 0)<br> 00185 <pre>virtual Int_t AddObject(UInt_t physicalID, const TBuffer3D & buffer, Bool_t * addChildren = 0)</pre> 00186 <p>If you use the first (simple) case a viewer using logical/physical pairs 00187 00188 SetSectionsValid(TBuffer3D::kBoundingBox); 00189 will generate IDs for each physical object internally. In the second you 00190 can specify 00191 a unique identifier from the client, which allows the viewer to be more 00192 efficient. It can now cache both logical and physical objects, and only discard 00193 physical 00194 objects no longer of interest as part of scene rebuilds.</p> 00195 <h4> 00196 Child Objects</h4> 00197 <p>In many geometries there is a rigid containment hierarchy, and so if the viewer 00198 is not interested in a certain object due to limits/size then it will also 00199 not be interest in any of the contained branch of descendents. Both AddObject() 00200 methods have an addChildren parameter. The viewer will complete this (if passed) 00201 indicating if children (contained within the one just sent) are worth adding.</p> 00202 <h4> 00203 Recyling TBuffer3D </h4> 00204 <p>Once add AddObject() has been called, the contents are copied to the viewer 00205 internally. You are free to destroy this object, or recycle it for the next 00206 object if suitable.</p> 00207 <!--*/ 00208 // -->END_HTML 00209 00210 ClassImp(TBuffer3D) 00211 00212 //______________________________________________________________________________ 00213 TBuffer3D::TBuffer3D(Int_t type, 00214 UInt_t reqPnts, UInt_t reqPntsCapacity, 00215 UInt_t reqSegs, UInt_t reqSegsCapacity, 00216 UInt_t reqPols, UInt_t reqPolsCapacity) : 00217 fType(type) 00218 { 00219 // Destructor 00220 // Construct from supplied shape type and raw sizes 00221 Init(); 00222 SetRawSizes(reqPnts, reqPntsCapacity, reqSegs, reqSegsCapacity, reqPols, reqPolsCapacity); 00223 } 00224 00225 00226 //______________________________________________________________________________ 00227 TBuffer3D::~TBuffer3D() 00228 { 00229 // Destructor 00230 if (fPnts) delete [] fPnts; 00231 if (fSegs) delete [] fSegs; 00232 if (fPols) delete [] fPols; 00233 //______________________________________________________________________________ 00234 } 00235 00236 //______________________________________________________________________________ 00237 void TBuffer3D::Init() 00238 { 00239 // Initialise buffer 00240 fID = 0; 00241 fColor = 0; 00242 // Set fLocalMaster in section kCore to identity 00243 fTransparency = 0; 00244 fLocalFrame = kFALSE; 00245 fReflection = kFALSE; 00246 SetLocalMasterIdentity(); 00247 00248 // Reset bounding box 00249 for (UInt_t v=0; v<8; v++) { 00250 for (UInt_t i=0; i<3; i++) { 00251 fBBVertex[v][i] = 0.0; 00252 } 00253 } 00254 // Set fLocalMaster in section kCore to identity 00255 00256 // Set kRaw tesselation section of buffer with supplied sizes 00257 fPnts = 0; 00258 fSegs = 0; 00259 fPols = 0; 00260 00261 fNbPnts = 0; 00262 fNbSegs = 0; 00263 fNbPols = 0; 00264 fPntsCapacity = 0; 00265 fSegsCapacity = 0; 00266 fPolsCapacity = 0; 00267 // Set fLocalMaster in section kCore to identity 00268 00269 // Wipe output section. 00270 fPhysicalID = 0; 00271 00272 // Set kRaw tesselation section of buffer with supplied sizes 00273 ClearSectionsValid(); 00274 } 00275 00276 //______________________________________________________________________________ 00277 void TBuffer3D::ClearSectionsValid() 00278 { 00279 // Clear any sections marked valid 00280 fSections = 0U; 00281 SetRawSizes(0, 0, 0, 0, 0, 0); 00282 } 00283 00284 //______________________________________________________________________________ 00285 void TBuffer3D::SetLocalMasterIdentity() 00286 { 00287 // Set kRaw tesselation section of buffer with supplied sizes 00288 // Set fLocalMaster in section kCore to identity 00289 for (UInt_t i=0; i<16; i++) { 00290 if (i%5) { 00291 fLocalMaster[i] = 0.0; 00292 } 00293 else { 00294 fLocalMaster[i] = 1.0; 00295 } 00296 } 00297 } 00298 00299 //______________________________________________________________________________ 00300 void TBuffer3D::SetAABoundingBox(const Double_t origin[3], const Double_t halfLengths[3]) 00301 { 00302 // Set fBBVertex in kBoundingBox section to a axis aligned (local) BB 00303 // using supplied origin and box half lengths 00304 // 00305 // 7-------6 00306 // /| /| 00307 // 3-------2 | 00308 // | 4-----|-5 00309 // |/ |/ 00310 // 0-------1 00311 // 00312 00313 // Vertex 0 00314 fBBVertex[0][0] = origin[0] - halfLengths[0]; // x 00315 fBBVertex[0][1] = origin[1] - halfLengths[1]; // y 00316 fBBVertex[0][2] = origin[2] - halfLengths[2]; // z 00317 // Vertex 1 00318 fBBVertex[1][0] = origin[0] + halfLengths[0]; // x 00319 fBBVertex[1][1] = origin[1] - halfLengths[1]; // y 00320 fBBVertex[1][2] = origin[2] - halfLengths[2]; // z 00321 // Vertex 2 00322 fBBVertex[2][0] = origin[0] + halfLengths[0]; // x 00323 fBBVertex[2][1] = origin[1] + halfLengths[1]; // y 00324 fBBVertex[2][2] = origin[2] - halfLengths[2]; // z 00325 // Vertex 3 00326 fBBVertex[3][0] = origin[0] - halfLengths[0]; // x 00327 fBBVertex[3][1] = origin[1] + halfLengths[1]; // y 00328 fBBVertex[3][2] = origin[2] - halfLengths[2]; // z 00329 // Vertex 4 00330 fBBVertex[4][0] = origin[0] - halfLengths[0]; // x 00331 fBBVertex[4][1] = origin[1] - halfLengths[1]; // y 00332 fBBVertex[4][2] = origin[2] + halfLengths[2]; // z 00333 // Vertex 5 00334 fBBVertex[5][0] = origin[0] + halfLengths[0]; // x 00335 fBBVertex[5][1] = origin[1] - halfLengths[1]; // y 00336 fBBVertex[5][2] = origin[2] + halfLengths[2]; // z 00337 // Vertex 6 00338 fBBVertex[6][0] = origin[0] + halfLengths[0]; // x 00339 fBBVertex[6][1] = origin[1] + halfLengths[1]; // y 00340 fBBVertex[6][2] = origin[2] + halfLengths[2]; // z 00341 // Vertex 7 00342 fBBVertex[7][0] = origin[0] - halfLengths[0]; // x 00343 fBBVertex[7][1] = origin[1] + halfLengths[1]; // y 00344 fBBVertex[7][2] = origin[2] + halfLengths[2]; // z 00345 } 00346 00347 //______________________________________________________________________________ 00348 Bool_t TBuffer3D::SetRawSizes(UInt_t reqPnts, UInt_t reqPntsCapacity, 00349 UInt_t reqSegs, UInt_t reqSegsCapacity, 00350 UInt_t reqPols, UInt_t reqPolsCapacity) 00351 { 00352 // Set kRaw tesselation section of buffer with supplied sizes 00353 Bool_t allocateOK = kTRUE; 00354 00355 fNbPnts = reqPnts; 00356 fNbSegs = reqSegs; 00357 fNbPols = reqPols; 00358 00359 if (reqPntsCapacity > fPntsCapacity) { 00360 delete [] fPnts; 00361 fPnts = new Double_t[reqPntsCapacity]; 00362 if (fPnts) { 00363 fPntsCapacity = reqPntsCapacity; 00364 } else { 00365 fPntsCapacity = fNbPnts = 0; 00366 allocateOK = kFALSE; 00367 } 00368 } 00369 if (reqSegsCapacity > fSegsCapacity) { 00370 delete [] fSegs; 00371 fSegs = new Int_t[reqSegsCapacity]; 00372 if (fSegs) { 00373 fSegsCapacity = reqSegsCapacity; 00374 } else { 00375 fSegsCapacity = fNbSegs = 0; 00376 allocateOK = kFALSE; 00377 } 00378 } 00379 if (reqPolsCapacity > fPolsCapacity) { 00380 delete [] fPols; 00381 fPols = new Int_t[reqPolsCapacity]; 00382 if (fPols) { 00383 fPolsCapacity = reqPolsCapacity; 00384 } else { 00385 fPolsCapacity = fNbPols = 0; 00386 allocateOK = kFALSE; 00387 } 00388 } 00389 00390 return allocateOK; 00391 } 00392 00393 //______________________________________________________________________________ 00394 TBuffer3DSphere::TBuffer3DSphere(UInt_t reqPnts, UInt_t reqPntsCapacity, 00395 UInt_t reqSegs, UInt_t reqSegsCapacity, 00396 UInt_t reqPols, UInt_t reqPolsCapacity) : 00397 TBuffer3D(TBuffer3DTypes::kSphere, reqPnts, reqPntsCapacity, reqSegs, reqSegsCapacity, reqPols, reqPolsCapacity), 00398 fRadiusInner(0.0), fRadiusOuter(0.0), 00399 fThetaMin(0.0), fThetaMax(180.0), 00400 fPhiMin(0.0), fPhiMax(360.0) 00401 //constructor 00402 { 00403 } 00404 00405 //______________________________________________________________________________ 00406 Bool_t TBuffer3DSphere::IsSolidUncut() const 00407 { 00408 // Test if buffer represents a solid uncut sphere 00409 if (fRadiusInner != 0.0 || 00410 fThetaMin != 0.0 || 00411 fThetaMax != 180.0 || 00412 fPhiMin != 0.0 || 00413 fPhiMax != 360.0 ) { 00414 return kFALSE; 00415 } else { 00416 return kTRUE; 00417 } 00418 } 00419 00420 //______________________________________________________________________________ 00421 TBuffer3DTube::TBuffer3DTube(UInt_t reqPnts, UInt_t reqPntsCapacity, 00422 UInt_t reqSegs, UInt_t reqSegsCapacity, 00423 UInt_t reqPols, UInt_t reqPolsCapacity) : 00424 TBuffer3D(TBuffer3DTypes::kTube, reqPnts, reqPntsCapacity, reqSegs, reqSegsCapacity, reqPols, reqPolsCapacity), 00425 fRadiusInner(0.0), fRadiusOuter(1.0), fHalfLength(1.0) 00426 { 00427 //constructor 00428 } 00429 00430 //______________________________________________________________________________ 00431 TBuffer3DTube::TBuffer3DTube(Int_t type, 00432 UInt_t reqPnts, UInt_t reqPntsCapacity, 00433 UInt_t reqSegs, UInt_t reqSegsCapacity, 00434 UInt_t reqPols, UInt_t reqPolsCapacity) : 00435 TBuffer3D(type, reqPnts, reqPntsCapacity, reqSegs, reqSegsCapacity, reqPols, reqPolsCapacity), 00436 fRadiusInner(0.0), fRadiusOuter(1.0), fHalfLength(1.0) 00437 { 00438 //constructor 00439 } 00440 00441 //______________________________________________________________________________ 00442 TBuffer3DTubeSeg::TBuffer3DTubeSeg(UInt_t reqPnts, UInt_t reqPntsCapacity, 00443 UInt_t reqSegs, UInt_t reqSegsCapacity, 00444 UInt_t reqPols, UInt_t reqPolsCapacity) : 00445 TBuffer3DTube(TBuffer3DTypes::kTubeSeg, reqPnts, reqPntsCapacity, reqSegs, reqSegsCapacity, reqPols, reqPolsCapacity), 00446 fPhiMin(0.0), fPhiMax(360.0) 00447 { 00448 //constructor 00449 } 00450 00451 //______________________________________________________________________________ 00452 TBuffer3DTubeSeg::TBuffer3DTubeSeg(Int_t type, 00453 UInt_t reqPnts, UInt_t reqPntsCapacity, 00454 UInt_t reqSegs, UInt_t reqSegsCapacity, 00455 UInt_t reqPols, UInt_t reqPolsCapacity) : 00456 TBuffer3DTube(type, reqPnts, reqPntsCapacity, reqSegs, reqSegsCapacity, reqPols, reqPolsCapacity), 00457 fPhiMin(0.0), fPhiMax(360.0) 00458 { 00459 //constructor 00460 } 00461 00462 //______________________________________________________________________________ 00463 TBuffer3DCutTube::TBuffer3DCutTube(UInt_t reqPnts, UInt_t reqPntsCapacity, 00464 UInt_t reqSegs, UInt_t reqSegsCapacity, 00465 UInt_t reqPols, UInt_t reqPolsCapacity) : 00466 TBuffer3DTubeSeg(TBuffer3DTypes::kCutTube, reqPnts, reqPntsCapacity, reqSegs, reqSegsCapacity, reqPols, reqPolsCapacity) 00467 { 00468 //constructor 00469 fLowPlaneNorm[0] = 0.0; fLowPlaneNorm[0] = 0.0; fLowPlaneNorm[0] = -1.0; 00470 fHighPlaneNorm[0] = 0.0; fHighPlaneNorm[0] = 0.0; fHighPlaneNorm[0] = 1.0; 00471 } 00472 00473 //CS specific 00474 UInt_t TBuffer3D::fgCSLevel = 0; 00475 00476 //______________________________________________________________________________ 00477 UInt_t TBuffer3D::GetCSLevel() 00478 { 00479 //return CS level 00480 return fgCSLevel; 00481 } 00482 00483 //______________________________________________________________________________ 00484 void TBuffer3D::IncCSLevel() 00485 { 00486 //increment CS level 00487 ++fgCSLevel; 00488 } 00489 00490 //______________________________________________________________________________ 00491 UInt_t TBuffer3D::DecCSLevel() 00492 { 00493 //decrement CS level 00494 return --fgCSLevel; 00495 }