visual_collision_entity.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 #include "nel/3d/u_visual_collision_entity.h"
00027 
00028 #include "nel/3d/visual_collision_entity.h"
00029 #include "nel/3d/landscape.h"
00030 #include "nel/3d/dru.h"
00031 #include "nel/3d/driver.h"
00032 #include "nel/3d/tile_bank.h"
00033 #include "nel/misc/hierarchical_timer.h"
00034 
00035 
00036 using namespace std;
00037 using namespace NLMISC;
00038 
00039 
00040 namespace NL3D
00041 {
00042 
00043 
00044 // ***************************************************************************
00045 // should be at least 2 meters.
00046 const   float   CVisualCollisionEntity::BBoxRadius= 10;
00047 const   float   CVisualCollisionEntity::BBoxRadiusZ= 20;
00048 const   uint32  CVisualCollisionEntity::_StartPatchQuadBlockSize= 64;   // 256 octets per entity minimum.
00049 vector<CPatchBlockIdent>        CVisualCollisionEntity::_TmpBlockIds;
00050 vector<CPatchQuadBlock*>        CVisualCollisionEntity::_TmpPatchQuadBlocks;
00051 
00052 
00053 // ***************************************************************************
00054 CVisualCollisionEntity::CVisualCollisionEntity(CVisualCollisionManager *owner) : _LandscapeQuadGrid(owner)
00055 {
00056     _Owner= owner;
00057     _PatchQuadBlocks.reserve(_StartPatchQuadBlockSize);
00058 
00059     _CurrentBBoxValidity.setHalfSize(CVector::Null);
00060 
00061     _GroundMode= true;
00062     _CeilMode= false;
00063     _SnapToRenderedTesselation= true;
00064 
00065     _LastGPTValid= false;
00066 }
00067 
00068 
00069 // ***************************************************************************
00070 CVisualCollisionEntity::~CVisualCollisionEntity()
00071 {
00072     // delete the _PatchQuadBlocks.
00073     for(sint i=0; i<(sint)_PatchQuadBlocks.size(); i++)
00074     {
00075         _Owner->deletePatchQuadBlock(_PatchQuadBlocks[i]);
00076     }
00077     _PatchQuadBlocks.clear();
00078 
00079     // delete the quadgrid.
00080     _LandscapeQuadGrid.clear();
00081 }
00082 
00083 
00084 // ***************************************************************************
00085 bool        CVisualCollisionEntity::snapToGround(CVector &pos)
00086 {
00087     CVector     normal;
00088     // Not optimized, but doesn't matter (one cross product is negligible).
00089     return snapToGround(pos, normal);
00090 }
00091 
00092 
00093 // ***************************************************************************
00094 CTrianglePatch      *CVisualCollisionEntity::getPatchTriangleUnderUs(const CVector &pos, CVector &res)
00095 {
00096     // verify if landscape (refptr) is here.
00097     if(_Owner->_Landscape==NULL)
00098     {
00099         _LastGPTValid= false;
00100         return NULL;
00101     }
00102 
00103 
00104     // Test GPT cache.
00105     //==================
00106     // If last call was valid, and if same pos (input or output), return cached information
00107     if(_LastGPTValid && (pos==_LastGPTPosInput || pos==_LastGPTPosOutput) )
00108     {
00109         // copy from cache.
00110         res= _LastGPTPosOutput;
00111         /* don't modify _LastGPTPosInput cache, for best cache behavior in all cases.
00112             1/ this is not necessary (here, if pos!=_LastGPTPosInput, THEN pos==_LastGPTPosOutput, no other possibilities)
00113             2/ it causes problems when getPatchTriangleUnderUs() is called randomly with the unsnapped or snapped position:
00114                 1st Time: zin:9.0  =>  zout:9.5 cache fail (ok, 1st time...)
00115                 2nd Time: zin:9.0  =>  zout:9.5 cache OK (_LastGPTPosInput.z==zin)
00116                 3rd Time: zin:9.5  =>  zout:9.5 cache OK (_LastGPTPosOutput.z==zin)
00117                 4th Time: zin:9.0  =>  zout:9.5 cache FAILS (_LastGPTPosInput.z= 9.5 => !=zin)
00118         */
00119         // and return ptr on cache.
00120         return &_LastGPTTrianglePatch;
00121     }
00122 
00123 
00124     // update the cache of tile info near this position.
00125     // =================
00126     testComputeLandscape(pos);
00127 
00128 
00129     // find possible faces under the entity.
00130     // =================
00131     CVisualTileDescNode     *ptr= _LandscapeQuadGrid.select(pos);
00132 
00133 
00134     // find the better face under the entity.
00135     // =================
00136     float   sqrBestDist= sqr(1000.f);
00137     CVector hit;
00138     // build the vertical ray.
00139     CVector     segP0= pos - CVector(0,0,100);
00140     CVector     segP1= pos + CVector(0,0,100);
00141 
00142 
00143     // triangles builded from this list.
00144     static  vector<CTrianglePatch>      testTriangles;
00145     // NB: not so many reallocation here, because static.
00146     testTriangles.clear();
00147     sint    bestTriangle= 0;
00148 
00149 
00150     // For all the faces in this quadgrid node.
00151     while(ptr)
00152     {
00153         // what is the quad block of this tile Id.
00154         sint                qbId= ptr->PatchQuadBlocId;
00155         nlassert(qbId>=0 && qbId<(sint)_PatchQuadBlocks.size());
00156         CPatchQuadBlock     &qb= *_PatchQuadBlocks[qbId];
00157 
00158         // Build the 2 triangles of this tile Id.
00159         sint    idStart= testTriangles.size();
00160         testTriangles.resize(idStart+2);
00161         qb.buildTileTriangles((uint8)ptr->QuadId, &testTriangles[idStart]);
00162 
00163         // Test the 2 triangles.
00164         for(sint i=0; i<2; i++)
00165         {
00166             CTrianglePatch  &tri= testTriangles[idStart+i];
00167             // test if the ray intersect.
00168             // NB: triangleIntersect() is faster than CTriangle::intersect().
00169             if(triangleIntersect(tri, segP0, segP1, hit))
00170             {
00171                 // find the nearest triangle.
00172                 float sqrdist= (hit-pos).sqrnorm();
00173                 if(sqrdist<sqrBestDist)
00174                 {
00175                     bestTriangle= idStart+i;
00176                     res= hit;
00177                     sqrBestDist= sqrdist;
00178                 }
00179             }
00180         }
00181 
00182 
00183         // Next in the list.
00184         ptr= ptr->Next;
00185     }
00186 
00187 
00188     // found ??
00189     if(sqrBestDist<sqr(1000))
00190     {
00191         // copy into cache
00192         _LastGPTValid= true;
00193         _LastGPTTrianglePatch= testTriangles[bestTriangle];
00194         _LastGPTPosInput= pos;
00195         _LastGPTPosOutput= res;
00196         // and return ptr on cache.
00197         return &_LastGPTTrianglePatch;
00198     }
00199     else
00200     {
00201         _LastGPTValid= false;
00202         return NULL;
00203     }
00204 
00205 }
00206 
00207 
00208 // ***************************************************************************
00209 bool        CVisualCollisionEntity::snapToGround(CVector &pos, CVector &normal)
00210 {
00211     // Get Patch Triangle Under Us
00212     CVector     res;
00213     CTrianglePatch  *tri= getPatchTriangleUnderUs(pos, res);
00214 
00215     // result. NB: if not found, dot not modify.
00216     if( tri )
00217     {
00218         if(_SnapToRenderedTesselation)
00219         {
00220             // snap the position to the nearest tesselation.
00221             pos= res;
00222 
00223             // snap the position to the current rendered tesselation.
00224             snapToLandscapeCurrentTesselation(pos, *tri);
00225         }
00226         else
00227         {
00228             // just snap to the accurate tile tesselation.
00229             pos= res;
00230         }
00231 
00232 
00233         // compute the normal.
00234         normal= (tri->V1-tri->V0)^(tri->V2-tri->V0);
00235         normal.normalize();
00236 
00237         return true;
00238     }
00239     else
00240         return false;
00241 }
00242 
00243 
00244 // ***************************************************************************
00245 void        CVisualCollisionEntity::computeUvForPos(const CTrianglePatch &tri, const CVector &pos, CUV &uv)
00246 {
00247     // compute UV gradients.
00248     CVector     Gu;
00249     CVector     Gv;
00250     tri.computeGradient(tri.Uv0.U, tri.Uv1.U, tri.Uv2.U, Gu);
00251     tri.computeGradient(tri.Uv0.V, tri.Uv1.V, tri.Uv2.V, Gv);
00252     // interpolate
00253     uv.U= tri.Uv0.U + Gu*(pos-tri.V0);
00254     uv.V= tri.Uv0.V + Gv*(pos-tri.V0);
00255 }
00256 
00257 
00258 // ***************************************************************************
00259 void        CVisualCollisionEntity::snapToLandscapeCurrentTesselation(CVector &pos, const CTrianglePatch &tri)
00260 {
00261     // compute UV for position.
00262     CUV     uv;
00263     computeUvForPos(tri, pos, uv);
00264 
00265     // Ask pos to landscape.
00266     CVector     posLand;
00267     posLand= _Owner->_Landscape->getTesselatedPos(tri.PatchId, uv);
00268 
00269     // just keep Z.
00270     pos.z= posLand.z;
00271 }
00272 
00273 
00274 // ***************************************************************************
00275 // TestYoyo. For Precision problem.
00276 /*static bool   testLine(CVector &p1, CVector &p0, const CVector &pos0)
00277 {
00278     float   epsilon=    0.1f;
00279 
00280     float       a,b,c;      // 2D cartesian coefficients of line in plane X/Y.
00281     float       norm;
00282     // Line p0-p1.
00283     a= -(p1.y-p0.y);
00284     b= (p1.x-p0.x);
00285     norm= sqrtf(sqr(a) + sqr(b));
00286     a/= norm;
00287     b/= norm;
00288     c= -(p0.x*a + p0.y*b);
00289     if( (a*pos0.x + b*pos0.y + c) < -epsilon)
00290         return false;
00291     else
00292         return true;
00293 }*/
00294 
00295 
00296 // ***************************************************************************
00297 bool        CVisualCollisionEntity::triangleIntersect2DGround(CTriangle &tri, const CVector &pos0)
00298 {
00299     CVector     &p0= tri.V0;
00300     CVector     &p1= tri.V1;
00301     CVector     &p2= tri.V2;
00302 
00303     // TestYoyo. Test for precision problems.
00304     /*if( testLine(p1, p0, pos0) && testLine(p2, p1, pos0) && testLine(p0, p2, pos0) )
00305     {
00306         nlinfo("Found Tri For Pos: %.07f, %.07f\n   P0: %.07f, %.07f\n   P1: %.07f, %.07f\n   P2: %.07f, %.07f",
00307             pos0.x, pos0.y, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
00308     }*/
00309 
00310     // Test if the face enclose the pos in X/Y plane.
00311     // NB: compute and using a BBox to do a rapid test is not a very good idea, since it will
00312     // add an overhead which is NOT negligeable compared to the following test.
00313     float       a,b,c;      // 2D cartesian coefficients of line in plane X/Y.
00314     // Line p0-p1.
00315     a= -(p1.y-p0.y);
00316     b= (p1.x-p0.x);
00317     c= -(p0.x*a + p0.y*b);
00318     if( (a*pos0.x + b*pos0.y + c) < 0)  return false;
00319     // Line p1-p2.
00320     a= -(p2.y-p1.y);
00321     b= (p2.x-p1.x);
00322     c= -(p1.x*a + p1.y*b);
00323     if( (a*pos0.x + b*pos0.y + c) < 0)  return false;
00324     // Line p2-p0.
00325     a= -(p0.y-p2.y);
00326     b= (p0.x-p2.x);
00327     c= -(p2.x*a + p2.y*b);
00328     if( (a*pos0.x + b*pos0.y + c) < 0)  return false;
00329 
00330     return true;
00331 }
00332 
00333 // ***************************************************************************
00334 bool        CVisualCollisionEntity::triangleIntersect2DCeil(CTriangle &tri, const CVector &pos0)
00335 {
00336     CVector     &p0= tri.V0;
00337     CVector     &p1= tri.V1;
00338     CVector     &p2= tri.V2;
00339 
00340     // Test if the face enclose the pos in X/Y plane.
00341     // NB: compute and using a BBox to do a rapid test is not a very good idea, since it will
00342     // add an overhead which is NOT negligeable compared to the following test.
00343     float       a,b,c;      // 2D cartesian coefficients of line in plane X/Y.
00344     // Line p0-p1.
00345     a= -(p1.y-p0.y);
00346     b= (p1.x-p0.x);
00347     c= -(p0.x*a + p0.y*b);
00348     if( (a*pos0.x + b*pos0.y + c) > 0)  return false;
00349     // Line p1-p2.
00350     a= -(p2.y-p1.y);
00351     b= (p2.x-p1.x);
00352     c= -(p1.x*a + p1.y*b);
00353     if( (a*pos0.x + b*pos0.y + c) > 0)  return false;
00354     // Line p2-p0.
00355     a= -(p0.y-p2.y);
00356     b= (p0.x-p2.x);
00357     c= -(p2.x*a + p2.y*b);
00358     if( (a*pos0.x + b*pos0.y + c) > 0)  return false;
00359 
00360     return true;
00361 }
00362 
00363 // ***************************************************************************
00364 bool        CVisualCollisionEntity::triangleIntersect(CTriangle &tri, const CVector &pos0, const CVector &pos1, CVector &hit)
00365 {
00366     CVector     &p0= tri.V0;
00367     CVector     &p1= tri.V1;
00368     CVector     &p2= tri.V2;
00369 
00370     bool    ok= false;
00371     if( _GroundMode && triangleIntersect2DGround(tri, pos0) )
00372         ok= true;
00373     if(!ok && _CeilMode && triangleIntersect2DCeil(tri, pos0) )
00374         ok= true;
00375     if(!ok)
00376         return false;
00377 
00378 
00379     // Compute the possible height.
00380     CVector     tmp;
00381     // build the plane
00382     CPlane plane;
00383     plane.make (p0, p1, p2);
00384     // intersect the vertical line with the plane.
00385     tmp= plane.intersect(pos0, pos1);
00386 
00387     float       h= tmp.z;
00388     // Test if it would fit in the wanted field.
00389     if(h>pos1.z)    return false;
00390     if(h<pos0.z)    return false;
00391 
00392     // OK!!
00393     // For cache completness, ensure that X and Y don't move, take same XY than pos0
00394     hit.x= pos0.x;
00395     hit.y= pos0.y;
00396     hit.z= h;
00397     return true;
00398 }
00399 
00400 // ***************************************************************************
00401 void        CVisualCollisionEntity::testComputeLandscape(const CVector &pos)
00402 {
00403     // if new position is out of the bbox surounding the entity.
00404     if(_CurrentBBoxValidity.getHalfSize()==CVector::Null || !_CurrentBBoxValidity.include(pos))
00405     {
00406         // must recompute the data around the entity.
00407         doComputeLandscape(pos);
00408     }
00409 }
00410 
00411 // ***************************************************************************
00412 void        CVisualCollisionEntity::doComputeLandscape(const CVector &pos)
00413 {
00414     sint    i;
00415 
00416     // setup new bbox.
00417     //==================
00418     // compute the bbox which must includes the patchQuadBlocks
00419     CAABBox     bboxToIncludePatchs;
00420     bboxToIncludePatchs.setCenter(pos);
00421     bboxToIncludePatchs.setHalfSize(CVector(BBoxRadius, BBoxRadius, BBoxRadiusZ));
00422     // setup the _CurrentBBoxValidity with same values, but BBoxRadiusZ/2
00423     _CurrentBBoxValidity.setCenter(pos);
00424     _CurrentBBoxValidity.setHalfSize(CVector(BBoxRadius, BBoxRadius, BBoxRadiusZ/2));
00425 
00426 
00427     // Search landscape blocks which are in the bbox.
00428     //==================
00429     _Owner->_Landscape->buildPatchBlocksInBBox(bboxToIncludePatchs, _TmpBlockIds);
00430 
00431 
00432 
00433     // Recompute PatchQuadBlockcs.
00434     //==================
00435     // This parts try to keeps old patch blocks so they are not recomputed if they already here.
00436 
00437     // sort PatchBlockIdent.
00438     sort(_TmpBlockIds.begin(), _TmpBlockIds.end());
00439 
00440     // Copy old array of ptr (ptr copy only).
00441     _TmpPatchQuadBlocks= _PatchQuadBlocks;
00442 
00443     // allocate dest array.
00444     _PatchQuadBlocks.resize(_TmpBlockIds.size());
00445 
00446     // Traverse all current patchBlocks, deleting old ones no longer needed, and creating new ones.
00447     // this algorithm suppose both array are sorted.
00448     uint    iOld=0;
00449     // parse until dest is filled.
00450     for(i=0; i<(sint)_PatchQuadBlocks.size();)
00451     {
00452         // get requested new BlockIdent.
00453         CPatchBlockIdent    newBi= _TmpBlockIds[i];
00454 
00455         // get requested old BlockIdent in the array.
00456         bool                oldEnd= false;
00457         CPatchBlockIdent    oldBi;
00458         if(iOld==_TmpPatchQuadBlocks.size())
00459             oldEnd= true;
00460         else
00461             oldBi= _TmpPatchQuadBlocks[iOld]->PatchBlockId;
00462 
00463         // if no more old blocks, or if new Block is < than current, we must create a new block, and insert it.
00464         if(oldEnd || newBi < oldBi)
00465         {
00466             // allocate the patch block.
00467             _PatchQuadBlocks[i]= _Owner->newPatchQuadBlock();
00468             // fill the patch block.
00469             _PatchQuadBlocks[i]->PatchBlockId= _TmpBlockIds[i];
00470             _Owner->_Landscape->fillPatchQuadBlock(*_PatchQuadBlocks[i]);
00471 
00472             // next new patch block.
00473             i++;
00474         }
00475         // else if current new Block is same than old block, just copy ptr.
00476         else if(newBi==oldBi)
00477         {
00478             // just copy ptr with the old one.
00479             _PatchQuadBlocks[i]= _TmpPatchQuadBlocks[iOld];
00480 
00481             // next new and old patch block.
00482             i++;
00483             iOld++;
00484         }
00485         // else, this old block is no longer used, delete it.
00486         else
00487         {
00488             _Owner->deletePatchQuadBlock(_TmpPatchQuadBlocks[iOld]);
00489             // next old patch block.
00490             iOld++;
00491         }
00492     }
00493     // Here, must delete old blocks not yet processed.
00494     for(;iOld<_TmpPatchQuadBlocks.size(); iOld++)
00495     {
00496         _Owner->deletePatchQuadBlock(_TmpPatchQuadBlocks[iOld]);
00497     }
00498     _TmpPatchQuadBlocks.clear();
00499 
00500 
00501     // Compute the quadGrid.
00502     //==================
00503 
00504     // Compute a delta so elt position for CLandscapeCollisionGrid are positive, and so fastFloor() used will work.
00505     CVector     delta;
00506     // center the position on 0.
00507     // floor may be important for precision when the delta is applied.
00508     delta.x= (float)floor(-pos.x);
00509     delta.y= (float)floor(-pos.y);
00510     delta.z= 0;
00511     // We must always have positive values for patchBlocks vertices.
00512     float   val= (float)ceil(BBoxRadius + 256);
00513     // NB: 256 is a security. Because of size of patchs, a value of 32 at max should be sufficient (64 for bigger patch (gfx))
00514     // we are large because doesn't matter, the CLandscapeCollisionGrid tiles.
00515     delta.x+= val;
00516     delta.y+= val;
00517 
00518     // rebuild the quadGrid.
00519     _LandscapeQuadGrid.build(_PatchQuadBlocks, delta);
00520 
00521 }
00522 
00523 
00524 // ***************************************************************************
00525 bool        CVisualCollisionEntity::getStaticLightSetup(NLMISC::CRGBA sunAmbient, const CVector &pos,
00526     std::vector<CPointLightInfluence> &pointLightList, uint8 &sunContribution, NLMISC::CRGBA &localAmbient)
00527 {
00528     // Get Patch Triangle Under Us
00529     CVector     res;
00530     CTrianglePatch  *tri= getPatchTriangleUnderUs(pos, res);
00531 
00532     // For now, no special ambient support on landscape => take sunAmbient
00533     localAmbient= sunAmbient;
00534 
00535     // result. NB: if not found, dot not modify.
00536     if( tri )
00537     {
00538         // compute UV for position.
00539         CUV     uv;
00540         computeUvForPos(*tri, pos, uv);
00541 
00542         // get the sunContribution
00543         sunContribution= _Owner->_Landscape->getLumel(tri->PatchId, uv);
00544         // see getStaticLightSetup.
00545         sunContribution= _Owner->_SunContributionLUT[sunContribution];
00546 
00547         // append any lights of interest.
00548         _Owner->_Landscape->appendTileLightInfluences(tri->PatchId, uv, pointLightList);
00549 
00550         return true;
00551     }
00552     else
00553     {
00554         // Suppose full Sun Contribution, and don't add any pointLight
00555         sunContribution= 255;
00556 
00557         return false;
00558     }
00559 }
00560 
00561 
00562 // ***************************************************************************
00563 bool        CVisualCollisionEntity::getSurfaceInfo(const CVector &pos, CSurfaceInfo &surfaceInfo)
00564 {
00565     H_AUTO( NL3D_CVisualCollisionEntity_getSurfaceInfo )
00566     // Get Patch Triangle Under Us
00567     CVector     res;
00568     CTrianglePatch  *tri= getPatchTriangleUnderUs(pos, res);
00569 
00570     // result. NB: if not found, dot not modify.
00571     if( tri )
00572     {
00573         // compute UV for position.
00574         CUV     uv;
00575         computeUvForPos(*tri, pos, uv);
00576 
00577         // get the tileelement
00578         CTileElement *tileElm = _Owner->_Landscape->getTileElement(tri->PatchId, uv);
00579         if (tileElm)
00580         {
00581             // Valid tile ?
00582             uint16 tileId = tileElm->Tile[0];
00583             if (tileId != NL_TILE_ELM_LAYER_EMPTY)
00584             {
00585                 // The tilebank
00586                 CTileBank &tileBank = _Owner->_Landscape->TileBank;
00587 
00588                 // Get xref info for this tile
00589                 int tileSet;
00590                 int number;
00591                 CTileBank::TTileType type;
00592                 tileBank.getTileXRef ((int)tileId, tileSet, number, type);
00593 
00594                 // Get the tileset from layer 0
00595                 const CTileSet* tileSetPtr = tileBank.getTileSet (tileSet);
00596 
00597                 // Fill the surface
00598                 surfaceInfo.UserSurfaceData = tileSetPtr->SurfaceData;
00599 
00600                 // Ok
00601                 return true;
00602             }
00603         }
00604     }
00605     return false;
00606 }
00607 
00608 
00609 // ***************************************************************************
00610 void        CVisualCollisionEntity::displayDebugGrid(IDriver &drv) const
00611 {
00612     // static to not reallocate each frame
00613     static  CMaterial   mat;
00614     static  bool        inited= false;
00615     if(!inited)
00616     {
00617         inited= true;
00618         mat.initUnlit();
00619     }
00620     static  vector<CLine>   lineList;
00621     lineList.clear();
00622 
00623     // Build lines for all patch quad blocks.
00624     for(uint i=0;i<_PatchQuadBlocks.size();i++)
00625     {
00626         CPatchQuadBlock     &pqb= *_PatchQuadBlocks[i];
00627         // Parse all quads of this patch block.
00628         CPatchBlockIdent    &pbid= pqb.PatchBlockId;
00629         for(uint t= pbid.T0; t<pbid.T1; t++)
00630         {
00631             for(uint s= pbid.S0; s<pbid.S1; s++)
00632             {
00633                 // compute quad coordinate in pqb.
00634                 uint    sd0= (s-pbid.S0);
00635                 uint    td0= (t-pbid.T0);
00636                 uint    sd1= sd0+1;
00637                 uint    td1= td0+1;
00638                 // get 4 vertex coord of quad
00639                 const CVector   &p0= pqb.Vertices[sd0 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
00640                 const CVector   &p1= pqb.Vertices[sd0 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
00641                 const CVector   &p2= pqb.Vertices[sd1 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
00642                 const CVector   &p3= pqb.Vertices[sd1 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
00643 
00644                 // build the 5 lines
00645                 lineList.push_back(CLine(p0, p1));
00646                 lineList.push_back(CLine(p1, p2));
00647                 lineList.push_back(CLine(p2, p3));
00648                 lineList.push_back(CLine(p3, p0));
00649                 lineList.push_back(CLine(p0, p2));
00650             }
00651         }
00652     }
00653 
00654     // Display the lines.
00655     CDRU::drawLinesUnlit(lineList, mat, drv);
00656 }
00657 
00658 
00659 
00660 } // NL3D

Generated on Thu Jan 7 08:26:32 2010 for NeL by  doxygen 1.6.1