1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
36 using namespace NLMISC
;
38 // Define this to remove user color (debug)
39 // #define NEL_FORCE_NO_USER_COLOR
49 // ***************************************************************************
50 CBezierPatch
CPatch::CachePatch
;
51 const CPatch
*CPatch::LastPatch
= NULL
;
52 uint32
CPatch::_Version
=7;
55 // ***************************************************************************
64 NumRenderableFaces
= 0;
66 // for Pacs process. By default, false.
67 ExcludeFromRefineAll
= false;
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().
77 // Default: not binded.
78 _BindZoneNeighbor
[0]= NULL
;
79 _BindZoneNeighbor
[1]= NULL
;
80 _BindZoneNeighbor
[2]= NULL
;
81 _BindZoneNeighbor
[3]= NULL
;
83 // No smooth by default.
86 // MasterBlock never clipped.
87 MasterBlock
.resetClip();
89 // Init UL circular list to NULL (not compiled)
95 _DLMContextRefCount
= 0;
98 _PatchRdrPassFar0
= NULL
;
100 _PatchRdrPassFar1
= NULL
;
103 // ***************************************************************************
109 // ***************************************************************************
110 void CPatch::release()
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...
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.
147 // Flag RenderClipped in 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
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);
167 // DynamciLightMap: release the _DLMContext if still exist.
172 _DLMContextRefCount
= 0;
176 // ***************************************************************************
177 CBezierPatch
*CPatch::unpackIntoCache() const
186 // ***************************************************************************
187 void CPatch::unpack(CBezierPatch
&p
) const
190 const CVector
&bias
= Zone
->getPatchBias();
191 float scale
= Zone
->getPatchScale();
194 Vertices
[i
].unpack(p
.Vertices
[i
], bias
, scale
);
196 Tangents
[i
].unpack(p
.Tangents
[i
], bias
, scale
);
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];
226 bmin
.minof(bmin
, p
.Vertices
[i
]);
227 bmax
.maxof(bmax
, p
.Vertices
[i
]);
231 bmin
.minof(bmin
, p
.Tangents
[i
]);
232 bmax
.maxof(bmax
, p
.Tangents
[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...)
258 buildBBoxFromBezierPatch(p
, 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
;
282 // compute and compare bbox of the subdivision patch against request bbox.
283 //========================
284 // NB: this compute includes possible noise.
286 buildBBoxFromBezierPatch(pa
, paBBox
);
287 // if do not intersect, stop here.
288 if( !paBBox
.intersect(bbox
) )
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 //========================
300 // Subdivide along the bigger side.
304 CBezierPatch left
, right
;
305 pa
.subdivideS(left
, right
);
306 uint8 sMiddle
= (uint8
)( ((uint
)s0
+(uint
)s1
) /2 );
308 addTrianglesInBBoxRecurs(paId
, bbox
, triangles
, tessLevel
, left
, s0
, sMiddle
, t0
, t1
);
310 addTrianglesInBBoxRecurs(paId
, bbox
, triangles
, tessLevel
, right
, sMiddle
, s1
, t0
, t1
);
315 CBezierPatch top
, bottom
;
316 pa
.subdivideT(top
, bottom
);
317 uint8 tMiddle
= (uint8
)( ((uint
)t0
+(uint
)t1
) /2 );
319 addTrianglesInBBoxRecurs(paId
, bbox
, triangles
, tessLevel
, top
, s0
, s1
, t0
, tMiddle
);
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
334 nlassert(tessLevel
<=2);
335 uint tessLen
= 1<<tessLevel
;
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
);
345 for(tl
=0; tl
<tessLen
; tl
++)
347 float fs0
, fs1
, ft0
, ft1
;
348 // compute t patch coordinates.
349 ft0
= startT0
+ (float)tl
* dt
;
351 for(sl
=0; sl
<tessLen
; sl
++)
353 // compute s patch coordinates.
354 fs0
= startS0
+ (float)sl
* 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.
372 quadBBox
.setCenter(p0
);
377 // insert only if intersect with the bbox.
378 if(quadBBox
.intersect(bbox
))
380 // build triangles (in CCW).
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
);
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
);
412 uint s
= PatchBlockId
.S0
+sd0
;
413 uint t
= PatchBlockId
.T0
+td0
;
414 nlassert(s
<PatchBlockId
.S1
);
415 nlassert(t
<PatchBlockId
.T1
);
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
;
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
];
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
;
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
);
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.
480 for(tl
=0; tl
<lenT
+1; tl
++)
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
;
516 // compute and compare bbox of the subdivision patch against request bbox.
517 //========================
518 // NB: this compute includes possible noise.
520 buildBBoxFromBezierPatch(pa
, paBBox
);
521 // if do not intersect, stop here.
522 if( !paBBox
.intersect(bbox
) )
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.
539 paBlockIds
.push_back(pbId
);
541 // else subdiv and reccurs.
542 //========================
545 // Subdivide along the bigger side.
549 CBezierPatch left
, right
;
550 pa
.subdivideS(left
, right
);
551 uint8 sMiddle
= (uint8
)( ((uint
)s0
+(uint
)s1
) /2 );
553 addPatchBlocksInBBoxRecurs(paId
, bbox
, paBlockIds
, left
, s0
, sMiddle
, t0
, t1
);
555 addPatchBlocksInBBoxRecurs(paId
, bbox
, paBlockIds
, right
, sMiddle
, s1
, t0
, t1
);
560 CBezierPatch top
, bottom
;
561 pa
.subdivideT(top
, bottom
);
562 uint8 tMiddle
= (uint8
)( ((uint
)t0
+(uint
)t1
) /2 );
564 addPatchBlocksInBBoxRecurs(paId
, bbox
, paBlockIds
, top
, s0
, s1
, t0
, tMiddle
);
566 addPatchBlocksInBBoxRecurs(paId
, bbox
, paBlockIds
, bottom
, s0
, s1
, tMiddle
, t1
);
573 // ***************************************************************************
574 CVector
CPatch::getTesselatedPos(CUV uv
) const
579 // recurs down the 2 sons.
580 CVector ret
= CVector::Null
;
581 Son0
->getTesselatedPos(uv
, true, ret
);
582 Son1
->getTesselatedPos(uv
, true, ret
);
588 // ***************************************************************************
589 bool CPatch::isRenderClipped() const
592 return Zone
->isPatchRenderClipped(PatchId
);
598 // ***************************************************************************
599 // ***************************************************************************
601 // ***************************************************************************
602 // ***************************************************************************
605 // ***************************************************************************
606 void CPatch::addRefTessBlocks()
612 if (TessBlocks
.empty())
614 // Allocate the tessblocks.
617 nlassert(NL3D_TESSBLOCK_TILESIZE
==4);
618 // A tessblock is 2*2 tiles.
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
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.
647 // append patch for Near updateLighting, since TessBlock lightmap may/will exist.
648 getLandscape()->linkPatchToNearUL(this);
653 // ***************************************************************************
654 void CPatch::decRefTessBlocks()
657 // If no loinger need the tessblocks, delete them.
658 if(TessBlockRefCount
==0)
660 nlassert(TessBlockRefCount
>=0);
664 // ***************************************************************************
665 void CPatch::clearTessBlocks()
669 // Vegetable management
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.
692 // remove patch from Near updateLighting, since no more TessBlock lightmap can exist.
693 getLandscape()->unlinkPatchFromNearUL(this);
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
;
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;
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?
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.
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
);
813 // Alloc if necessary the TessBlocks.
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
);
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.
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.
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.
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
)
945 numtb
= tt
*(uint
)(OrderS
>>1) + ts
;
950 // ***************************************************************************
951 void CPatch::appendTileMaterialToRenderList(CTileMaterial
*tm
)
955 // Alloc if necessary the TessBlocks.
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.
968 // inc ref to the context, creating it if needed.
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.
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();
982 CBezierPatch
*bpatch
= unpackIntoCache();
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
)
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.
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.
1025 // DynamicLighting. When in near, must compute the context, to have good UVs.
1027 // dec ref the context, deleting it if needed.
1030 const std::vector
<ULandscapeTileCallback
*> &tc
= getLandscape()->getTileCallbacks();
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
)
1047 getNumTessBlock(fv
->PCoord
, type
, numtb
);
1050 if(type
==FVMasterBlock
|| type
==FVTessBlockEdge
)
1052 fv
->OwnerBlock
= &MasterBlock
;
1053 MasterBlock
.FarVertexList
.append(fv
);
1057 // Alloc if necessary the TessBlocks.
1060 fv
->OwnerBlock
= &TessBlocks
[numtb
];
1061 TessBlocks
[numtb
].FarVertexList
.append(fv
);
1064 // ***************************************************************************
1065 void CPatch::removeFarVertexFromRenderList(CTessFarVertex
*fv
)
1069 getNumTessBlock(fv
->PCoord
, type
, numtb
);
1072 if(type
==FVMasterBlock
|| type
==FVTessBlockEdge
)
1074 MasterBlock
.FarVertexList
.remove(fv
);
1075 fv
->OwnerBlock
= NULL
;
1079 TessBlocks
[numtb
].FarVertexList
.remove(fv
);
1080 fv
->OwnerBlock
= NULL
;
1082 // Destroy if necessary the TessBlocks.
1088 // ***************************************************************************
1089 void CPatch::appendNearVertexToRenderList(CTileMaterial
*tileMat
, CTessNearVertex
*nv
)
1093 // Alloc if necessary the TessBlocks.
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
)
1107 computeTbTm(numtb
, numtm
, tileMat
->TileS
, tileMat
->TileT
);
1108 TessBlocks
[numtb
].NearVertexList
.remove(nv
);
1109 nv
->OwnerBlock
= NULL
;
1111 // Destroy if necessary the TessBlocks.
1117 // ***************************************************************************
1118 // ***************************************************************************
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];
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];
1146 fa
->PCoord
.setST(0,0);
1148 fb
->PCoord
.setST(0,1);
1150 fc
->PCoord
.setST(1,1);
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);
1161 Tesselation layout. For Square Face, and if OrderS>=OrderT.
1170 For rectangles whith OrderT>OrderS. It is VERY IMPORTANT, for splitRectangular() reasons.
1180 nlassert(Son0
==NULL
);
1181 nlassert(Son1
==NULL
);
1182 Son0
= getLandscape()->newTessFace();
1183 Son1
= getLandscape()->newTessFace();
1196 Son0
->PVBase
.setST(0, 1);
1197 Son0
->PVLeft
.setST(1, 1);
1198 Son0
->PVRight
.setST(0, 0);
1208 Son0
->PVBase
.setST(0, 0);
1209 Son0
->PVLeft
.setST(0, 1);
1210 Son0
->PVRight
.setST(1, 0);
1216 Son0
->Size
= ErrorSize
/2;
1217 Son0
->computeSplitPoint();
1230 Son1
->PVBase
.setST(1, 0);
1231 Son1
->PVLeft
.setST(0, 0);
1232 Son1
->PVRight
.setST(1, 1);
1242 Son1
->PVBase
.setST(1, 1);
1243 Son1
->PVLeft
.setST(1, 0);
1244 Son1
->PVRight
.setST(0, 1);
1250 Son1
->Size
= ErrorSize
/2;
1251 Son1
->computeSplitPoint();
1254 // Prepare the render list...
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
)
1291 // For updateLighting, get the correct pointer now.
1292 // Init UL circular list to me
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
;
1306 computeDefaultErrorSize();
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];
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.
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
;
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
1371 // Test is on a edge/corner of the patch
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
;
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.
1404 // Get my neighbor, if any.
1406 getBindNeighbor(edgeId
, bindInfo
);
1407 // Fast reject: if no neighbor on the edge, just return my pos.
1412 // else must get vertex pos of my neighbor, and average.
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
);
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.
1437 CVector vertexOnNeb
= nebPatch
->computeVertexButCorner(stTileOut
.x
, stTileOut
.y
, onCorner
);
1439 // If the neighbor is on a corner, then use its corner value.
1444 // Average the 2 and return this result.
1445 vertexOnMe
+= vertexOnNeb
;
1454 return computeVertex(s
, t
);
1458 // ***************************************************************************
1459 CVector
CPatch::computeVertexButCorner(float s
, float t
, bool &onCorner
) const
1464 // Test is on a edge/corner of the patch
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
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
;
1483 // Error, but Avoid warning
1484 return CVector::Null
;
1490 return computeVertex(s
, t
);
1495 // ***************************************************************************
1496 void CPatch::refineAll()
1507 // ***************************************************************************
1508 void CPatch::averageTesselationVertices()
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];
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()
1539 // Recompute the BaseVertices.
1540 CTessVertex
*a
= BaseVertices
[0];
1541 CTessVertex
*b
= BaseVertices
[1];
1542 CTessVertex
*c
= BaseVertices
[2];
1543 CTessVertex
*d
= BaseVertices
[3];
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
;
1578 // ***************************************************************************
1579 void CPatch::serial(NLMISC::IStream
&f
)
1583 - remove unused information from CTileColor. just keep 565 color
1585 - default UnderWater flags for tileElements before version 6.
1587 - TileLightInfluences serialized.
1589 - Smooth flag serialized
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.
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]);
1616 f
.xmlSerial (Interiors
[0], Interiors
[1], Interiors
[2], Interiors
[3], "INTERIORS");
1618 f
.xmlPush ("TILES");
1619 f
.serialCont(Tiles
);
1624 // Read/Write TileColors.
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
);
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
));
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
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
1659 f
.xmlSerial (OrderS
, "ORDER_S");
1660 f
.xmlSerial (OrderT
, "ORDER_T");
1662 f
.xmlPush ("COMPRESSED_LUMELS");
1663 f
.serialCont(CompressedLumels
);
1666 // Else cannot create here the TileColors, because we need the OrderS/OrderT information... Done into CZone serial.
1669 f
.xmlSerial (NoiseRotation
, "NOISE_ROTATION");
1670 f
.xmlSerial (_CornerSmoothFlag
, "CORNER_SMOOTH_FLAG");
1674 // No Rotation / not smooth by default.
1676 _CornerSmoothFlag
= 0;
1680 f
.xmlSerial(Flags
, "FLAGS");
1684 Flags
=NL_PATCH_SMOOTH_FLAG_MASK
;
1687 // Serialize TileLightInfluences
1690 f
.xmlPush ("TILE_LIGHT_INFLUENCES");
1691 f
.serialCont(TileLightInfluences
);
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 // ***************************************************************************
1721 // ***************************************************************************
1722 // ***************************************************************************
1726 // ***************************************************************************
1727 void CPatch::unbind()
1729 nlassert(Son0
&& Son1
);
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
);
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.
1761 if(edge
==0 || edge
==1)
1768 if(edge
==0 || edge
==3)
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.
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
;
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.
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;
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
1844 face
= Son1
->linkTessFaceWithEdge(uv0
, uv1
, linkTo
);
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).
1871 // just Copy zone (if not NULL).
1872 _BindZoneNeighbor
[i
]= Edges
[i
].Zone
;
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];
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();
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
);
1907 CBindInfo
&bind
= Edges
[i
];
1909 nlassert(bind
.NPatchs
==0 || bind
.NPatchs
==1 || bind
.NPatchs
==2 || bind
.NPatchs
==4 || bind
.NPatchs
==5);
1913 this->changeEdgeNeighbor(i
, bind
.Next
[0]->getRootFaceForEdge(bind
.Edge
[0]));
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
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
;
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
1998 // build a CPatchUVLocator to transpose coorindate ot this edge in coordinate on the bigger Neighbor patch.
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
;
2008 CPatch
*patchNeighbor
;
2010 pid
= puvloc
.selectPatch(uvi0
);
2011 puvloc
.locateUV(uvi0
, pid
, patchNeighbor
, uvo0
);
2012 nlassert(patchNeighbor
== bindInfo
.Next
[0]);
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
);
2028 this->changeEdgeNeighbor(i
, faceNeighbor
);
2034 // Propagate the binds to sons.
2041 // ***************************************************************************
2042 void CPatch::forceMergeAtTileLevel()
2044 nlassert(Son0
&& Son1
);
2046 Son0
->forceMergeAtTileLevel();
2047 Son1
->forceMergeAtTileLevel();
2052 // ***************************************************************************
2053 // ***************************************************************************
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.
2071 // Default: take addtive of pass 0.
2073 // If the pass1 is not empty, may take its tile.
2074 if(Tiles
[tileId
].Tile
[1]!=0xFFFF)
2077 // If the pass2 is not empty, take its tile.
2078 if(Tiles
[tileId
].Tile
[2]!=0xFFFF)
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).
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.
2111 // Default: take addtive of pass 0.
2113 // If the pass1 is not empty, may take its tile.
2114 if(Tiles
[tileId
].Tile
[1]!=0xFFFF)
2117 // If the pass2 is not empty, take its tile.
2118 if(Tiles
[tileId
].Tile
[2]!=0xFFFF)
2123 sint tileNumber
= Tiles
[tileId
].Tile
[passNum
];
2124 if(tileNumber
==0xFFFF)
2126 // dummy... Should not be called here.
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)
2145 type
= CTile::additive
;
2147 type
= CTile::diffuse
;
2151 Zone
->Landscape
->getTileUvScaleBiasRot(uint16(tileNumber
), type
, uvScaleBias
, rotalpha
);
2153 // Add the special rotation of 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
];
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
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
;
2225 // ***************************************************************************
2226 // ***************************************************************************
2227 // Realtime Bind info.
2228 // ***************************************************************************
2229 // ***************************************************************************
2232 // ***************************************************************************
2233 void CPatch::getBindNeighbor(uint edge
, CBindInfo
&neighborEdge
) const
2237 if(_BindZoneNeighbor
[edge
]!=NULL
)
2239 getZone()->buildBindInfo(PatchId
, edge
, _BindZoneNeighbor
[edge
], neighborEdge
);
2243 neighborEdge
.Zone
= NULL
;
2244 neighborEdge
.NPatchs
= 0;
2245 neighborEdge
.MultipleBindNum
= 0;
2249 // ***************************************************************************
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.
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);
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
);
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
);