Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / patch.cpp
blob29f960a280a1bbcd5d87f1295acbb5ddba82cd2e
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
20 #include "nel/3d/patch.h"
21 #include "nel/3d/tessellation.h"
22 #include "nel/3d/bezier_patch.h"
23 #include "nel/3d/zone.h"
24 #include "nel/3d/landscape.h"
25 #include "nel/misc/vector.h"
26 #include "nel/misc/common.h"
27 #include "nel/3d/patchuv_locator.h"
28 #include "nel/3d/vegetable_manager.h"
29 #include "nel/misc/fast_floor.h"
30 #include "nel/3d/light_influence_interpolator.h"
31 #include "nel/3d/patchdlm_context.h"
32 #include "nel/misc/hierarchical_timer.h"
33 #include "nel/3d/u_landscape.h"
35 using namespace std;
36 using namespace NLMISC;
38 // Define this to remove user color (debug)
39 // #define NEL_FORCE_NO_USER_COLOR
41 #ifdef DEBUG_NEW
42 #define new DEBUG_NEW
43 #endif
45 namespace NL3D
49 // ***************************************************************************
50 CBezierPatch CPatch::CachePatch;
51 const CPatch *CPatch::LastPatch= NULL;
52 uint32 CPatch::_Version=7;
55 // ***************************************************************************
56 CPatch::CPatch()
58 Zone= NULL;
59 OrderS=0;
60 OrderT=0;
61 Son0=NULL;
62 Son1=NULL;
63 TessBlockRefCount=0;
64 NumRenderableFaces= 0;
66 // for Pacs process. By default, false.
67 ExcludeFromRefineAll= false;
69 // Init Passes.
70 // DO NOT FILL Patch here, because of operator= problem. do it in compile().
71 // By default, RdrPasses are NULL.
73 // To force computation of texture info on next preRender().
74 Far0= -1;
75 Far1= -1;
77 // Default: not binded.
78 _BindZoneNeighbor[0]= NULL;
79 _BindZoneNeighbor[1]= NULL;
80 _BindZoneNeighbor[2]= NULL;
81 _BindZoneNeighbor[3]= NULL;
82 NoiseRotation= 0;
83 // No smooth by default.
84 _CornerSmoothFlag= 0;
86 // MasterBlock never clipped.
87 MasterBlock.resetClip();
89 // Init UL circular list to NULL (not compiled)
90 _ULNearPrec= NULL;
91 _ULNearNext= NULL;
93 // Dynamic LightMap
94 _DLMContext= NULL;
95 _DLMContextRefCount= 0;
97 // Render Passes
98 _PatchRdrPassFar0= NULL;
99 _NextRdrFar0= NULL;
100 _PatchRdrPassFar1= NULL;
101 _NextRdrFar1= NULL;
103 // ***************************************************************************
104 CPatch::~CPatch()
106 release();
109 // ***************************************************************************
110 void CPatch::release()
112 if(Zone)
114 // First, delete the VB if the zone was removed while the patch is visible.
115 if(!isRenderClipped())
117 // release VertexBuffer.
118 deleteVBAndFaceVector();
119 // Flag RenderClipped in Zone
120 Zone->_PatchRenderClipped.set(PatchId, true);
123 // THIS PATCH MSUT BE UNBOUND FIRST!!!!!
124 nlassert(Son0 && Son1);
125 nlassert(Son0->isLeaf() && Son1->isLeaf());
126 nlassert(Son0->FLeft == NULL);
127 nlassert(Son0->FRight == NULL);
128 nlassert(Son1->FLeft == NULL);
129 nlassert(Son1->FRight == NULL);
131 // Free renderPass of landscape, and maybe force computation of texture info on next preRender().
132 // Must do it here, before deletion of Zone, OrderS/T etc...
133 resetRenderFar();
135 getLandscape()->deleteTessFace(Son0);
136 getLandscape()->deleteTessFace(Son1);
137 // Vertices are smartptr/deleted in zone.
140 // Flag the fact that this patch can't be rendered.
141 OrderS=0;
142 OrderT=0;
143 Son0=NULL;
144 Son1=NULL;
145 clearTessBlocks();
146 resetMasterBlock();
147 // Flag RenderClipped in Zone
148 if(Zone)
150 Zone->_PatchRenderClipped.set( PatchId, true);
151 Zone->_PatchOldRenderClipped.set( PatchId, true);
154 // the pathc is uncompiled. must do it after clearTessBlocks(), because may use it
155 // for vegetable manager, and for updateLighting
156 Zone= NULL;
158 // uncompile: reset UpdateLighting circular list to NULL.
159 if(_ULNearPrec!= NULL)
161 // verify the patch is correctly unlinked from any ciruclar list.
162 nlassert(_ULNearPrec==this && _ULNearNext==this);
164 _ULNearPrec= NULL;
165 _ULNearNext= NULL;
167 // DynamciLightMap: release the _DLMContext if still exist.
168 if(_DLMContext)
169 delete _DLMContext;
170 // reset
171 _DLMContext= NULL;
172 _DLMContextRefCount= 0;
176 // ***************************************************************************
177 CBezierPatch *CPatch::unpackIntoCache() const
179 if(LastPatch!=this)
181 unpack(CachePatch);
182 LastPatch=this;
184 return &CachePatch;
186 // ***************************************************************************
187 void CPatch::unpack(CBezierPatch &p) const
189 sint i;
190 const CVector &bias= Zone->getPatchBias();
191 float scale= Zone->getPatchScale();
193 for(i=0;i<4;i++)
194 Vertices[i].unpack(p.Vertices[i], bias, scale);
195 for(i=0;i<8;i++)
196 Tangents[i].unpack(p.Tangents[i], bias, scale);
197 for(i=0;i<4;i++)
198 Interiors[i].unpack(p.Interiors[i], bias, scale);
200 // ***************************************************************************
201 void CPatch::computeDefaultErrorSize()
203 CBezierPatch &p= *unpackIntoCache();
204 CVector &v0= p.Vertices[0];
205 CVector &v1= p.Vertices[1];
206 CVector &v2= p.Vertices[2];
208 // \todo yoyo: TODO_NOISE: modulate this value with tangents (roundiness of patch), and with the displacement map.
209 ErrorSize= ((v1 - v0)^(v2 - v0)).norm();
215 // ***************************************************************************
216 void CPatch::buildBBoxFromBezierPatch(const CBezierPatch &p, CAABBox &ret) const
218 // Because of the structure of CAABBox, extend() is not fast enough for us. first compute bmin, bmax,
219 // then compute the bbox.
220 CVector bmin= p.Vertices[0];
221 CVector bmax= bmin;
223 sint i;
224 for(i=0;i<4;i++)
226 bmin.minof(bmin, p.Vertices[i]);
227 bmax.maxof(bmax, p.Vertices[i]);
229 for(i=0;i<8;i++)
231 bmin.minof(bmin, p.Tangents[i]);
232 bmax.maxof(bmax, p.Tangents[i]);
234 for(i=0;i<4;i++)
236 bmin.minof(bmin, p.Interiors[i]);
237 bmax.maxof(bmax, p.Interiors[i]);
240 // Modulate with the maximum displacement map (useful for patch clipping).
241 static CVector vectorNoiseMax(NL3D_NOISE_MAX, NL3D_NOISE_MAX, NL3D_NOISE_MAX);
242 bmin-= vectorNoiseMax;
243 bmax+= vectorNoiseMax;
244 // NB: this is not very optimal, since the BBox may be very too big. eg: patch 16mx16m => bbox 18mx18m.
245 // But remind that tessblocks do not use this BBox, and are computed with the real geometry.
247 ret.setMinMax(bmin, bmax);
251 // ***************************************************************************
252 CAABBox CPatch::buildBBox() const
254 CBezierPatch &p= *unpackIntoCache();
256 // Compute Bounding Box. (easiest way...)
257 CAABBox ret;
258 buildBBoxFromBezierPatch(p, ret);
260 return ret;
264 // ***************************************************************************
265 void CPatch::addTrianglesInBBox(CPatchIdent paId, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel) const
267 CBezierPatch &bpatch= *unpackIntoCache();
269 // call with the whole root patch.
270 addTrianglesInBBoxRecurs(paId, bbox, triangles, tileTessLevel, bpatch, 0, OrderS, 0, OrderT);
274 // ***************************************************************************
275 void CPatch::addTrianglesInBBoxRecurs(CPatchIdent paId, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tessLevel,
276 const CBezierPatch &pa, uint8 s0, uint8 s1, uint8 t0, uint8 t1) const
278 uint8 lenS=s1-s0, lenT=t1-t0;
279 nlassert(lenS>0);
280 nlassert(lenT>0);
282 // compute and compare bbox of the subdivision patch against request bbox.
283 //========================
284 // NB: this compute includes possible noise.
285 CAABBox paBBox;
286 buildBBoxFromBezierPatch(pa, paBBox);
287 // if do not intersect, stop here.
288 if( !paBBox.intersect(bbox) )
289 return;
290 // else if at tile level, then just computeTriangles.
291 //========================
292 else if( lenS==1 && lenT==1 )
294 addTileTrianglesInBBox(paId, bbox, triangles, tessLevel, s0, t0);
296 // else subdiv and reccurs.
297 //========================
298 else
300 // Subdivide along the bigger side.
301 if(lenS>lenT)
303 // subdivide.
304 CBezierPatch left, right;
305 pa.subdivideS(left, right);
306 uint8 sMiddle= (uint8)( ((uint)s0+(uint)s1) /2 );
307 // recurs left.
308 addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, left, s0, sMiddle, t0, t1);
309 // recurs right.
310 addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, right, sMiddle, s1, t0, t1);
312 else
314 // subdivide.
315 CBezierPatch top, bottom;
316 pa.subdivideT(top, bottom);
317 uint8 tMiddle= (uint8)( ((uint)t0+(uint)t1) /2 );
318 // recurs top.
319 addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, top, s0, s1, t0, tMiddle);
320 // recurs bottom.
321 addTrianglesInBBoxRecurs(paId, bbox, triangles, tessLevel, bottom, s0, s1, tMiddle, t1);
329 // ***************************************************************************
330 void CPatch::addTileTrianglesInBBox(CPatchIdent paId, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tessLevel, uint8 s0, uint8 t0) const
332 nlassert(s0<OrderS);
333 nlassert(t0<OrderT);
334 nlassert(tessLevel<=2);
335 uint tessLen= 1<<tessLevel;
337 // some preca.
338 float startS0= (float)s0 / (float)(OrderS);
339 float startT0= (float)t0 / (float)(OrderT);
340 float ds= 1.0f/(float)(OrderS*tessLen);
341 float dt= 1.0f/(float)(OrderT*tessLen);
343 // Parse all quads.
344 uint sl,tl;
345 for(tl=0; tl<tessLen; tl++)
347 float fs0, fs1, ft0, ft1;
348 // compute t patch coordinates.
349 ft0= startT0 + (float)tl * dt ;
350 ft1= ft0 + dt;
351 for(sl=0; sl<tessLen; sl++)
353 // compute s patch coordinates.
354 fs0= startS0 + (float)sl * ds ;
355 fs1= fs0 + ds;
357 // Compute Quad vectors (in CCW).
358 CVector p0, p1, p2, p3;
359 CUV uv0, uv1, uv2, uv3;
360 uv0.U= fs0; uv0.V= ft0;
361 uv1.U= fs0; uv1.V= ft1;
362 uv2.U= fs1; uv2.V= ft1;
363 uv3.U= fs1; uv3.V= ft0;
364 // evaluate patch (with noise). (NB: because of cache, patch decompression cost nothing).
365 p0= computeVertex(uv0.U, uv0.V);
366 p1= computeVertex(uv1.U, uv1.V);
367 p2= computeVertex(uv2.U, uv2.V);
368 p3= computeVertex(uv3.U, uv3.V);
370 // build the bbox of this quad, and test with request bbox.
371 CAABBox quadBBox;
372 quadBBox.setCenter(p0);
373 quadBBox.extend(p1);
374 quadBBox.extend(p2);
375 quadBBox.extend(p3);
377 // insert only if intersect with the bbox.
378 if(quadBBox.intersect(bbox))
380 // build triangles (in CCW).
381 CTrianglePatch tri;
382 tri.PatchId= paId;
384 // first tri.
385 tri.V0= p0; tri.V1= p1; tri.V2= p2;
386 tri.Uv0= uv0; tri.Uv1= uv1; tri.Uv2= uv2;
387 triangles.push_back(tri);
389 // second tri.
390 tri.V0= p2; tri.V1= p3; tri.V2= p0;
391 tri.Uv0= uv2; tri.Uv1= uv3; tri.Uv2= uv0;
392 triangles.push_back(tri);
394 // NB: this is not the same tesselation than in tesselation.cpp.
395 // But this looks like Ben's NLPACS::CLocalRetriever tesselation.
404 // ***************************************************************************
405 void CPatchQuadBlock::buildTileTriangles(uint8 quadId, CTrianglePatch triangles[2]) const
407 // copute coordinate of the tile we want.
408 uint sd0= quadId&(NL_PATCH_BLOCK_MAX_QUAD-1);
409 uint td0= quadId/(NL_PATCH_BLOCK_MAX_QUAD);
410 uint sd1= sd0+1;
411 uint td1= td0+1;
412 uint s= PatchBlockId.S0+sd0;
413 uint t= PatchBlockId.T0+td0;
414 nlassert(s<PatchBlockId.S1);
415 nlassert(t<PatchBlockId.T1);
417 // Compute UV coord.
418 float fs0= (float)s / (float)(PatchBlockId.OrderS);
419 float ft0= (float)t / (float)(PatchBlockId.OrderT);
420 float fs1= (float)(s+1) / (float)(PatchBlockId.OrderS);
421 float ft1= (float)(t+1) / (float)(PatchBlockId.OrderT);
422 CUV uv0, uv1, uv2, uv3;
423 uv0.U= fs0; uv0.V= ft0;
424 uv1.U= fs0; uv1.V= ft1;
425 uv2.U= fs1; uv2.V= ft1;
426 uv3.U= fs1; uv3.V= ft0;
428 // get vertex coord.
429 const CVector &p0= Vertices[sd0 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
430 const CVector &p1= Vertices[sd0 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
431 const CVector &p2= Vertices[sd1 + td1*NL_PATCH_BLOCK_MAX_VERTEX];
432 const CVector &p3= Vertices[sd1 + td0*NL_PATCH_BLOCK_MAX_VERTEX];
434 // build triangles.
435 // first tri.
437 CTrianglePatch &tri= triangles[0];
438 tri.PatchId= PatchBlockId.PatchId;
439 tri.V0= p0; tri.V1= p1; tri.V2= p2;
440 tri.Uv0= uv0; tri.Uv1= uv1; tri.Uv2= uv2;
443 // second tri.
445 CTrianglePatch &tri= triangles[1];
446 tri.PatchId= PatchBlockId.PatchId;
447 tri.V0= p2; tri.V1= p3; tri.V2= p0;
448 tri.Uv0= uv2; tri.Uv1= uv3; tri.Uv2= uv0;
454 // ***************************************************************************
455 void CPatch::fillPatchQuadBlock(CPatchQuadBlock &quadBlock) const
457 CPatchBlockIdent &pbId= quadBlock.PatchBlockId;
458 uint lenS= pbId.S1-pbId.S0;
459 uint lenT= pbId.T1-pbId.T0;
460 nlassert( pbId.OrderS==OrderS );
461 nlassert( pbId.OrderT==OrderT );
462 nlassert( pbId.S1<=OrderS );
463 nlassert( pbId.T1<=OrderT );
464 nlassert( pbId.S0<pbId.S1 );
465 nlassert( pbId.T0<pbId.T1 );
466 nlassert( lenS<=NL_PATCH_BLOCK_MAX_QUAD );
467 nlassert( lenT<=NL_PATCH_BLOCK_MAX_QUAD );
469 // Fill vertices.
470 uint s0= pbId.S0;
471 uint t0= pbId.T0;
472 // some preca.
473 float startS0= (float)s0 / (float)(OrderS);
474 float startT0= (float)t0 / (float)(OrderT);
475 float ds= 1.0f/(float)(OrderS);
476 float dt= 1.0f/(float)(OrderT);
478 // Parse all quads vertices corner.
479 uint sl,tl;
480 for(tl=0; tl<lenT+1; tl++)
482 float fs, ft;
483 // compute t patch coordinates.
484 ft= startT0 + (float)tl * dt ;
485 for(sl=0; sl<lenS+1; sl++)
487 // compute s patch coordinates.
488 fs= startS0 + (float)sl * ds ;
490 // Must use computeContinousVertex, to ensure continous coordinate on patch edges
491 quadBlock.Vertices[sl + tl*NL_PATCH_BLOCK_MAX_VERTEX]= computeContinousVertex(fs, ft);
498 // ***************************************************************************
499 void CPatch::addPatchBlocksInBBox(CPatchIdent paId, const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds) const
501 CBezierPatch &bpatch= *unpackIntoCache();
503 // call with the whole root patch.
504 addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, bpatch, 0, OrderS, 0, OrderT);
508 // ***************************************************************************
509 void CPatch::addPatchBlocksInBBoxRecurs(CPatchIdent paId, const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds,
510 const CBezierPatch &pa, uint8 s0, uint8 s1, uint8 t0, uint8 t1) const
512 uint8 lenS=s1-s0, lenT=t1-t0;
513 nlassert(lenS>0);
514 nlassert(lenT>0);
516 // compute and compare bbox of the subdivision patch against request bbox.
517 //========================
518 // NB: this compute includes possible noise.
519 CAABBox paBBox;
520 buildBBoxFromBezierPatch(pa, paBBox);
521 // if do not intersect, stop here.
522 if( !paBBox.intersect(bbox) )
523 return;
524 // else if at CPatchQuadBlock tile level, then just add this Id.
525 //========================
526 else if( lenS<=NL_PATCH_BLOCK_MAX_QUAD && lenT<=NL_PATCH_BLOCK_MAX_QUAD )
528 // Add this PatchBlock desctiptor to the list.
529 CPatchBlockIdent pbId;
530 // Fill struct from this and result of recursion.
531 pbId.PatchId= paId;
532 pbId.OrderS= OrderS;
533 pbId.OrderT= OrderT;
534 pbId.S0= s0;
535 pbId.S1= s1;
536 pbId.T0= t0;
537 pbId.T1= t1;
538 // Add to list.
539 paBlockIds.push_back(pbId);
541 // else subdiv and reccurs.
542 //========================
543 else
545 // Subdivide along the bigger side.
546 if(lenS>lenT)
548 // subdivide.
549 CBezierPatch left, right;
550 pa.subdivideS(left, right);
551 uint8 sMiddle= (uint8)( ((uint)s0+(uint)s1) /2 );
552 // recurs left.
553 addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, left, s0, sMiddle, t0, t1);
554 // recurs right.
555 addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, right, sMiddle, s1, t0, t1);
557 else
559 // subdivide.
560 CBezierPatch top, bottom;
561 pa.subdivideT(top, bottom);
562 uint8 tMiddle= (uint8)( ((uint)t0+(uint)t1) /2 );
563 // recurs top.
564 addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, top, s0, s1, t0, tMiddle);
565 // recurs bottom.
566 addPatchBlocksInBBoxRecurs(paId, bbox, paBlockIds, bottom, s0, s1, tMiddle, t1);
573 // ***************************************************************************
574 CVector CPatch::getTesselatedPos(CUV uv) const
576 // clamp values.
577 clamp(uv.U, 0, 1);
578 clamp(uv.V, 0, 1);
579 // recurs down the 2 sons.
580 CVector ret= CVector::Null;
581 Son0->getTesselatedPos(uv, true, ret);
582 Son1->getTesselatedPos(uv, true, ret);
584 return ret;
588 // ***************************************************************************
589 bool CPatch::isRenderClipped() const
591 if(Zone)
592 return Zone->isPatchRenderClipped(PatchId);
593 else
594 return true;
598 // ***************************************************************************
599 // ***************************************************************************
600 // RENDER LIST.
601 // ***************************************************************************
602 // ***************************************************************************
605 // ***************************************************************************
606 void CPatch::addRefTessBlocks()
608 uint i;
610 TessBlockRefCount++;
612 if (TessBlocks.empty())
614 // Allocate the tessblocks.
615 //==========
617 nlassert(NL3D_TESSBLOCK_TILESIZE==4);
618 // A tessblock is 2*2 tiles.
619 sint os= OrderS>>1;
620 sint ot= OrderT>>1;
621 nlassert(os>0);
622 nlassert(ot>0);
623 TessBlocks.resize(os*ot);
624 // init all tessBlocks with the Patch ptr.
625 for(i=0; i<TessBlocks.size(); i++)
626 TessBlocks[i].init(this);
629 // Vegetable management
630 //==========
631 CVegetableManager *vegetableManager= getLandscape()->_VegetableManager;
633 // Create ClipBlocks.
634 uint nTbPerCb= NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK;
635 uint wCB= (os + nTbPerCb-1) >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
636 uint hCB= (ot + nTbPerCb-1) >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
637 VegetableClipBlocks.resize(wCB * hCB);
638 // allocate ClipBlocks
639 for(i=0; i<VegetableClipBlocks.size(); i++)
641 VegetableClipBlocks[i]= vegetableManager->createClipBlock();
645 // updateLighting management.
646 //==========
647 // append patch for Near updateLighting, since TessBlock lightmap may/will exist.
648 getLandscape()->linkPatchToNearUL(this);
653 // ***************************************************************************
654 void CPatch::decRefTessBlocks()
656 TessBlockRefCount--;
657 // If no loinger need the tessblocks, delete them.
658 if(TessBlockRefCount==0)
659 clearTessBlocks();
660 nlassert(TessBlockRefCount>=0);
664 // ***************************************************************************
665 void CPatch::clearTessBlocks()
667 uint i;
669 // Vegetable management
670 //==========
671 // if compiled.
672 if(Zone)
674 CVegetableManager *vegetableManager= getLandscape()->_VegetableManager;
676 // delete still existing vegetable Igs.
677 deleteAllVegetableIgs();
679 // delete ClipBlocks.
680 for(i=0; i<VegetableClipBlocks.size(); i++)
682 vegetableManager->deleteClipBlock(VegetableClipBlocks[i]);
684 contReset(VegetableClipBlocks);
688 // updateLighting management.
689 //==========
690 if(Zone)
692 // remove patch from Near updateLighting, since no more TessBlock lightmap can exist.
693 getLandscape()->unlinkPatchFromNearUL(this);
697 // Delete TessBlocks
698 //==========
699 TessBlockRefCount=0;
700 contReset(TessBlocks);
704 // ***************************************************************************
705 void CPatch::resetMasterBlock()
707 // We should be not visible so FaceVector no more exist.
708 nlassert(isRenderClipped());
710 MasterBlock.FarVertexList.clear();
711 MasterBlock.FarFaceList.clear();
712 NumRenderableFaces= 0;
713 // no tiles should be here!!
714 nlassert(MasterBlock.NearVertexList.size()==0);
717 // ***************************************************************************
718 uint CPatch::getNumTessBlock(CTessFace *face)
720 // To which tessBlocks link the face?
721 // compute an approx middle of the face.
722 CParamCoord edgeMid(face->PVLeft, face->PVRight);
723 CParamCoord middle(edgeMid, face->PVBase);
724 // Coordinate of the tessblock (2*2 a tile!! so the >>1).
725 uint ts= ((uint)middle.S * (uint)(OrderS>>1)) / 0x8000;
726 uint tt= ((uint)middle.T * (uint)(OrderT>>1)) / 0x8000;
727 uint numtb= tt*(uint)(OrderS>>1) + ts;
729 return numtb;
733 // ***************************************************************************
734 void CPatch::getNumTessBlock(CParamCoord pc, TFarVertType &type, uint &numtb)
736 uint tboS= (uint)(OrderS>>1);
737 uint tboT= (uint)(OrderT>>1);
739 // Coordinate of the tessblock (2*2 a tile!! so the >>1).
740 uint ts= ((uint)pc.S * tboS) / 0x8000;
741 uint tt= ((uint)pc.T * tboT) / 0x8000;
742 numtb= tt*tboS + ts;
744 bool edgeS= (ts*0x8000) == ((uint)pc.S * tboS);
745 bool edgeT= (tt*0x8000) == ((uint)pc.T * tboT);
747 // Does this vertex lies on a corner of a TessBlock?
748 if(edgeS && edgeT)
749 type= FVMasterBlock;
750 // Does this vertex lies on a edge of a TessBlock?
751 else if(edgeS || edgeT)
752 type= FVTessBlockEdge;
753 // Else it lies exclusively IN a TessBlock.
754 else
755 type= FVTessBlock;
761 // ***************************************************************************
762 void CPatch::extendTessBlockWithEndPos(CTessFace *face)
764 if(face->Level>=TessBlockLimitLevel)
766 // get the tessBlock of the face.
767 uint numtb= getNumTessBlock(face);
769 // Must enlarge the BSphere of the tesblock!!
770 TessBlocks[numtb].extendSphereFirst(face->VBase->EndPos);
771 TessBlocks[numtb].extendSphereAdd(face->VLeft->EndPos);
772 TessBlocks[numtb].extendSphereAdd(face->VRight->EndPos);
773 TessBlocks[numtb].extendSphereCompile();
778 // ***************************************************************************
779 void CPatch::dirtTessBlockFaceVector(CTessBlock &tb)
781 // If patch is visible, block's faceVector should exist, but are no more valid.
782 if(!isRenderClipped())
784 // If this tessBlock not already notified to modification.
785 if(!tb.isInModifyList())
787 // Then append, and delete all FaceVector.
788 // NB: delete FaceVector now, because the TessBlock himself may disapear soon.
789 tb.appendToModifyListAndDeleteFaceVector(getLandscape()->_TessBlockModificationRoot, getLandscape()->_FaceVectorManager);
795 // ***************************************************************************
796 void CPatch::appendFaceToRenderList(CTessFace *face)
798 // Update the number of renderable Faces
799 NumRenderableFaces++;
801 // Update Gnal render.
802 //====================
803 if(face->Level<TessBlockLimitLevel)
805 MasterBlock.FarFaceList.append(face);
806 MasterBlock.FaceTileMaterialRefCount++;
808 // The facelist is modified, so we must update the faceVector, if visible.
809 dirtTessBlockFaceVector(MasterBlock);
811 else
813 // Alloc if necessary the TessBlocks.
814 addRefTessBlocks();
816 // link the face to the good tessblock.
817 uint numtb= getNumTessBlock(face);
818 TessBlocks[numtb].FarFaceList.append(face);
819 TessBlocks[numtb].FaceTileMaterialRefCount++;
821 // The facelist is modified, so we must update the faceVector, if visible.
822 dirtTessBlockFaceVector(TessBlocks[numtb]);
824 // Must enlarge the BSphere of the tesblock!!
825 // We must do it on a per-face approach, because of tessblocks 's corners which are outside of tessblocks.
826 TessBlocks[numtb].extendSphereFirst(face->VBase->EndPos);
827 TessBlocks[numtb].extendSphereAdd(face->VLeft->EndPos);
828 TessBlocks[numtb].extendSphereAdd(face->VRight->EndPos);
829 // I think this should be done too on StartPos, for geomorph (rare??...) problems.
830 // \todo yoyo: is this necessary???
831 TessBlocks[numtb].extendSphereAdd(face->VBase->StartPos);
832 TessBlocks[numtb].extendSphereAdd(face->VLeft->StartPos);
833 TessBlocks[numtb].extendSphereAdd(face->VRight->StartPos);
834 TessBlocks[numtb].extendSphereCompile();
837 // Update Tile render (no need to do it if face not at least at tessblock level).
838 appendFaceToTileRenderList(face);
843 // ***************************************************************************
844 void CPatch::removeFaceFromRenderList(CTessFace *face)
846 // Update the number of renderable Faces
847 NumRenderableFaces--;
848 nlassert(NumRenderableFaces>=0);
850 // Update Gnal render.
851 //====================
852 if(face->Level<TessBlockLimitLevel)
854 MasterBlock.FarFaceList.remove(face);
855 MasterBlock.FaceTileMaterialRefCount--;
857 // The facelist is modified, so we must update the faceVector, if visible.
858 dirtTessBlockFaceVector(MasterBlock);
860 else
862 // link the face to the good tessblock.
863 uint numtb= getNumTessBlock(face);
864 TessBlocks[numtb].FarFaceList.remove(face);
865 TessBlocks[numtb].FaceTileMaterialRefCount--;
867 // The facelist is modified, so we must update the faceVector, if visible.
868 dirtTessBlockFaceVector(TessBlocks[numtb]);
870 // Update Tile render (no need to do it if face not at least at tessblock level).
871 removeFaceFromTileRenderList(face);
873 // Destroy if necessary the TessBlocks.
874 decRefTessBlocks();
879 // ***************************************************************************
880 void CPatch::appendFaceToTileRenderList(CTessFace *face)
882 if(face->TileMaterial)
884 // For all valid faces, update their links.
885 // Do not do this for lightmap, since it use same face from RGB0 pass.
886 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
888 CPatchRdrPass *tilePass= face->TileMaterial->Pass[i].PatchRdrPass;
889 // If tile i enabled.
890 if(tilePass)
892 // a face should have created for this pass.
893 nlassert(face->TileFaces[i]);
894 face->TileMaterial->TileFaceList[i].append(face->TileFaces[i]);
898 // The facelist is modified, so we must update the faceVector, if visible.
899 uint numtb= getNumTessBlock(face);
900 dirtTessBlockFaceVector(TessBlocks[numtb]);
902 // Shadow: append it to the Shadow Triangles.
903 getLandscape()->appendToShadowPolyReceiver(face);
908 // ***************************************************************************
909 void CPatch::removeFaceFromTileRenderList(CTessFace *face)
911 if(face->TileMaterial)
913 // For all valid faces, update their links.
914 // Do not do this for lightmap, since it use same face from RGB0 pass.
915 for(sint i=0;i<NL3D_MAX_TILE_FACE;i++)
917 CPatchRdrPass *tilePass= face->TileMaterial->Pass[i].PatchRdrPass;
918 // If tile i enabled.
919 if(tilePass)
921 // a face should have created for this pass.
922 nlassert(face->TileFaces[i]);
923 face->TileMaterial->TileFaceList[i].remove(face->TileFaces[i]);
927 // The facelist is modified, so we must update the faceVector, if visible.
928 uint numtb= getNumTessBlock(face);
929 dirtTessBlockFaceVector(TessBlocks[numtb]);
931 // Shadow: remove it from the Shadow Triangles.
932 getLandscape()->removeFromShadowPolyReceiver(face);
937 // ***************************************************************************
938 void CPatch::computeTbTm(uint &numtb, uint &numtm, uint ts, uint tt)
940 sint is= ts&1;
941 sint it= tt&1;
942 ts>>=1;
943 tt>>=1;
945 numtb= tt*(uint)(OrderS>>1) + ts;
946 numtm= it*2+is;
950 // ***************************************************************************
951 void CPatch::appendTileMaterialToRenderList(CTileMaterial *tm)
953 nlassert(tm);
955 // Alloc if necessary the TessBlocks.
956 addRefTessBlocks();
958 uint numtb, numtm;
959 computeTbTm(numtb, numtm, tm->TileS, tm->TileT);
960 TessBlocks[numtb].RdrTileRoot[numtm]= tm;
961 TessBlocks[numtb].FaceTileMaterialRefCount++;
962 TessBlocks[numtb].TileMaterialRefCount++;
963 // The master block contains the whole patch TileMaterialRefCount
964 MasterBlock.TileMaterialRefCount++;
966 // DynamicLighting. When in near, must compute the context, to have good UVs.
967 //==========
968 // inc ref to the context, creating it if needed.
969 addRefDLMContext();
970 // NB: do it before creating the vegetableBlock, because vegetables use DLM Uvs.
972 // if was no tiles before in this tessBlock, create a Vegetable block.
973 //==========
974 // one Tile <=> was 0 before
975 if( TessBlocks[numtb].TileMaterialRefCount == 1 && getLandscape()->isVegetableActive() )
977 createVegetableBlock(numtb, tm->TileS, tm->TileT);
979 const std::vector<ULandscapeTileCallback *> &tc = getLandscape()->getTileCallbacks();
980 if (!tc.empty())
982 CBezierPatch *bpatch= unpackIntoCache();
983 CTileAddedInfo tai;
985 tai.Corners[0] = bpatch->eval((float) tm->TileS / OrderS, (float) tm->TileT / OrderT);
986 tai.Corners[1] = bpatch->eval((tm-> TileS + 1.f) / OrderS, (float) tm->TileT / OrderT);
987 tai.Corners[2] = bpatch->eval( (tm-> TileS + 1.f) / OrderS, (tm->TileT + 1.f) / OrderT);
988 tai.Corners[3] = bpatch->eval( (float) tm-> TileS / OrderS, (tm->TileT + 1.f) / OrderT);
989 tai.Center = bpatch->eval( (tm-> TileS + 0.5f) / OrderS, (tm->TileT + 0.5f) / OrderT);
991 tai.Normal = bpatch->evalNormal( (tm-> TileS + 0.5f) / OrderS, (tm->TileT + 0.5f) / OrderT);
992 tai.TileID = (uint64) tm; // pointer to tile material serves as a unique identifier
994 for(std::vector<ULandscapeTileCallback *>::const_iterator it = tc.begin(); it != tc.end(); ++it)
996 (*it)->tileAdded(tai);
1000 // ***************************************************************************
1001 void CPatch::removeTileMaterialFromRenderList(CTileMaterial *tm)
1003 nlassert(tm);
1005 uint numtb, numtm;
1006 computeTbTm(numtb, numtm, tm->TileS, tm->TileT);
1007 TessBlocks[numtb].RdrTileRoot[numtm]= NULL;
1008 TessBlocks[numtb].FaceTileMaterialRefCount--;
1009 TessBlocks[numtb].TileMaterialRefCount--;
1010 // The master block contains the whole patch TileMaterialRefCount
1011 MasterBlock.TileMaterialRefCount--;
1013 // if no more tiles in this tessBlock, delete the vegetable Block.
1014 //==========
1015 // if no more tiles in this tessBlock
1016 if( TessBlocks[numtb].TileMaterialRefCount==0 )
1018 // release the vegetableBlock (if any)
1019 releaseVegetableBlock(numtb);
1022 // Destroy if necessary the TessBlocks.
1023 decRefTessBlocks();
1025 // DynamicLighting. When in near, must compute the context, to have good UVs.
1026 //==========
1027 // dec ref the context, deleting it if needed.
1028 decRefDLMContext();
1030 const std::vector<ULandscapeTileCallback *> &tc = getLandscape()->getTileCallbacks();
1031 if (!tc.empty())
1034 for(std::vector<ULandscapeTileCallback *>::const_iterator it = tc.begin(); it != tc.end(); ++it)
1036 (*it)->tileRemoved((uint64) tm); // pointer to tile material serves as a unique identifier
1042 // ***************************************************************************
1043 void CPatch::appendFarVertexToRenderList(CTessFarVertex *fv)
1045 TFarVertType type;
1046 uint numtb;
1047 getNumTessBlock(fv->PCoord, type, numtb);
1050 if(type==FVMasterBlock || type==FVTessBlockEdge)
1052 fv->OwnerBlock= &MasterBlock;
1053 MasterBlock.FarVertexList.append(fv);
1055 else
1057 // Alloc if necessary the TessBlocks.
1058 addRefTessBlocks();
1060 fv->OwnerBlock= &TessBlocks[numtb];
1061 TessBlocks[numtb].FarVertexList.append(fv);
1064 // ***************************************************************************
1065 void CPatch::removeFarVertexFromRenderList(CTessFarVertex *fv)
1067 TFarVertType type;
1068 uint numtb;
1069 getNumTessBlock(fv->PCoord, type, numtb);
1072 if(type==FVMasterBlock || type==FVTessBlockEdge)
1074 MasterBlock.FarVertexList.remove(fv);
1075 fv->OwnerBlock= NULL;
1077 else
1079 TessBlocks[numtb].FarVertexList.remove(fv);
1080 fv->OwnerBlock= NULL;
1082 // Destroy if necessary the TessBlocks.
1083 decRefTessBlocks();
1088 // ***************************************************************************
1089 void CPatch::appendNearVertexToRenderList(CTileMaterial *tileMat, CTessNearVertex *nv)
1091 nlassert(tileMat);
1093 // Alloc if necessary the TessBlocks.
1094 addRefTessBlocks();
1096 uint numtb, numtm;
1097 computeTbTm(numtb, numtm, tileMat->TileS, tileMat->TileT);
1098 nv->OwnerBlock= &TessBlocks[numtb];
1099 TessBlocks[numtb].NearVertexList.append(nv);
1101 // ***************************************************************************
1102 void CPatch::removeNearVertexFromRenderList(CTileMaterial *tileMat, CTessNearVertex *nv)
1104 nlassert(tileMat);
1106 uint numtb, numtm;
1107 computeTbTm(numtb, numtm, tileMat->TileS, tileMat->TileT);
1108 TessBlocks[numtb].NearVertexList.remove(nv);
1109 nv->OwnerBlock= NULL;
1111 // Destroy if necessary the TessBlocks.
1112 decRefTessBlocks();
1117 // ***************************************************************************
1118 // ***************************************************************************
1119 // BASIC BUILD.
1120 // ***************************************************************************
1121 // ***************************************************************************
1126 // ***************************************************************************
1127 void CPatch::makeRoots()
1129 CTessVertex *a= BaseVertices[0];
1130 CTessVertex *b= BaseVertices[1];
1131 CTessVertex *c= BaseVertices[2];
1132 CTessVertex *d= BaseVertices[3];
1134 // Set positions.
1135 a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
1136 b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
1137 c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
1138 d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
1140 // Init Far vetices.
1141 CTessFarVertex *fa= &BaseFarVertices[0];
1142 CTessFarVertex *fb= &BaseFarVertices[1];
1143 CTessFarVertex *fc= &BaseFarVertices[2];
1144 CTessFarVertex *fd= &BaseFarVertices[3];
1145 fa->Src= a;
1146 fa->PCoord.setST(0,0);
1147 fb->Src= b;
1148 fb->PCoord.setST(0,1);
1149 fc->Src= c;
1150 fc->PCoord.setST(1,1);
1151 fd->Src= d;
1152 fd->PCoord.setST(1,0);
1154 // We don't have to fill the Far vertices VB here, because this patch is still not visible.
1155 // NB: we can't because we don't have any driver here.
1156 nlassert(isRenderClipped()==true);
1159 // Make Roots.
1161 Tesselation layout. For Square Face, and if OrderS>=OrderT.
1163 A-------D
1164 |\ Son1 |
1165 | \ |
1166 | \ |
1167 | Son0 \|
1168 B-------C
1170 For rectangles whith OrderT>OrderS. It is VERY IMPORTANT, for splitRectangular() reasons.
1172 A-------D
1173 | Son0 /|
1174 | / |
1175 | / |
1176 |/ Son1 |
1177 B-------C
1180 nlassert(Son0==NULL);
1181 nlassert(Son1==NULL);
1182 Son0= getLandscape()->newTessFace();
1183 Son1= getLandscape()->newTessFace();
1185 // Son0.
1186 Son0->Patch= this;
1187 Son0->Level= 0;
1188 if(OrderS>=OrderT)
1190 Son0->VBase= b;
1191 Son0->VLeft= c;
1192 Son0->VRight= a;
1193 Son0->FVBase= fb;
1194 Son0->FVLeft= fc;
1195 Son0->FVRight= fa;
1196 Son0->PVBase.setST(0, 1);
1197 Son0->PVLeft.setST(1, 1);
1198 Son0->PVRight.setST(0, 0);
1200 else
1202 Son0->VBase= a;
1203 Son0->VLeft= b;
1204 Son0->VRight= d;
1205 Son0->FVBase= fa;
1206 Son0->FVLeft= fb;
1207 Son0->FVRight= fd;
1208 Son0->PVBase.setST(0, 0);
1209 Son0->PVLeft.setST(0, 1);
1210 Son0->PVRight.setST(1, 0);
1212 Son0->FBase= Son1;
1213 Son0->FLeft= NULL;
1214 Son0->FRight= NULL;
1215 // No tile info.
1216 Son0->Size= ErrorSize/2;
1217 Son0->computeSplitPoint();
1219 // Son1.
1220 Son1->Patch= this;
1221 Son1->Level= 0;
1222 if(OrderS>=OrderT)
1224 Son1->VBase= d;
1225 Son1->VLeft= a;
1226 Son1->VRight= c;
1227 Son1->FVBase= fd;
1228 Son1->FVLeft= fa;
1229 Son1->FVRight= fc;
1230 Son1->PVBase.setST(1, 0);
1231 Son1->PVLeft.setST(0, 0);
1232 Son1->PVRight.setST(1, 1);
1234 else
1236 Son1->VBase= c;
1237 Son1->VLeft= d;
1238 Son1->VRight= b;
1239 Son1->FVBase= fc;
1240 Son1->FVLeft= fd;
1241 Son1->FVRight= fb;
1242 Son1->PVBase.setST(1, 1);
1243 Son1->PVLeft.setST(1, 0);
1244 Son1->PVRight.setST(0, 1);
1246 Son1->FBase= Son0;
1247 Son1->FLeft= NULL;
1248 Son1->FRight= NULL;
1249 // No tile info.
1250 Son1->Size= ErrorSize/2;
1251 Son1->computeSplitPoint();
1254 // Prepare the render list...
1255 clearTessBlocks();
1256 resetMasterBlock();
1257 appendFarVertexToRenderList(fa);
1258 appendFarVertexToRenderList(fb);
1259 appendFarVertexToRenderList(fc);
1260 appendFarVertexToRenderList(fd);
1261 appendFaceToRenderList(Son0);
1262 appendFaceToRenderList(Son1);
1264 // Useful for geomorph: Init 2 root faces MaxNearLimit, and MaxFaceSize
1265 // NB: since no geomorph is made on endpoints (StartPos==EndPos) of patchs, this is not useful.
1266 // but it is important to ensure the VP or software geomorph won't crash with bad float values.
1267 // Init MaxFaceSize.
1268 Son0->VBase->MaxFaceSize= 1;
1269 Son0->VLeft->MaxFaceSize= 1;
1270 Son0->VRight->MaxFaceSize= 1;
1271 Son1->VBase->MaxFaceSize= 1;
1272 Son1->VLeft->MaxFaceSize= 1;
1273 Son1->VRight->MaxFaceSize= 1;
1274 // Init MaxNearLimit.
1275 Son0->VBase->MaxNearLimit= 1;
1276 Son0->VLeft->MaxNearLimit= 1;
1277 Son0->VRight->MaxNearLimit= 1;
1278 Son1->VBase->MaxNearLimit= 1;
1279 Son1->VLeft->MaxNearLimit= 1;
1280 Son1->VRight->MaxNearLimit= 1;
1285 // ***************************************************************************
1286 void CPatch::compile(CZone *z, uint patchId, uint8 orderS, uint8 orderT, CTessVertex *baseVertices[4], float errorSize)
1288 nlassert(z);
1289 Zone= z;
1291 // For updateLighting, get the correct pointer now.
1292 // Init UL circular list to me
1293 _ULNearPrec= this;
1294 _ULNearNext= this;
1297 // Once the patch is inserted and compiled in a zone, it is ready to be rendered.
1298 // init the MasterBlock.
1299 MasterBlock.init(this);
1301 // only 65536 patch per zone allowed.
1302 nlassert(patchId<0x10000);
1303 PatchId= (uint16)patchId;
1305 if(errorSize==0)
1306 computeDefaultErrorSize();
1307 else
1308 ErrorSize= errorSize;
1310 nlassert(orderS==2 || orderS==4 || orderS==8 || orderS==16);
1311 nlassert(orderT==2 || orderT==4 || orderT==8 || orderT==16);
1312 nlassert (OrderS==orderS);
1313 nlassert (OrderT==orderT);
1315 // Compile additional infos.
1316 sint ps= getPowerOf2(orderS) , pt= getPowerOf2(orderT);
1317 sint pmin= min(ps,pt);
1318 sint pmax= max(ps,pt);
1319 // Rectangular patch OK.
1320 // Work, since patch 1xX are illegal. => The TileLimitLevel is at least 2 level distant from the time where
1321 // the rectangular patch is said "un-rectangular-ed" (tesselation looks like square). Hence, there is no problem
1322 // with rectangular UV geomorph (well don't bother me, make a draw :) ).
1323 TileLimitLevel= pmin*2 + pmax-pmin;
1324 // A TessBlock is a 2*2 tile. This simple formula works because patch 1xX are illegal.
1325 TessBlockLimitLevel= TileLimitLevel-2;
1326 // This tell us when the tess face is "un-rectangular-ed" (to say a square). Before, it is a "rectangular" face,
1327 // which has a strange fxxxxxg split.
1328 // If patch is square, then SquareLimitLevel=0 (ok!!).
1329 SquareLimitLevel= pmax-pmin;
1331 // Bind vertices, to zone base vertices.
1332 BaseVertices[0]= baseVertices[0];
1333 BaseVertices[1]= baseVertices[1];
1334 BaseVertices[2]= baseVertices[2];
1335 BaseVertices[3]= baseVertices[3];
1337 // build Sons.
1338 makeRoots();
1340 // ***************************************************************************
1341 CVector CPatch::computeVertex(float s, float t) const
1343 // \todo yoyo: TODO_UVCORRECT: use UV correction.
1345 if(getLandscape()->getNoiseMode())
1347 // compute displacement map to disturb result.
1348 CVector displace;
1349 computeNoise(s,t, displace);
1351 // return patch(s,t) + dispalcement result.
1352 // unpack. Do it after computeNoise(), because this last may change the cache.
1353 CBezierPatch *patch= unpackIntoCache();
1354 return patch->eval(s,t) + displace;
1356 else
1358 // unpack and return patch(s,t).
1359 CBezierPatch *patch= unpackIntoCache();
1360 return patch->eval(s,t);
1365 // ***************************************************************************
1366 CVector CPatch::computeContinousVertex(float s, float t) const
1368 // must be compiled
1369 nlassert(Zone);
1371 // Test is on a edge/corner of the patch
1372 sint edgeIdS= -1;
1373 sint edgeIdT= -1;
1374 if(s==0) edgeIdS= 0;
1375 else if(s==1) edgeIdS= 2;
1376 if(t==0) edgeIdT= 3;
1377 else if(t==1) edgeIdT= 1;
1379 // test if on a corner
1380 if(edgeIdS>=0 && edgeIdT>=0)
1382 // return the baseVertex according to edge falgs
1383 if(edgeIdS==0 && edgeIdT==3) return BaseVertices[0]->EndPos;
1384 if(edgeIdS==0 && edgeIdT==1) return BaseVertices[1]->EndPos;
1385 if(edgeIdS==2 && edgeIdT==1) return BaseVertices[2]->EndPos;
1386 if(edgeIdS==2 && edgeIdT==3) return BaseVertices[3]->EndPos;
1387 nlstop;
1388 // Error, but Avoid warning
1389 return CVector::Null;
1391 // test if on an edge
1392 else if(edgeIdS>=0 || edgeIdT>=0)
1394 // Yes, must compute myslef
1395 CVector vertexOnMe= computeVertex(s,t);
1397 // Then, must compute my neighbor.
1398 sint edgeId;
1399 if(edgeIdS>=0)
1400 edgeId= edgeIdS;
1401 else
1402 edgeId= edgeIdT;
1404 // Get my neighbor, if any.
1405 CBindInfo bindInfo;
1406 getBindNeighbor(edgeId, bindInfo);
1407 // Fast reject: if no neighbor on the edge, just return my pos.
1408 if(!bindInfo.Zone)
1410 return vertexOnMe;
1412 // else must get vertex pos of my neighbor, and average.
1413 else
1415 // use a CPatchUVLocator to get UV in neighbor patch
1416 CPatchUVLocator uvLocator;
1417 uvLocator.build(this, edgeId, bindInfo);
1419 // UVlocator use OrderS/OrderT coordinate system.
1420 CVector2f stTileIn, stTileOut;
1421 stTileIn.x= s * getOrderS();
1422 stTileIn.y= t * getOrderT();
1424 // transform coordinate to get into the neigbhor patch
1425 uint pid= uvLocator.selectPatch(stTileIn);
1426 CPatch *nebPatch;
1427 uvLocator.locateUV(stTileIn, pid, nebPatch, stTileOut);
1429 // transform neigbhor coord in 0..1 coordinate space.
1430 stTileOut.x/= nebPatch->getOrderS();
1431 stTileOut.y/= nebPatch->getOrderT();
1433 // and compute vertex. NB: if binded on 2 or 4 patch, it is then possible that stTileOut is on a
1434 // a corner ( (0,0), (0,1) ...).
1435 // In this case, we must use the precomputed Vertex pos, for completeness.
1436 bool onCorner;
1437 CVector vertexOnNeb= nebPatch->computeVertexButCorner(stTileOut.x, stTileOut.y, onCorner);
1439 // If the neighbor is on a corner, then use its corner value.
1440 if(onCorner)
1441 return vertexOnNeb;
1442 else
1444 // Average the 2 and return this result.
1445 vertexOnMe+= vertexOnNeb;
1446 vertexOnMe/= 2;
1447 return vertexOnMe;
1452 // else, std case
1453 else
1454 return computeVertex(s, t);
1458 // ***************************************************************************
1459 CVector CPatch::computeVertexButCorner(float s, float t, bool &onCorner) const
1461 // must be compiled
1462 nlassert(Zone);
1464 // Test is on a edge/corner of the patch
1465 sint edgeIdS= -1;
1466 sint edgeIdT= -1;
1467 if(s==0) edgeIdS= 0;
1468 else if(s==1) edgeIdS= 2;
1469 if(t==0) edgeIdT= 3;
1470 else if(t==1) edgeIdT= 1;
1472 // test if on a corner
1473 if(edgeIdS>=0 && edgeIdT>=0)
1475 // indicate that yes, we are on a corner
1476 onCorner= true;
1477 // return the baseVertex according to edge falgs
1478 if(edgeIdS==0 && edgeIdT==3) return BaseVertices[0]->EndPos;
1479 if(edgeIdS==0 && edgeIdT==1) return BaseVertices[1]->EndPos;
1480 if(edgeIdS==2 && edgeIdT==1) return BaseVertices[2]->EndPos;
1481 if(edgeIdS==2 && edgeIdT==3) return BaseVertices[3]->EndPos;
1482 nlstop;
1483 // Error, but Avoid warning
1484 return CVector::Null;
1486 // else, std case
1487 else
1489 onCorner= false;
1490 return computeVertex(s, t);
1495 // ***************************************************************************
1496 void CPatch::refineAll()
1498 // refineAll.
1499 nlassert(Son0);
1500 nlassert(Son1);
1501 Son0->refineAll();
1502 Son1->refineAll();
1507 // ***************************************************************************
1508 void CPatch::averageTesselationVertices()
1510 nlassert(Son0);
1511 nlassert(Son1);
1513 // Recompute the BaseVertices. This is useful for Pacs.
1514 // Because CLandscape::averageTesselationVertices() is made on a strict order for patchs (map of zones, then
1515 // array of patchs), we are sure to overwrite BaseVertices in this order.
1516 CTessVertex *a= BaseVertices[0];
1517 CTessVertex *b= BaseVertices[1];
1518 CTessVertex *c= BaseVertices[2];
1519 CTessVertex *d= BaseVertices[3];
1520 // Set positions.
1521 a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
1522 b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
1523 c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
1524 d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
1527 // Average the tesselation of sons.
1528 Son0->averageTesselationVertices();
1529 Son1->averageTesselationVertices();
1533 // ***************************************************************************
1534 void CPatch::refreshTesselationGeometry()
1536 nlassert(Son0);
1537 nlassert(Son1);
1539 // Recompute the BaseVertices.
1540 CTessVertex *a= BaseVertices[0];
1541 CTessVertex *b= BaseVertices[1];
1542 CTessVertex *c= BaseVertices[2];
1543 CTessVertex *d= BaseVertices[3];
1544 // Set positions.
1545 a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
1546 b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
1547 c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
1548 d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
1551 // refresh the tesselation of sons.
1552 Son0->refreshTesselationGeometry();
1553 Son1->refreshTesselationGeometry();
1557 // ***************************************************************************
1558 void CPatch::resetRenderFar()
1560 if (_PatchRdrPassFar0)
1562 // free the render pass.
1563 Zone->Landscape->freeFarRenderPass (this, _PatchRdrPassFar0, Far0);
1564 _PatchRdrPassFar0= NULL;
1566 if (_PatchRdrPassFar1)
1568 // free the render pass.
1569 Zone->Landscape->freeFarRenderPass (this, _PatchRdrPassFar1, Far1);
1570 _PatchRdrPassFar1= NULL;
1573 Far0= -1;
1574 Far1= -1;
1578 // ***************************************************************************
1579 void CPatch::serial(NLMISC::IStream &f)
1582 Version 7:
1583 - remove unused information from CTileColor. just keep 565 color
1584 Version 6:
1585 - default UnderWater flags for tileElements before version 6.
1586 Version 5:
1587 - TileLightInfluences serialized.
1588 Version 4:
1589 - Smooth flag serialized
1590 Version 3:
1591 - NoiseRotation.
1592 - NoiseSmooth.
1593 Version 2:
1594 - Lumels.
1595 Version 1:
1596 - Tile color.
1597 Version 0:
1598 - base version.
1600 uint ver= f.serialVersion(_Version);
1602 // No more compatibility before version 2, because OrderS / OrderT not serialized in preceding version
1603 // Doens't matter since CZone::serial() do not support it too.
1604 if (ver<2)
1606 throw EOlderStream(f);
1609 f.xmlSerial (Vertices[0], Vertices[1], Vertices[2], Vertices[3], "VERTICIES");
1611 f.xmlPush ("TANGENTS");
1612 f.serial (Tangents[0], Tangents[1], Tangents[2], Tangents[3]);
1613 f.serial (Tangents[4], Tangents[5], Tangents[6], Tangents[7]);
1614 f.xmlPop ();
1616 f.xmlSerial (Interiors[0], Interiors[1], Interiors[2], Interiors[3], "INTERIORS");
1618 f.xmlPush ("TILES");
1619 f.serialCont(Tiles);
1620 f.xmlPop ();
1622 if(ver>=1)
1624 // Read/Write TileColors.
1625 if(ver<=6)
1627 nlassert(f.isReading());
1629 // read old version of tilesColors (ie with LightX/LightY/LightZ, which are deprecated now)
1630 vector<CTileColorOldPatchVersion6> tmpArray;
1631 f.xmlPush ("TILE_COLORS");
1632 f.serialCont(tmpArray);
1633 f.xmlPop ();
1635 // then just copy to TileColors.
1636 TileColors.resize(tmpArray.size());
1637 if(!TileColors.empty())
1639 memcpy(&TileColors[0], &tmpArray[0], TileColors.size()*sizeof(CTileColor));
1642 else
1644 // version >=7, just serial array of TileColors (16 bits TileColor only)
1645 f.xmlPush ("TILE_COLORS");
1646 f.serialCont(TileColors);
1647 #ifdef NEL_FORCE_NO_USER_COLOR
1648 CTileColor color;
1649 color.Color565 = 0xffff;
1650 uint size = TileColors.size ();
1651 TileColors.resize (0);
1652 TileColors.resize (size, color);
1653 #endif // NEL_FORCE_NO_USER_COLOR
1654 f.xmlPop ();
1657 if(ver>=2)
1659 f.xmlSerial (OrderS, "ORDER_S");
1660 f.xmlSerial (OrderT, "ORDER_T");
1662 f.xmlPush ("COMPRESSED_LUMELS");
1663 f.serialCont(CompressedLumels);
1664 f.xmlPop ();
1666 // Else cannot create here the TileColors, because we need the OrderS/OrderT information... Done into CZone serial.
1667 if(ver>=3)
1669 f.xmlSerial (NoiseRotation, "NOISE_ROTATION");
1670 f.xmlSerial (_CornerSmoothFlag, "CORNER_SMOOTH_FLAG");
1672 else
1674 // No Rotation / not smooth by default.
1675 NoiseRotation= 0;
1676 _CornerSmoothFlag= 0;
1678 if(ver>=4)
1680 f.xmlSerial(Flags, "FLAGS");
1682 else
1684 Flags=NL_PATCH_SMOOTH_FLAG_MASK;
1687 // Serialize TileLightInfluences
1688 if(ver>=5)
1690 f.xmlPush ("TILE_LIGHT_INFLUENCES");
1691 f.serialCont(TileLightInfluences);
1692 f.xmlPop ();
1694 else
1696 if(f.isReading())
1698 // Fill default.
1699 resetTileLightInfluences();
1703 // if read a too old version,
1704 if(ver<6 && f.isReading())
1706 // reset tileElements vegetableState to AboveWater.
1707 for(uint i=0; i<Tiles.size(); i++)
1709 Tiles[i].setVegetableState(CTileElement::AboveWater);
1718 // ***************************************************************************
1719 // ***************************************************************************
1720 // Bind / UnBind.
1721 // ***************************************************************************
1722 // ***************************************************************************
1726 // ***************************************************************************
1727 void CPatch::unbind()
1729 nlassert(Son0 && Son1);
1731 Son0->unbind();
1732 Son1->unbind();
1733 Son0->forceMerge();
1734 Son1->forceMerge();
1735 // forcemerge should have be completed.
1736 nlassert(Son0->isLeaf() && Son1->isLeaf());
1737 // unbind should have be completed.
1738 nlassert(Son0->FLeft == NULL);
1739 nlassert(Son0->FRight == NULL);
1740 nlassert(Son1->FLeft == NULL);
1741 nlassert(Son1->FRight == NULL);
1744 // unbind Noise.
1745 _BindZoneNeighbor[0]= NULL;
1746 _BindZoneNeighbor[1]= NULL;
1747 _BindZoneNeighbor[2]= NULL;
1748 _BindZoneNeighbor[3]= NULL;
1753 // ***************************************************************************
1754 CTessFace *CPatch::getRootFaceForEdge(sint edge) const
1756 nlassert(edge>=0 && edge<=3);
1758 // See tessellation rules.
1759 if(OrderS>=OrderT)
1761 if(edge==0 || edge==1)
1762 return Son0;
1763 else
1764 return Son1;
1766 else
1768 if(edge==0 || edge==3)
1769 return Son0;
1770 else
1771 return Son1;
1775 // ***************************************************************************
1776 CTessVertex *CPatch::getRootVertexForEdge(sint edge) const
1778 // Return the vertex which is the start of edge.
1779 nlassert(edge>=0 && edge<=3);
1781 // See tessellation rules.
1782 if(OrderS>=OrderT)
1784 switch(edge)
1786 case 0: return Son0->VRight;
1787 case 1: return Son0->VBase;
1788 case 2: return Son0->VLeft;
1789 case 3: return Son1->VBase;
1790 default: return NULL;
1793 else
1795 switch(edge)
1797 case 0: return Son0->VBase;
1798 case 1: return Son0->VLeft;
1799 case 2: return Son1->VBase;
1800 case 3: return Son0->VRight;
1801 default: return NULL;
1807 // ***************************************************************************
1808 void CPatch::changeEdgeNeighbor(sint edge, CTessFace *to)
1810 nlassert(edge>=0 && edge<=3);
1812 // See tessellation rules.
1813 if(OrderS>=OrderT)
1815 switch(edge)
1817 case 0: Son0->FRight= to; break;
1818 case 1: Son0->FLeft= to; break;
1819 case 2: Son1->FRight= to; break;
1820 case 3: Son1->FLeft= to; break;
1823 else
1825 switch(edge)
1827 case 0: Son0->FLeft= to; break;
1828 case 1: Son1->FRight= to; break;
1829 case 2: Son1->FLeft= to; break;
1830 case 3: Son0->FRight= to; break;
1836 // ***************************************************************************
1837 CTessFace *CPatch::linkTessFaceWithEdge(const CVector2f &uv0, const CVector2f &uv1, CTessFace *linkTo)
1839 nlassert(Son0 && Son1);
1840 // Try to link with Root Son0
1841 CTessFace *face= Son0->linkTessFaceWithEdge(uv0, uv1, linkTo);
1842 // if Failed Try to link with Root Son1
1843 if(!face)
1844 face= Son1->linkTessFaceWithEdge(uv0, uv1, linkTo);
1845 return face;
1849 // ***************************************************************************
1850 void CPatch::bind(CBindInfo Edges[4], bool rebind)
1852 // The multiple Patch Face.
1853 // By default, Patch==NULL, FLeft, FRight and FBase==NULL so ok!
1854 static CTessFace bind1_2[4];
1855 static CTessFace bind1_4[8];
1858 // THIS PATCH MUST BE UNBOUND FIRST!!!!!
1859 nlassert(Son0 && Son1);
1860 nlassert(Son0->isLeaf() && Son1->isLeaf());
1861 nlassert(Son0->FLeft == NULL);
1862 nlassert(Son0->FRight == NULL);
1863 nlassert(Son1->FLeft == NULL);
1864 nlassert(Son1->FRight == NULL);
1867 // bind the Realtime bind info here (before any computeVertex, and before bind too).
1868 sint i;
1869 for(i=0;i<4;i++)
1871 // just Copy zone (if not NULL).
1872 _BindZoneNeighbor[i]= Edges[i].Zone;
1876 if(!rebind)
1878 // Just recompute base vertices.
1879 CTessVertex *a= BaseVertices[0];
1880 CTessVertex *b= BaseVertices[1];
1881 CTessVertex *c= BaseVertices[2];
1882 CTessVertex *d= BaseVertices[3];
1883 // Set positions.
1884 a->Pos= a->StartPos= a->EndPos= computeVertex(0,0);
1885 b->Pos= b->StartPos= b->EndPos= computeVertex(0,1);
1886 c->Pos= c->StartPos= c->EndPos= computeVertex(1,1);
1887 d->Pos= d->StartPos= d->EndPos= computeVertex(1,0);
1888 // NB: no propagation problem, since the patch has root only (since has to be unbound!!!)
1889 // Recompute centers.
1890 Son0->computeSplitPoint();
1891 Son1->computeSplitPoint();
1893 else
1895 // Keep old Vertices as computed from neighbors, but reFill the 4 FarVertices.
1896 // NB: don't do it on NearVertices because suppose that Near is Off when a bind occurs (often far away).
1897 checkFillVertexVBFar(Son0->FVBase);
1898 checkFillVertexVBFar(Son0->FVLeft);
1899 checkFillVertexVBFar(Son0->FVRight);
1900 checkFillVertexVBFar(Son1->FVBase);
1904 // Bind the roots.
1905 for(i=0;i<4;i++)
1907 CBindInfo &bind= Edges[i];
1909 nlassert(bind.NPatchs==0 || bind.NPatchs==1 || bind.NPatchs==2 || bind.NPatchs==4 || bind.NPatchs==5);
1910 if(bind.NPatchs==1)
1912 // Bind me on Next.
1913 this->changeEdgeNeighbor(i, bind.Next[0]->getRootFaceForEdge(bind.Edge[0]));
1914 // Bind Next on me.
1915 bind.Next[0]->changeEdgeNeighbor(bind.Edge[0], this->getRootFaceForEdge(i));
1917 else if(bind.NPatchs==2)
1919 // Setup multiple bind.
1920 this->changeEdgeNeighbor(i, bind1_2+i);
1921 bind1_2[i].FBase= this->getRootFaceForEdge(i);
1922 // Setup the multiple face.
1923 // Follow the conventions! Make a draw for understand. Small Patchs are numbered in CCW.
1924 bind1_2[i].SonRight= bind.Next[0]->getRootFaceForEdge(bind.Edge[0]);
1925 bind1_2[i].SonLeft= bind.Next[1]->getRootFaceForEdge(bind.Edge[1]);
1926 bind1_2[i].VBase= bind.Next[0]->getRootVertexForEdge(bind.Edge[0]);
1927 // Set a "flag" to neighbors, so they know what edge is to be bind on me.
1928 bind.Next[0]->changeEdgeNeighbor(bind.Edge[0], &CTessFace::MultipleBindFace);
1929 bind.Next[1]->changeEdgeNeighbor(bind.Edge[1], &CTessFace::MultipleBindFace);
1931 else if(bind.NPatchs==4)
1933 // Setup multiple bind level 0.
1934 this->changeEdgeNeighbor(i, bind1_2+i);
1935 bind1_2[i].FBase= this->getRootFaceForEdge(i);
1937 // Setup multiple bind level 1.
1938 // Follow the conventions! Make a draw for understand. Small Patchs are numbered in CCW.
1939 bind1_2[i].SonRight= bind1_4 + 2*i+0;
1940 bind1_2[i].SonLeft= bind1_4 + 2*i+1;
1941 bind1_2[i].VBase= bind.Next[1]->getRootVertexForEdge(bind.Edge[1]);
1942 // Make first multiple face bind level1.
1943 bind1_4[2*i+0].FBase= &CTessFace::MultipleBindFace; // to link correctly when the root face will be splitted.
1944 bind1_4[2*i+0].SonRight= bind.Next[0]->getRootFaceForEdge(bind.Edge[0]);
1945 bind1_4[2*i+0].SonLeft= bind.Next[1]->getRootFaceForEdge(bind.Edge[1]);
1946 bind1_4[2*i+0].VBase= bind.Next[0]->getRootVertexForEdge(bind.Edge[0]);
1947 // Make second multiple face bind level1.
1948 bind1_4[2*i+1].FBase= &CTessFace::MultipleBindFace; // to link correctly when the root face will be splitted.
1949 bind1_4[2*i+1].SonRight= bind.Next[2]->getRootFaceForEdge(bind.Edge[2]);
1950 bind1_4[2*i+1].SonLeft= bind.Next[3]->getRootFaceForEdge(bind.Edge[3]);
1951 bind1_4[2*i+1].VBase= bind.Next[2]->getRootVertexForEdge(bind.Edge[2]);
1953 // Set a "flag" to neighbors, so they know what edge is to be bind on me.
1954 bind.Next[0]->changeEdgeNeighbor(bind.Edge[0], &CTessFace::MultipleBindFace);
1955 bind.Next[1]->changeEdgeNeighbor(bind.Edge[1], &CTessFace::MultipleBindFace);
1956 bind.Next[2]->changeEdgeNeighbor(bind.Edge[2], &CTessFace::MultipleBindFace);
1957 bind.Next[3]->changeEdgeNeighbor(bind.Edge[3], &CTessFace::MultipleBindFace);
1959 else if(bind.NPatchs==5)
1961 /* I am binded to a bigger patch. There is 2 cases:
1962 - rebind=false. This is an original Bind of all patch of a zone.
1963 If my bigger patch has not be bound, I CANNOT do rebind faces, since my bigger neighbor patch is not
1964 correctly tesselated.
1965 Wait for the BiggerPatch do the correct bind (see above)
1966 - rebind=true. This is possible for a patch in border of zone to have some bind 1/X (even if Bind 1/X
1967 is not possible across zone, it IS possible that a patch containing a bind 1/X NOT ON EDGE OF ZONE
1968 exist (and they do exist...))
1970 If neighbor bind has been done (must be the case for rebind), MUST do the rebind
1971 (because of CZoneBindPatch() which first unbind() this, then bind())
1973 // if rebind, my neigbhor bind should be done
1974 if(rebind==true)
1976 nlassert(bind.Next[0]->_BindZoneNeighbor[bind.Edge[0]]);
1978 // if my neighbor is bound, i have to do the bind (since CZoneBindPatch() had call unbind)
1979 if(bind.Next[0]->_BindZoneNeighbor[bind.Edge[0]])
1981 // First, make the link with the face to which I must connect.
1982 // -----------------
1984 // Get the coordinate of the current edge of this patch
1985 CVector2f uvi0, uvi1;
1986 switch(i)
1988 case 0: uvi0.set(0,0); uvi1.set(0,1); break;
1989 case 1: uvi0.set(0,1); uvi1.set(1,1); break;
1990 case 2: uvi0.set(1,1); uvi1.set(1,0); break;
1991 case 3: uvi0.set(1,0); uvi1.set(0,0); break;
1993 // mul by OrderS/OrderT for CPatchUVLocator
1994 uvi0.x*= OrderS;
1995 uvi0.y*= OrderT;
1996 uvi1.x*= OrderS;
1997 uvi1.y*= OrderT;
1998 // build a CPatchUVLocator to transpose coorindate ot this edge in coordinate on the bigger Neighbor patch.
1999 CBindInfo bindInfo;
2000 getBindNeighbor(i, bindInfo);
2001 nlassert(bindInfo.Zone!=NULL && bindInfo.NPatchs==1);
2002 CPatchUVLocator puvloc;
2003 puvloc.build(this, i, bindInfo);
2005 // transpose from this patch coord in neighbor patch coord.
2006 CVector2f uvo0, uvo1;
2007 uint pid;
2008 CPatch *patchNeighbor;
2009 // Do it for uvi0
2010 pid= puvloc.selectPatch(uvi0);
2011 puvloc.locateUV(uvi0, pid, patchNeighbor, uvo0);
2012 nlassert(patchNeighbor == bindInfo.Next[0]);
2013 // Do it for uvi1
2014 pid= puvloc.selectPatch(uvi1);
2015 puvloc.locateUV(uvi1, pid, patchNeighbor, uvo1);
2016 nlassert(patchNeighbor == bindInfo.Next[0]);
2017 // Rescale to have uv in 0,1 basis.
2018 uvo0.x/= patchNeighbor->OrderS;
2019 uvo0.y/= patchNeighbor->OrderT;
2020 uvo1.x/= patchNeighbor->OrderS;
2021 uvo1.y/= patchNeighbor->OrderT;
2023 // Now, traverse the tesselation and find the first CTessFace which use this edge.
2024 CTessFace *faceNeighbor;
2025 faceNeighbor= patchNeighbor->linkTessFaceWithEdge(uvo0, uvo1, this->getRootFaceForEdge(i));
2026 nlassert(faceNeighbor);
2027 // Bind me on Next.
2028 this->changeEdgeNeighbor(i, faceNeighbor);
2034 // Propagate the binds to sons.
2035 Son0->updateBind();
2036 Son1->updateBind();
2041 // ***************************************************************************
2042 void CPatch::forceMergeAtTileLevel()
2044 nlassert(Son0 && Son1);
2046 Son0->forceMergeAtTileLevel();
2047 Son1->forceMergeAtTileLevel();
2052 // ***************************************************************************
2053 // ***************************************************************************
2054 // Texturing.
2055 // ***************************************************************************
2056 // ***************************************************************************
2059 // ***************************************************************************
2060 CPatchRdrPass *CPatch::getTileRenderPass(sint tileId, sint pass)
2062 // All but lightmap.
2063 nlassert(pass==NL3D_TILE_PASS_RGB0 || pass==NL3D_TILE_PASS_RGB1 || pass==NL3D_TILE_PASS_RGB2 ||
2064 pass==NL3D_TILE_PASS_ADD);
2066 bool additive= (pass==NL3D_TILE_PASS_ADD);
2067 sint passNum= pass-NL3D_TILE_PASS_RGB0;
2068 // If additive, take the additve tile of bigger existing pass.
2069 if(additive)
2071 // Default: take addtive of pass 0.
2072 passNum= 0;
2073 // If the pass1 is not empty, may take its tile.
2074 if(Tiles[tileId].Tile[1]!=0xFFFF)
2076 passNum= 1;
2077 // If the pass2 is not empty, take its tile.
2078 if(Tiles[tileId].Tile[2]!=0xFFFF)
2079 passNum= 2;
2083 sint tileNumber= Tiles[tileId].Tile[passNum];
2084 if(tileNumber==0xFFFF)
2086 // Display a "fake" only if pass 0.
2087 if(pass==NL3D_TILE_PASS_RGB0)
2088 return Zone->Landscape->getTileRenderPass(0xFFFF, false);
2089 // Else, this tile do not have such a pass (not a transition).
2090 return NULL;
2092 else
2094 // return still may be NULL, in additive case.
2095 return Zone->Landscape->getTileRenderPass(uint16(tileNumber), additive);
2099 // ***************************************************************************
2100 void CPatch::getTileUvInfo(sint tileId, sint pass, bool alpha, uint8 &orient, CVector &uvScaleBias, bool &is256x256, uint8 &uvOff)
2102 // All but lightmap.
2103 nlassert(pass==NL3D_TILE_PASS_RGB0 || pass==NL3D_TILE_PASS_RGB1 || pass==NL3D_TILE_PASS_RGB2 ||
2104 pass==NL3D_TILE_PASS_ADD);
2106 bool additive= (pass==NL3D_TILE_PASS_ADD);
2107 sint passNum= pass-NL3D_TILE_PASS_RGB0;
2108 // If additive, take the additve tile of bigger existing pass.
2109 if(additive)
2111 // Default: take addtive of pass 0.
2112 passNum= 0;
2113 // If the pass1 is not empty, may take its tile.
2114 if(Tiles[tileId].Tile[1]!=0xFFFF)
2116 passNum= 1;
2117 // If the pass2 is not empty, take its tile.
2118 if(Tiles[tileId].Tile[2]!=0xFFFF)
2119 passNum= 2;
2123 sint tileNumber= Tiles[tileId].Tile[passNum];
2124 if(tileNumber==0xFFFF)
2126 // dummy... Should not be called here.
2127 orient= 0;
2128 uvScaleBias.x=0;
2129 uvScaleBias.y=0;
2130 uvScaleBias.z=1;
2131 is256x256=false;
2132 uvOff=0;
2134 else
2136 orient= Tiles[tileId].getTileOrient(passNum);
2137 Tiles[tileId].getTile256Info(is256x256, uvOff);
2138 CTile::TBitmap type;
2139 // If alpha wanted, return its UV info (works either for Alpha in Diffuse Pass and Alpha in Additive Pass)
2140 if(alpha)
2141 type= CTile::alpha;
2142 else
2144 if(additive)
2145 type= CTile::additive;
2146 else
2147 type= CTile::diffuse;
2150 uint8 rotalpha;
2151 Zone->Landscape->getTileUvScaleBiasRot(uint16(tileNumber), type, uvScaleBias, rotalpha);
2153 // Add the special rotation of alpha.
2154 if(alpha)
2155 orient= (orient+rotalpha)&3;
2161 // ***************************************************************************
2162 void CPatch::deleteTileUvs()
2164 Son0->deleteTileUvs();
2165 Son1->deleteTileUvs();
2169 // ***************************************************************************
2170 void CPatch::recreateTileUvs()
2172 // Reset the Tile rdr list.
2173 for(sint tb=0; tb<(sint)TessBlocks.size();tb++)
2175 // Vertices must all be reseted.
2176 TessBlocks[tb].NearVertexList.clear();
2177 for(sint i=0;i<NL3D_TESSBLOCK_TILESIZE;i++)
2179 CTileMaterial *tm= TessBlocks[tb].RdrTileRoot[i];
2180 if(tm)
2182 for(sint pass=0;pass<NL3D_MAX_TILE_FACE;pass++)
2184 tm->TileFaceList[pass].clear();
2190 Son0->recreateTileUvs();
2191 Son1->recreateTileUvs();
2195 // ***************************************************************************
2196 void CPatch::appendTessellationLeaves(std::vector<const CTessFace*> &leaves) const
2198 nlassert(Son0);
2199 nlassert(Son1);
2200 Son0->appendTessellationLeaves(leaves);
2201 Son1->appendTessellationLeaves(leaves);
2205 // ***************************************************************************
2206 CLandscape *CPatch::getLandscape () const
2208 return Zone->getLandscape();
2215 // ***************************************************************************
2216 uint8 CPatch::getOrderForEdge(sint8 edge) const
2218 uint e= ((sint)edge + 256)&3;
2219 // If an horizontal edge.
2220 if( e&1 ) return OrderS;
2221 else return OrderT;
2225 // ***************************************************************************
2226 // ***************************************************************************
2227 // Realtime Bind info.
2228 // ***************************************************************************
2229 // ***************************************************************************
2232 // ***************************************************************************
2233 void CPatch::getBindNeighbor(uint edge, CBindInfo &neighborEdge) const
2235 nlassert(edge<4);
2237 if(_BindZoneNeighbor[edge]!=NULL)
2239 getZone()->buildBindInfo(PatchId, edge, _BindZoneNeighbor[edge], neighborEdge);
2241 else
2243 neighborEdge.Zone= NULL;
2244 neighborEdge.NPatchs= 0;
2245 neighborEdge.MultipleBindNum= 0;
2249 // ***************************************************************************
2250 /// debug coloring
2251 void CPatch::setupColorsFromTileFlags(const NLMISC::CRGBA colors[4])
2253 for (uint s = 0; s <= OrderS; ++s)
2255 for (uint t = 0; t <= OrderT; ++t)
2257 uint index = std::min(t, (uint) (OrderT - 1)) * OrderS
2258 + std::min(s, (uint) (OrderS - 1));
2259 TileColors[s + t * (OrderS + 1)].Color565 = colors[(uint) (Tiles[index].getVegetableState())].get565();
2264 // ***************************************************************************
2265 void CPatch::copyTileFlagsFromPatch(const CPatch *src)
2267 nlassert(OrderS == src->OrderS
2268 && OrderT == src->OrderT);
2270 for (uint k = 0; k < Tiles.size(); ++k)
2272 Tiles[k].copyFlagsFromOther(src->Tiles[k]);
2277 // ***************************************************************************
2278 // ***************************************************************************
2279 // Tiles get interface.
2280 // ***************************************************************************
2281 // ***************************************************************************
2284 // ***************************************************************************
2285 CTileElement *CPatch::getTileElement(const CUV &uv)
2287 // compute tile coord and lumel coord.
2288 sint ts, tt;
2290 // fastFloor: use a precision of 256 to avoid doing OptFastFloorBegin.
2291 // add 128, to round and get cneter of lumel.
2292 ts= NLMISC::OptFastFloor(uv.U* (OrderS<<8) + 128); ts>>=8;
2293 tt= NLMISC::OptFastFloor(uv.V* (OrderT<<8) + 128); tt>>=8;
2294 clamp(ts, 0, OrderS-1);
2295 clamp(tt, 0, OrderT-1);
2297 // get the lumel
2298 return &(Tiles[ts+tt*OrderS]);
2301 // ***************************************************************
2302 uint32 CPatch::countNumTriFar0() const
2304 uint32 numIndex = MasterBlock.Far0FaceVector ? *MasterBlock.Far0FaceVector : 0;
2305 uint nTessBlock= TessBlocks.size();
2306 const CTessBlock *pTessBlock= nTessBlock>0? &TessBlocks[0]: NULL;
2307 for(; nTessBlock>0; pTessBlock++, nTessBlock--)
2309 const CTessBlock &tblock= *pTessBlock;
2310 // if block visible, render
2311 if( tblock.visibleFar0() )
2313 numIndex += *(tblock.Far0FaceVector);
2316 return numIndex;
2319 // ***************************************************************
2320 uint32 CPatch::countNumTriFar1() const
2322 uint32 numIndex = MasterBlock.Far1FaceVector ? *MasterBlock.Far1FaceVector : 0;
2323 uint nTessBlock= TessBlocks.size();
2324 const CTessBlock *pTessBlock= nTessBlock>0? &TessBlocks[0]: NULL;
2325 for(; nTessBlock>0; pTessBlock++, nTessBlock--)
2327 const CTessBlock &tblock= *pTessBlock;
2328 // if block visible, render
2329 if( tblock.visibleFar1() )
2331 numIndex += *(tblock.Far1FaceVector);
2334 return numIndex;
2341 } // NL3D