Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / zone.cpp
blob029f6da8105a393b15f7c58c6d28693e04968f3a
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"
19 #include "nel/3d/zone.h"
20 #include "nel/3d/landscape.h"
21 #include "nel/3d/zone_symmetrisation.h"
22 #include "nel/misc/common.h"
23 #include "nel/misc/hierarchical_timer.h"
26 using namespace NLMISC;
27 using namespace std;
30 // define it only for debug bind.
31 //#define NL3D_DEBUG_DONT_BIND_PATCH
33 #ifdef DEBUG_NEW
34 #define new DEBUG_NEW
35 #endif
37 namespace NL3D
42 // ***************************************************************************
43 // ***************************************************************************
44 // CPatchInfo
45 // ***************************************************************************
46 // ***************************************************************************
49 // ***************************************************************************
50 void CPatchInfo::setCornerSmoothFlag(uint corner, bool smooth)
52 nlassert(corner<=3);
53 uint mask= 1<<corner;
54 if(smooth)
55 _CornerSmoothFlag|= mask;
56 else
57 _CornerSmoothFlag&= ~mask;
60 // ***************************************************************************
61 bool CPatchInfo::getCornerSmoothFlag(uint corner) const
63 nlassert(corner<=3);
64 uint mask= 1<<corner;
65 return (_CornerSmoothFlag & mask)!=0;
69 // ***************************************************************************
70 // ***************************************************************************
71 // CZone
72 // ***************************************************************************
73 // ***************************************************************************
76 // ***************************************************************************
77 CZone::CZone()
79 ZoneId= 0;
80 Compiled= false;
81 Landscape= NULL;
82 ClipResult= ClipOut;
84 // ***************************************************************************
85 CZone::~CZone()
87 // release() must have been called.
88 nlassert(!Compiled);
92 // ***************************************************************************
93 void CZone::computeBBScaleBias(const CAABBox &bb)
95 ZoneBB= bb;
96 // Take a security for noise. (useful for zone clipping).
97 ZoneBB.setHalfSize(ZoneBB.getHalfSize()+CVector(NL3D_NOISE_MAX, NL3D_NOISE_MAX, NL3D_NOISE_MAX));
98 CVector hs= ZoneBB.getHalfSize();
99 float rmax= maxof(hs.x, hs.y, hs.z);
100 PatchScale= rmax / 32760; // Prevent from float imprecision by taking 32760 and not 32767.
101 PatchBias= ZoneBB.getCenter();
105 // ***************************************************************************
106 void CZone::build(uint16 zoneId, const std::vector<CPatchInfo> &patchs, const std::vector<CBorderVertex> &borderVertices, uint32 numVertices)
108 CZoneInfo zinfo;
109 zinfo.ZoneId= zoneId;
110 zinfo.Patchs= patchs;
111 zinfo.BorderVertices= borderVertices;
113 build(zinfo, numVertices);
115 // ***************************************************************************
116 void CZone::build(const CZoneInfo &zoneInfo, uint32 numVertices)
118 sint i,j;
119 nlassert(!Compiled);
121 // Ref inupt
122 uint16 zoneId= zoneInfo.ZoneId;
123 const std::vector<CPatchInfo> &patchs= zoneInfo.Patchs;
124 const std::vector<CBorderVertex> &borderVertices= zoneInfo.BorderVertices;
127 ZoneId= zoneId;
128 BorderVertices= borderVertices;
130 // Compute the bbox and the bias/scale.
131 //=====================================
132 CAABBox bb;
133 if(!patchs.empty())
134 bb.setCenter(patchs[0].Patch.Vertices[0]);
135 bb.setHalfSize(CVector::Null);
136 for(j=0;j<(sint)patchs.size();j++)
138 const CBezierPatch &p= patchs[j].Patch;
139 for(i=0;i<4;i++)
140 bb.extend(p.Vertices[i]);
141 for(i=0;i<8;i++)
142 bb.extend(p.Tangents[i]);
143 for(i=0;i<4;i++)
144 bb.extend(p.Interiors[i]);
146 // Compute BBox, and Patch Scale Bias, according to Noise.
147 computeBBScaleBias(bb);
150 // Compute/compress Patchs.
151 //=========================
152 Patchs.resize(patchs.size());
153 PatchConnects.resize(patchs.size());
154 sint maxVertex=-1;
155 for(j=0;j<(sint)patchs.size();j++)
157 const CPatchInfo &pi= patchs[j];
158 const CBezierPatch &p= pi.Patch;
159 CPatch &pa= Patchs[j];
160 CPatchConnect &pc= PatchConnects[j];
162 // Smoothing flags
163 pa.Flags&=~NL_PATCH_SMOOTH_FLAG_MASK;
164 pa.Flags|=NL_PATCH_SMOOTH_FLAG_MASK&(pi.Flags<<NL_PATCH_SMOOTH_FLAG_SHIFT);
167 // Noise Data
168 // copy noise rotation.
169 pa.NoiseRotation= pi.NoiseRotation;
170 // copy all noise smoothing info.
171 for(i=0;i<4;i++)
173 pa.setCornerSmoothFlag(i, pi.getCornerSmoothFlag(i));
176 // Copy order of the patch
177 pa.OrderS= pi.OrderS;
178 pa.OrderT= pi.OrderT;
180 // Build the patch.
181 for(i=0;i<4;i++)
182 pa.Vertices[i].pack(p.Vertices[i], PatchBias, PatchScale);
183 for(i=0;i<8;i++)
184 pa.Tangents[i].pack(p.Tangents[i], PatchBias, PatchScale);
185 for(i=0;i<4;i++)
186 pa.Interiors[i].pack(p.Interiors[i], PatchBias, PatchScale);
187 pa.Tiles= pi.Tiles;
188 pa.TileColors= pi.TileColors;
189 /* Copy TileLightInfluences. It is possible that pi.TileLightInfluences.size()!= 0
190 and pi.TileLightInfluences.size()!= (uint)(pi.OrderS/2+1)*(pi.OrderT/2+1)
191 Because of a preceding bug where pa.OrderS and pa.OrderT were not initialized before the
192 pa.resetTileLightInfluences();
194 if( pi.TileLightInfluences.size()!= (uint)(pi.OrderS/2+1)*(pi.OrderT/2+1) )
196 pa.resetTileLightInfluences();
198 else
200 pa.TileLightInfluences= pi.TileLightInfluences;
203 // Number of lumels in this patch
204 uint lumelCount=(pi.OrderS*NL_LUMEL_BY_TILE)*(pi.OrderT*NL_LUMEL_BY_TILE);
206 // Lumel empty ?
207 if (pi.Lumels.size ()==lumelCount)
209 // Pack the lumel map
210 pa.packShadowMap (&pi.Lumels[0]);
212 else
214 // Reset lightmap
215 pa.resetCompressedLumels ();
218 nlassert(pa.Tiles.size()== (uint)pi.OrderS*pi.OrderT);
219 nlassert(pa.TileColors.size()== (uint)(pi.OrderS+1)*(pi.OrderT+1));
221 // Build the patchConnect.
222 pc.ErrorSize= pi.ErrorSize;
223 for(i=0;i<4;i++)
225 pc.BaseVertices[i]= pi.BaseVertices[i];
226 maxVertex= max((sint)pc.BaseVertices[i], maxVertex);
228 for(i=0;i<4;i++)
229 pc.BindEdges[i]= pi.BindEdges[i];
232 NumVertices= maxVertex+1;
233 NumVertices= max((uint32)NumVertices, numVertices);
235 // Init the Clip Arrays
236 _PatchRenderClipped.resize((uint)Patchs.size());
237 _PatchOldRenderClipped.resize((uint)Patchs.size());
238 _PatchRenderClipped.setAll();
239 _PatchOldRenderClipped.setAll();
241 // Copy PointLights.
242 //=========================
243 // build array, lights are sorted
244 std::vector<uint> plRemap;
245 _PointLightArray.build(zoneInfo.PointLights, plRemap);
246 // Check TileLightInfluences integrity, and remap PointLight Indices.
247 for(j=0;j<(sint)patchs.size();j++)
249 CPatch &pa= Patchs[j];
250 for(uint k= 0; k<pa.TileLightInfluences.size(); k++)
252 CTileLightInfluence &tli= pa.TileLightInfluences[k];
253 for(uint l=0; l<CTileLightInfluence::NumLightPerCorner; l++)
255 // If NULL light, break and continue to next TileLightInfluence.
256 if(tli.Light[l]== 0xFF)
257 break;
258 else
260 // Check good index.
261 nlassert(tli.Light[l] < _PointLightArray.getPointLights().size());
262 // Remap index, because of light sorting.
263 tli.Light[l]= plRemap[tli.Light[l]];
271 // ***************************************************************************
272 void CZone::retrieve(std::vector<CPatchInfo> &patchs, std::vector<CBorderVertex> &borderVertices)
274 CZoneInfo zinfo;
276 retrieve(zinfo);
278 patchs= zinfo.Patchs;
279 borderVertices= zinfo.BorderVertices;
282 // ***************************************************************************
283 void CZone::retrieve(CZoneInfo &zoneInfo)
285 sint i,j;
287 // Ref on input.
288 std::vector<CPatchInfo> &patchs= zoneInfo.Patchs;
289 std::vector<CBorderVertex> &borderVertices= zoneInfo.BorderVertices;
290 // Copy zoneId.
291 zoneInfo.ZoneId= getZoneId();
294 // uncompress Patchs.
295 //=========================
296 patchs.resize(Patchs.size());
297 for(j=0;j<(sint)patchs.size();j++)
299 CPatchInfo &pi= patchs[j];
300 CBezierPatch &p= pi.Patch;
301 CPatch &pa= Patchs[j];
302 CPatchConnect &pc= PatchConnects[j];
305 // Smoothing flags
306 pi.Flags= (pa.Flags&NL_PATCH_SMOOTH_FLAG_MASK)>>NL_PATCH_SMOOTH_FLAG_SHIFT;
309 // Noise Data
310 // copy noise rotation.
311 pi.NoiseRotation= pa.NoiseRotation;
312 // copy all noise smoothing info.
313 for(i=0;i<4;i++)
315 pi.setCornerSmoothFlag(i, pa.getCornerSmoothFlag(i));
319 // re-Build the uncompressed bezier patch.
320 for(i=0;i<4;i++)
321 pa.Vertices[i].unpack(p.Vertices[i], PatchBias, PatchScale);
322 for(i=0;i<8;i++)
323 pa.Tangents[i].unpack(p.Tangents[i], PatchBias, PatchScale);
324 for(i=0;i<4;i++)
325 pa.Interiors[i].unpack(p.Interiors[i], PatchBias, PatchScale);
326 pi.Tiles= pa.Tiles;
327 pi.TileColors= pa.TileColors;
328 pi.TileLightInfluences= pa.TileLightInfluences;
329 pi.Lumels.resize ((pa.OrderS*4)*(pa.OrderT*4));
330 pi.Flags=(pa.Flags&NL_PATCH_SMOOTH_FLAG_MASK)>>NL_PATCH_SMOOTH_FLAG_SHIFT;
332 // Unpack the lumel map
333 pa.unpackShadowMap (&pi.Lumels[0]);
335 // from the patchConnect.
336 pi.OrderS= pa.OrderS;
337 pi.OrderT= pa.OrderT;
338 pi.ErrorSize= pc.ErrorSize;
339 for(i=0;i<4;i++)
341 pi.BaseVertices[i]= pc.BaseVertices[i];
343 for(i=0;i<4;i++)
344 pi.BindEdges[i]= pc.BindEdges[i];
347 // retrieve bordervertices.
348 //=========================
349 borderVertices= BorderVertices;
351 // retrieve PointLights.
352 //=========================
353 zoneInfo.PointLights= _PointLightArray.getPointLights();
358 // ***************************************************************************
359 void CZone::build(const CZone &zone)
361 nlassert(!Compiled);
363 ZoneId= zone.ZoneId;
364 BorderVertices= zone.BorderVertices;
366 // Compute the bbox and the bias/scale.
367 //=====================================
368 ZoneBB= zone.ZoneBB;
369 PatchScale= zone.PatchScale;
370 PatchBias= zone.PatchBias;
373 // Compute/compress Patchs.
374 //=========================
375 Patchs= zone.Patchs;
376 PatchConnects= zone.PatchConnects;
378 // Init the Clip Arrays
379 _PatchRenderClipped.resize((uint)Patchs.size());
380 _PatchOldRenderClipped.resize((uint)Patchs.size());
381 _PatchRenderClipped.setAll();
382 _PatchOldRenderClipped.setAll();
385 // copy pointLights.
386 //=========================
387 _PointLightArray= zone._PointLightArray;
390 NumVertices= zone.NumVertices;
395 // ***************************************************************************
396 void CBorderVertex::serial(NLMISC::IStream &f)
398 /* ***********************************************
399 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
400 * It can be loaded/called through CAsyncFileManager for instance
401 * ***********************************************/
402 (void)f.serialVersion(0);
404 f.xmlSerial (CurrentVertex, "CURRENT_VERTEX");
405 f.xmlSerial (NeighborZoneId, "NEIGHTBOR_ZONE_ID");
406 f.xmlSerial (NeighborVertex, "NEIGHTBOR_VERTEX");
408 void CZone::CPatchConnect::serial(NLMISC::IStream &f)
410 /* ***********************************************
411 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
412 * It can be loaded/called through CAsyncFileManager for instance
413 * ***********************************************/
414 uint ver= f.serialVersion(1);
416 if (ver<1)
417 f.serial(OldOrderS, OldOrderT, ErrorSize);
418 else
419 f.serial(ErrorSize);
420 f.xmlSerial (BaseVertices[0], BaseVertices[1], BaseVertices[2], BaseVertices[3], "BASE_VERTICES");
421 f.xmlSerial (BindEdges[0], BindEdges[1], BindEdges[2], BindEdges[3], "BIND_EDGES");
423 void CPatchInfo::CBindInfo::serial(NLMISC::IStream &f)
425 /* ***********************************************
426 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
427 * It can be loaded/called through CAsyncFileManager for instance
428 * ***********************************************/
429 (void)f.serialVersion(0);
430 f.xmlSerial(NPatchs, "NPATCH");
431 nlassert ( (NPatchs==0) | (NPatchs==1) | (NPatchs==2) | (NPatchs==4) | (NPatchs==5) );
432 f.xmlSerial (ZoneId, "ZONE_ID");
433 f.xmlSerial (Next[0], Next[1], Next[2], Next[3], "NEXT_PATCH");
434 f.xmlSerial (Edge[0], Edge[1], Edge[2], Edge[3], "NEXT_EDGE");
437 // ***************************************************************************
438 void CZone::serial(NLMISC::IStream &f)
440 /* ***********************************************
441 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
442 * It can be loaded/called through CAsyncFileManager for instance
443 * ***********************************************/
445 Version 4:
446 - PointLights
447 Version 3:
448 - Lumels compression version 2.
449 Version 2:
450 - Lumels.
451 Version 1:
452 - Tile color.
453 Version 0:
454 - base verison.
456 uint ver= f.serialVersion(4);
458 // No more compatibility before version 3
459 if (ver<3)
461 throw EOlderStream(f);
464 f.serialCheck(NELID("ENOZ"));
466 f.xmlSerial (ZoneId, "ZONE_ID");
467 f.xmlSerial (ZoneBB, "BB");
468 f.xmlSerial (PatchBias, "PATCH_BIAS");
469 f.xmlSerial (PatchScale, "PATCH_SCALE");
470 f.xmlSerial (NumVertices, "NUM_VERTICES");
472 f.xmlPush ("BORDER_VERTICES");
473 f.serialCont(BorderVertices);
474 f.xmlPop ();
476 f.xmlPush ("PATCHES");
477 f.serialCont(Patchs);
478 f.xmlPop ();
480 f.xmlPush ("PATCH_CONNECTS");
481 f.serialCont(PatchConnects);
482 f.xmlPop ();
484 if (ver>=4)
486 f.xmlPush ("POINT_LIGHTS");
487 f.serial(_PointLightArray);
488 f.xmlPop ();
491 // If read, must create and init Patch Clipped state to true (clipped even if not compiled)
492 if(f.isReading())
494 _PatchRenderClipped.resize((uint)Patchs.size());
495 _PatchOldRenderClipped.resize((uint)Patchs.size());
496 _PatchRenderClipped.setAll();
497 _PatchOldRenderClipped.setAll();
500 // If read and version 0, must init default TileColors of patchs.
501 //===============================================================
502 // if(f.isReading() && ver<2) ...
503 // Deprecated, because ver<3 not supported
508 // ***************************************************************************
509 void CZone::compile(CLandscape *landscape, TZoneMap &loadedZones)
511 sint i,j;
512 TZoneMap neighborZones;
514 //nlinfo("Compile Zone: %d \n", (sint32)getZoneId());
516 // Can't compile if compiled.
517 nlassert(!Compiled);
518 Landscape= landscape;
520 // Attach this to loadedZones.
521 //============================
522 nlassert(loadedZones.find(ZoneId)==loadedZones.end());
523 loadedZones[ZoneId]= this;
525 // Create/link the base vertices according to present neigbor zones.
526 //============================
527 BaseVertices.clear();
528 BaseVertices.resize(NumVertices);
529 // First try to link vertices to other.
530 for(i=0;i<(sint)BorderVertices.size();i++)
532 sint cur= BorderVertices[i].CurrentVertex;
533 sint vertto= BorderVertices[i].NeighborVertex;
534 sint zoneto= BorderVertices[i].NeighborZoneId;
535 nlassert(cur<NumVertices);
537 if(loadedZones.find(zoneto)!=loadedZones.end())
539 CZone *zone;
540 zone= (*loadedZones.find(zoneto)).second;
541 nlassert(zone!=this);
542 // insert the zone in the neigborood (if not done...).
543 neighborZones[zoneto]= zone;
544 // Doesn't matter if BaseVertices is already linked to another zone...
545 // This should be the same pointer in this case...
546 BaseVertices[cur]= zone->getBaseVertex(vertto);
549 // Else, create unbounded vertices.
550 for(i=0;i<(sint)BaseVertices.size();i++)
552 if(BaseVertices[i]==NULL)
554 BaseVertices[i]= new CTessBaseVertex;
559 // compile() the patchs.
560 //======================
561 for(j=0;j<(sint)Patchs.size();j++)
563 CPatch &pa= Patchs[j];
564 CPatchConnect &pc= PatchConnects[j];
565 CTessVertex *baseVertices[4];
567 baseVertices[0]= &(BaseVertices[pc.BaseVertices[0]]->Vert);
568 baseVertices[1]= &(BaseVertices[pc.BaseVertices[1]]->Vert);
569 baseVertices[2]= &(BaseVertices[pc.BaseVertices[2]]->Vert);
570 baseVertices[3]= &(BaseVertices[pc.BaseVertices[3]]->Vert);
571 pa.compile(this, j, pa.OrderS, pa.OrderT, baseVertices, pc.ErrorSize);
574 // compile() the Clip information for the patchs.
575 //======================
576 _PatchBSpheres.resize(Patchs.size());
577 for(j=0;j<(sint)Patchs.size();j++)
579 CPatch &pa= Patchs[j];
581 // Buil the BSPhere of the patch.
582 CAABBox bb= pa.buildBBox();
583 _PatchBSpheres[j].Center= bb.getCenter();
584 _PatchBSpheres[j].Radius= bb.getRadius();
587 // bind() the patchs. (after all compiled).
588 //===================
589 for(j=0;j<(sint)Patchs.size();j++)
591 CPatch &pa= Patchs[j];
592 CPatchConnect &pc= PatchConnects[j];
594 // bind the patch. This is the original bind, not a rebind.
595 bindPatch(loadedZones, pa, pc, false);
599 // rebindBorder() on neighbor zones.
600 //==================================
601 ItZoneMap zoneIt;
602 // Traverse the neighborood.
603 for(zoneIt= neighborZones.begin(); zoneIt!=neighborZones.end(); zoneIt++)
605 (*zoneIt).second->rebindBorder(loadedZones);
608 // End!!
609 Compiled= true;
612 // ***************************************************************************
613 void CZone::release(TZoneMap &loadedZones)
615 sint i,j;
617 if(!Compiled)
618 return;
620 // detach this zone to loadedZones.
621 //=================================
622 nlassert(loadedZones.find(ZoneId)!=loadedZones.end());
623 loadedZones.erase(ZoneId);
624 // It doesn't server to unbindPatch(), since patch is not binded to neigbors.
627 // unbind() the patchs.
628 //=====================
629 for(j=0;j<(sint)Patchs.size();j++)
631 CPatch &pa= Patchs[j];
632 unbindPatch(pa);
636 // rebindBorder() on neighbor zones.
637 //==================================
638 // Build the nieghborood.
639 TZoneMap neighborZones;
640 for(i=0;i<(sint)BorderVertices.size();i++)
642 sint cur= BorderVertices[i].CurrentVertex;
643 sint zoneto= BorderVertices[i].NeighborZoneId;
644 nlassert(cur<NumVertices);
646 if(loadedZones.find(zoneto)!=loadedZones.end())
648 CZone *zone;
649 zone= (*loadedZones.find(zoneto)).second;
650 nlassert(zone!=this);
651 // insert the zone in the neigborood (if not done...).
652 neighborZones[zoneto]= zone;
655 // rebind borders.
656 ItZoneMap zoneIt;
657 // Traverse the neighborood.
658 for(zoneIt= neighborZones.begin(); zoneIt!=neighborZones.end(); zoneIt++)
660 // Since
661 (*zoneIt).second->rebindBorder(loadedZones);
665 // release() the patchs.
666 //======================
667 // unbind() need compiled neigbor patchs, so do the release after all unbind (so after rebindBorder() too...).
668 for(j=0;j<(sint)Patchs.size();j++)
670 CPatch &pa= Patchs[j];
671 pa.release();
675 // destroy/unlink the base vertices (internal..), according to present neigbor zones.
676 //=================================
677 // Just release the smartptrs (easy!!). Do it after patchs released...
678 BaseVertices.clear();
681 // End!!
682 Compiled= false;
683 Landscape= NULL;
684 ClipResult= ClipOut;
688 // ***************************************************************************
689 // ***************************************************************************
690 // Private part.
691 // ***************************************************************************
692 // ***************************************************************************
695 // ***************************************************************************
696 void CZone::rebindBorder(TZoneMap &loadedZones)
698 sint j;
700 // rebind patchs which are on border.
701 for(j=0;j<(sint)Patchs.size();j++)
703 CPatch &pa= Patchs[j];
704 CPatchConnect &pc= PatchConnects[j];
706 if(patchOnBorder(pc))
708 // rebind the patch. This is a rebind.
709 bindPatch(loadedZones, pa, pc, true);
714 // ***************************************************************************
715 CPatch *CZone::getZonePatch(TZoneMap &loadedZones, sint zoneId, sint patch)
717 #ifdef NL3D_DEBUG_DONT_BIND_PATCH
718 return NULL;
719 #endif
720 if(loadedZones.find(zoneId)==loadedZones.end())
721 return NULL;
722 else
723 return (loadedZones[zoneId])->getPatch(patch);
727 // ***************************************************************************
728 void CZone::buildBindInfo(uint patchId, uint edge, CZone *neighborZone, CPatch::CBindInfo &paBind)
730 nlassert(patchId < Patchs.size());
731 nlassert(neighborZone);
733 CPatchConnect &pc= PatchConnects[patchId];
736 // Get the bind info of this patch to his neighbor on "edge".
737 CPatchInfo::CBindInfo &pcBind= pc.BindEdges[edge];
738 nlassert(pcBind.NPatchs==0 || pcBind.NPatchs==1 || pcBind.NPatchs==2 || pcBind.NPatchs==4 || pcBind.NPatchs==5);
741 // copy zone ptr.
742 paBind.Zone= neighborZone;
745 // Special case of a small patch connected to a bigger.
746 if(pcBind.NPatchs==5)
748 paBind.NPatchs= 1;
749 paBind.Next[0]= neighborZone->getPatch(pcBind.Next[0]);
750 paBind.Edge[0]= pcBind.Edge[0];
752 // Get the twin bindInfo of pcBind.
753 const CPatchInfo::CBindInfo &pcBindNeighbor=
754 neighborZone->getPatchConnect(pcBind.Next[0])->BindEdges[pcBind.Edge[0]];
755 // must have a multiple bind.
756 nlassert(pcBindNeighbor.NPatchs == 2 || pcBindNeighbor.NPatchs == 4);
758 // number of bind is stored on the twin bindInfo.
759 paBind.MultipleBindNum= pcBindNeighbor.NPatchs;
761 // Search our patchId on neighbor;
762 paBind.MultipleBindId= 255;
763 for(sint i=0; i<paBind.MultipleBindNum; i++)
765 if(pcBindNeighbor.Next[i]==patchId)
766 paBind.MultipleBindId= i;
768 nlassert(paBind.MultipleBindId!= 255);
770 else
772 paBind.MultipleBindNum= 0;
773 paBind.NPatchs= pcBind.NPatchs;
774 for(sint i=0;i<paBind.NPatchs; i++)
776 paBind.Next[i]= neighborZone->getPatch(pcBind.Next[i]);
777 paBind.Edge[i]= pcBind.Edge[i];
785 // ***************************************************************************
786 void CZone::bindPatch(TZoneMap &loadedZones, CPatch &pa, CPatchConnect &pc, bool rebind)
788 CPatch::CBindInfo edges[4];
790 // Fill all edges.
791 for(sint i=0;i<4;i++)
793 CPatchInfo::CBindInfo &pcBind= pc.BindEdges[i];
794 CPatch::CBindInfo &paBind= edges[i];
796 nlassert(pcBind.NPatchs==0 || pcBind.NPatchs==1 || pcBind.NPatchs==2 || pcBind.NPatchs==4 || pcBind.NPatchs==5);
797 paBind.NPatchs= pcBind.NPatchs;
800 // Find the zone.
801 TZoneMap::iterator itZoneMap;
802 // If no neighbor, or if zone neighbor not loaded.
803 if( paBind.NPatchs==0 || (itZoneMap=loadedZones.find(pcBind.ZoneId)) == loadedZones.end() )
804 paBind.Zone= NULL;
805 else
806 paBind.Zone= itZoneMap->second;
809 // Special case of a small patch connected to a bigger.
810 if(paBind.NPatchs==5)
812 paBind.Edge[0]= pcBind.Edge[0];
813 paBind.Next[0]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[0]);
814 // If not loaded, don't bind to this edge.
815 if(!paBind.Next[0])
816 paBind.NPatchs=0;
817 else
819 // pa.bind() will do the job.
820 // Leave it flagged with NPatchs==5.
821 continue;
826 // Bind 1/1 and 1/2,1/4
827 if(paBind.NPatchs>=1)
829 paBind.Edge[0]= pcBind.Edge[0];
830 paBind.Next[0]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[0]);
831 // If not loaded, don't bind to this edge.
832 if(!paBind.Next[0])
833 paBind.NPatchs=0;
835 if(paBind.NPatchs>=2)
837 paBind.Edge[1]= pcBind.Edge[1];
838 paBind.Next[1]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[1]);
839 // If not loaded, don't bind to this edge.
840 if(!paBind.Next[1])
841 paBind.NPatchs=0;
843 if(paBind.NPatchs>=4)
845 paBind.Edge[2]= pcBind.Edge[2];
846 paBind.Edge[3]= pcBind.Edge[3];
847 paBind.Next[2]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[2]);
848 paBind.Next[3]= CZone::getZonePatch(loadedZones, pcBind.ZoneId, pcBind.Next[3]);
849 // If not loaded, don't bind to this edge.
850 if(!paBind.Next[2] || !paBind.Next[3])
851 paBind.NPatchs=0;
855 // First, unbind.
856 pa.unbind();
858 // Then bind.
859 pa.bind(edges, rebind);
863 // ***************************************************************************
864 void CZone::unbindPatch(CPatch &pa)
867 Remind: the old version with CPatch::unbindFrom*() doesn't work because of CZone::release(). This function
868 first erase the zone from loadedZones...
869 Not matter here. We use CPatch::unbind() which should do all the good job correctly (unbind pa from ohters
870 , and unbind others from pa at same time).
873 pa.unbind();
877 // ***************************************************************************
878 bool CZone::patchOnBorder(const CPatchConnect &pc) const
880 // If only one of neighbor patch is not of this zone, we are on a border.
882 // Test all edges.
883 for(sint i=0;i<4;i++)
885 const CPatchInfo::CBindInfo &pcBind= pc.BindEdges[i];
887 nlassert(pcBind.NPatchs==0 || pcBind.NPatchs==1 || pcBind.NPatchs==2 || pcBind.NPatchs==4 || pcBind.NPatchs==5);
888 if(pcBind.NPatchs>=1)
890 if(pcBind.ZoneId != ZoneId)
891 return true;
895 return false;
899 // ***************************************************************************
900 // ***************************************************************************
901 // Render part.
902 // ***************************************************************************
903 // ***************************************************************************
906 // ***************************************************************************
907 const CBSphere &CZone::getPatchBSphere(uint patch) const
909 static CBSphere dummySphere;
910 if(patch<_PatchBSpheres.size())
911 return _PatchBSpheres[patch];
912 else
913 return dummySphere;
917 // ***************************************************************************
918 void CZone::clip(const std::vector<CPlane> &pyramid)
920 H_AUTO( NLMISC_ClipZone );
922 nlassert(Compiled);
924 // bkup old ClipResult. NB: by default, it is ClipOut (no VB created).
925 sint oldClipResult= ClipResult;
927 // Pyramid with only the planes that clip the zone
928 static std::vector<CPlane> patchPyramid(10);
929 static std::vector<uint> patchPyramidIndex(10);
930 patchPyramidIndex.clear();
932 // Compute ClipResult.
933 //-------------------
934 ClipResult= ClipIn;
935 for(sint i=0;i<(sint)pyramid.size();i++)
937 // If entirely out.
938 if(!ZoneBB.clipBack(pyramid[i]))
940 ClipResult= ClipOut;
941 // If out of only one plane, out of all.
942 break;
944 // If partially IN (ie not entirely out, and not entirely IN)
945 else if(ZoneBB.clipFront(pyramid[i]))
947 // Force ClipResult to be ClipSide, and not ClipIn.
948 ClipResult=ClipSide;
949 // Append the plane index to list to test
950 patchPyramidIndex.push_back(i);
955 // Easy Clip :)
956 if(Patchs.empty())
958 ClipResult= ClipOut;
959 // don't need to go below...
960 return;
964 // Clip By Patch Pass.
965 //--------------------
966 if(ClipResult==ClipOut)
968 H_AUTO( NLMISC_ClipZone_Out );
970 // Set All RenderClip flags to true.
971 _PatchRenderClipped.setAll();
973 else if(ClipResult==ClipIn)
975 H_AUTO( NLMISC_ClipZone_In );
977 // Set All RenderClip flags to false.
978 _PatchRenderClipped.clearAll();
980 else
982 H_AUTO( NLMISC_ClipZone_Side );
984 // Copy only the pyramid planes of interest
985 patchPyramid.resize(patchPyramidIndex.size());
986 uint i;
987 for(i=0;i<patchPyramidIndex.size();i++)
989 patchPyramid[i]= pyramid[patchPyramidIndex[i]];
992 // clip all patchs with the simplified pyramid
993 clipPatchs(patchPyramid);
997 // delete / reallocate / fill VBuffers.
998 //-------------------
999 // If there is a change in the Clip of the zone, or if patchs may have change (ie ClipSide is undetermined).
1000 if(oldClipResult!=ClipResult || oldClipResult==ClipSide)
1002 // get BitSet as Raw Array of uint32
1003 uint32 *oldRenderClip= const_cast<uint32*>(&_PatchOldRenderClipped.getVector()[0]);
1004 const uint32 *newRenderClip= &_PatchRenderClipped.getVector()[0];
1005 uint numPatchs= (uint)Patchs.size();
1006 // Then, we must test by patch.
1007 for(uint i=0;i<numPatchs;oldRenderClip++, newRenderClip++)
1009 uint32 oldWord= *oldRenderClip;
1010 uint32 newWord= *newRenderClip;
1011 // process at max 32 patch
1012 uint maxNumBits= min((numPatchs-i), 32U);
1013 uint32 mask= 1;
1014 for(;maxNumBits>0;maxNumBits--, mask<<=1, i++)
1016 // same as: if(_PatchOldRenderClipped[i] != _PatchRenderClipped[i])
1017 if( (oldWord^newWord)&mask )
1019 // set the flag.
1020 *oldRenderClip&= ~mask;
1021 *oldRenderClip|= newWord&mask;
1022 // update clip patch
1023 Patchs[i].updateClipPatchVB( (newWord&mask)!=0 );
1033 // ***************************************************************************
1034 void CZone::clipPatchs(const std::vector<CPlane> &pyramid)
1036 // Init all to Not clipped
1037 _PatchRenderClipped.clearAll();
1039 for(uint j=0;j<_PatchBSpheres.size();j++)
1041 CBSphere &bSphere= _PatchBSpheres[j];
1042 for(sint i=0;i<(sint)pyramid.size();i++)
1044 // If entirely out.
1045 if(!bSphere.clipBack(pyramid[i]))
1047 _PatchRenderClipped.set(j, true);
1048 break;
1055 // ***************************************************************************
1056 // DebugYoyo.
1057 // Code for Debug test Only.. Do not erase it, may be used later :)
1059 static void cleanTess(CTessFace *face)
1061 if(!face->isLeaf())
1063 cleanTess(face->SonLeft);
1064 cleanTess(face->SonRight);
1066 // If has father, clean it.
1067 if(face->Father)
1069 CTessFace *face1=face->Father;
1070 CTessFace *face2=face->Father->FBase;
1071 face1->FLeft= face1->SonLeft->FBase;
1072 face1->FRight= face1->SonRight->FBase;
1073 if(face2!=NULL)
1075 face2->FLeft= face2->SonLeft->FBase;
1076 face2->FRight= face2->SonRight->FBase;
1080 static void testTess(CTessFace *face)
1082 if(!face->isLeaf())
1084 testTess(face->SonLeft);
1085 testTess(face->SonRight);
1087 // Test validity.
1088 nlassert(!face->FBase || face->FBase->Patch!=(CPatch*)0xdddddddd);
1089 nlassert(!face->FLeft || face->FLeft->Patch!=(CPatch*)0xdddddddd);
1090 nlassert(!face->FRight || face->FRight->Patch!=(CPatch*)0xdddddddd);
1092 static void checkTess()
1094 // This test should be inserted at begin of CZone::refine().
1095 // And it needs hacking public/private.
1096 CPatch *pPatch;
1097 sint n;
1098 pPatch= &(*Patchs.begin());
1099 for(n=(sint)Patchs.size();n>0;n--, pPatch++)
1101 cleanTess(pPatch->Son0);
1102 cleanTess(pPatch->Son1);
1104 pPatch= &(*Patchs.begin());
1105 for(n=(sint)Patchs.size();n>0;n--, pPatch++)
1107 testTess(pPatch->Son0);
1108 testTess(pPatch->Son1);
1114 // ***************************************************************************
1115 void CZone::excludePatchFromRefineAll(uint patch, bool exclude)
1117 nlassert(Compiled);
1118 nlassert(patch<Patchs.size());
1120 if(patch>=Patchs.size())
1121 return;
1123 Patchs[patch].ExcludeFromRefineAll= exclude;
1127 // ***************************************************************************
1128 void CZone::refineAll()
1130 nlassert(Compiled);
1132 if(Patchs.empty())
1133 return;
1135 // DO NOT do a forceNoRenderClip(), to avoid big allocation of Near/Far VB vertices in driver.
1136 // DO NOT modify ClipResult, to avoid big allocation of Near/Far VB vertices in driver.
1138 // refine ALL patchs (even those which may be invisible).
1139 CPatch *pPatch= &(*Patchs.begin());
1140 sint n;
1141 for(n=(sint)Patchs.size();n>0;n--, pPatch++)
1143 // For Pacs construction: may exclude some patch from refineAll (for speed improvement).
1144 if(!pPatch->ExcludeFromRefineAll)
1145 pPatch->refineAll();
1151 // ***************************************************************************
1152 void CZone::averageTesselationVertices()
1154 nlassert(Compiled);
1156 if(Patchs.empty())
1157 return;
1159 // averageTesselationVertices of ALL patchs.
1160 CPatch *pPatch= &(*Patchs.begin());
1161 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
1163 pPatch->averageTesselationVertices();
1168 // ***************************************************************************
1169 void CZone::preRender()
1171 nlassert(Compiled);
1173 // Must be 2^X-1.
1174 static const uint updateFarRefineFreq= 15;
1175 // Take the renderDate here.
1176 uint curDateMod= CLandscapeGlobals::CurrentRenderDate & updateFarRefineFreq;
1178 // If no patchs, do nothing.
1179 if(Patchs.empty())
1180 return;
1182 /* If patchs invisible, must still update their Far Textures,
1183 else, there may be slowdown when we turn the head.
1187 // If all the zone is invisible.
1188 if(ClipResult==ClipOut)
1190 // No patchs are visible, but maybe update the far textures.
1191 if( curDateMod==(ZoneId & updateFarRefineFreq) )
1193 // updateTextureFarOnly for all patchs.
1194 for(uint i=0;i<Patchs.size();i++)
1196 Patchs[i].updateTextureFarOnly(_PatchBSpheres[i]);
1200 // else If some patchs only are visible.
1201 else if(ClipResult==ClipSide)
1203 // PreRender Pass, or updateTextureFarOnly(), according to _PatchRenderClipped state.
1204 for(uint i=0;i<Patchs.size();i++)
1206 // If the patch is visible
1207 if(!_PatchRenderClipped[i])
1209 // Then preRender it.
1210 Patchs[i].preRender(_PatchBSpheres[i]);
1212 else
1214 // else maybe updateFar it.
1215 // ZoneId+i for better repartition.
1216 if( curDateMod==((ZoneId+i) & updateFarRefineFreq) )
1217 Patchs[i].updateTextureFarOnly(_PatchBSpheres[i]);
1221 else // ClipResult==ClipIn
1223 // PreRender Pass for All
1224 for(uint i=0;i<Patchs.size();i++)
1226 Patchs[i].preRender(_PatchBSpheres[i]);
1233 // ***************************************************************************
1234 void CZone::resetRenderFarAndDeleteVBFV()
1236 for(uint i=0;i<Patchs.size();i++)
1238 // If patch is visible
1239 if(!_PatchRenderClipped[i])
1241 // release VertexBuffer, and FaceBuffer
1242 Patchs[i].deleteVBAndFaceVector();
1243 // Flag.
1244 _PatchRenderClipped.set(i, true);
1247 Patchs[i].resetRenderFar();
1252 // ***************************************************************************
1253 void CZone::forceMergeAtTileLevel()
1255 CPatch *pPatch=0;
1257 if (!Patchs.empty())
1258 pPatch= &(*Patchs.begin());
1260 for(sint n=(sint)Patchs.size();n>0;n--, pPatch++)
1262 pPatch->forceMergeAtTileLevel();
1267 // ***************************************************************************
1268 // ***************************************************************************
1269 // Misc part.
1270 // ***************************************************************************
1271 // ***************************************************************************
1274 // ***************************************************************************
1275 void CZone::changePatchTextureAndColor (sint numPatch, const std::vector<CTileElement> *tiles, const std::vector<CTileColor> *colors)
1277 nlassert(numPatch>=0);
1278 nlassert(numPatch<getNumPatchs());
1281 // Update the patch texture.
1282 if (tiles)
1284 nlassert( Patchs[numPatch].Tiles.size() == tiles->size() );
1285 Patchs[numPatch].Tiles = *tiles;
1288 // Update the patch colors.
1289 if (colors)
1291 nlassert( Patchs[numPatch].TileColors.size() == colors->size() );
1292 Patchs[numPatch].TileColors = *colors;
1295 if (Compiled)
1297 // If the patch is visible, then we must LockBuffers, because new VertexVB may be created.
1298 if(!_PatchRenderClipped[numPatch])
1299 Landscape->updateGlobalsAndLockBuffers(CVector::Null);
1301 // Recompute UVs for new setup of Tiles.
1302 Patchs[numPatch].deleteTileUvs();
1303 Patchs[numPatch].recreateTileUvs();
1305 // unlockBuffers() if necessary.
1306 if(!_PatchRenderClipped[numPatch])
1308 Landscape->unlockBuffers();
1309 // This patch is visible, and TileFaces have been deleted / added.
1310 // So must update TessBlock.
1311 Landscape->updateTessBlocksFaceVector();
1317 // ***************************************************************************
1318 void CZone::refreshTesselationGeometry(sint numPatch)
1320 nlassert(numPatch>=0);
1321 nlassert(numPatch<getNumPatchs());
1322 nlassert(Compiled);
1324 // At next render, we must re-fill the entire unclipped VB, so change are taken into account.
1325 Landscape->_RenderMustRefillVB= true;
1327 Patchs[numPatch].refreshTesselationGeometry();
1331 // ***************************************************************************
1332 const std::vector<CTileElement> &CZone::getPatchTexture(sint numPatch) const
1334 nlassert(numPatch>=0);
1335 nlassert(numPatch<getNumPatchs());
1337 // Update the patch texture.
1338 return Patchs[numPatch].Tiles;
1342 // ***************************************************************************
1343 const std::vector<CTileColor> &CZone::getPatchColor(sint numPatch) const
1345 nlassert(numPatch>=0);
1346 nlassert(numPatch<getNumPatchs());
1348 // Update the patch texture.
1349 return Patchs[numPatch].TileColors;
1352 // ***************************************************************************
1353 void CZone::setTileColor(bool monochrome, float factor)
1355 nlassert(factor >= 0.0f); // factor must not be negative as its a multiplier
1357 if (monochrome)
1359 for (uint32 i = 0; i < Patchs.size(); ++i)
1361 vector<CTileColor> &rTC = Patchs[i].TileColors;
1362 for (uint32 j = 0; j < rTC.size(); ++j)
1364 float fR = (rTC[j].Color565 & 31) / 32.0f;
1365 float fG = ((rTC[j].Color565 >> 5) & 63) / 64.0f;
1366 float fB = ((rTC[j].Color565 >> 11) & 31) / 32.0f;
1368 fR = 0.28f * fR + 0.59f * fG + 0.13f * fB;
1370 nlassert(fR < 0.99f);
1372 fR *= factor;
1373 if (fR > 0.99f) fR = 0.99f; // Avoid reaching 1
1375 uint16 nR = (uint16)(fR * 32.0f);
1376 uint16 nG = (uint16)(fR * 64.0f);
1377 uint16 nB = (uint16)(fR * 32.0f);
1379 rTC[j].Color565 = nR + (nG << 5) + (nB << 11);
1383 else
1385 if (factor != 1.0f)
1387 for (uint32 i = 0; i < Patchs.size(); ++i)
1389 vector<CTileColor> &rTC = Patchs[i].TileColors;
1390 for (uint32 j = 0; j < rTC.size(); ++j)
1392 float fR = (rTC[j].Color565 & 31) / 32.0f;
1393 float fG = ((rTC[j].Color565 >> 5) & 63) / 64.0f;
1394 float fB = ((rTC[j].Color565 >> 11) & 31) / 32.0f;
1396 fR *= factor;
1397 fG *= factor;
1398 fB *= factor;
1400 if (fR > 0.99f) fR = 0.99f;
1401 if (fG > 0.99f) fG = 0.99f;
1402 if (fB > 0.99f) fB = 0.99f;
1404 uint16 nR = (uint16)(fR * 32.0f);
1405 uint16 nG = (uint16)(fG * 64.0f);
1406 uint16 nB = (uint16)(fB * 32.0f);
1408 rTC[j].Color565 = nR + (nG << 5) + (nB << 11);
1415 // ***************************************************************************
1416 void CZone::debugBinds(FILE *f)
1418 fprintf(f, "*****************************\n");
1419 fprintf(f, "ZoneId: %d. NPatchs:%u\n", ZoneId, (uint)PatchConnects.size());
1420 sint i;
1421 for(i=0;i<(sint)PatchConnects.size();i++)
1423 CPatchConnect &pc= PatchConnects[i];
1424 fprintf(f, "patch%d:\n", i);
1425 for(sint j=0;j<4;j++)
1427 CPatchInfo::CBindInfo &bd= pc.BindEdges[j];
1428 fprintf(f, " edge%d: Zone:%u. NPatchs:%u. ", j, (uint)bd.ZoneId, (uint)bd.NPatchs);
1429 for(sint k=0;k<bd.NPatchs;k++)
1431 fprintf(f, "p%ue%u - ", (uint)bd.Next[k], (uint)bd.Edge[k]);
1433 fprintf(f, "\n");
1437 fprintf(f,"Vertices :\n");
1438 for(i=0;i<(sint)BorderVertices.size();i++)
1440 fprintf(f,"current : %u -> (zone %u) vertex %u\n", (uint)BorderVertices[i].CurrentVertex,
1441 (uint)BorderVertices[i].NeighborZoneId,
1442 (uint)BorderVertices[i].NeighborVertex);
1447 // ***************************************************************************
1448 void CZone::applyHeightField(const CLandscape &landScape)
1450 sint i,j;
1451 vector<CBezierPatch> patchs;
1453 // no patch, do nothing.
1454 if(Patchs.empty())
1455 return;
1457 // 0. Unpack patchs to Bezier Patchs.
1458 //===================================
1459 patchs.resize(Patchs.size());
1460 for(j=0;j<(sint)patchs.size();j++)
1462 CBezierPatch &p= patchs[j];
1463 CPatch &pa= Patchs[j];
1465 // re-Build the uncompressed bezier patch.
1466 for(i=0;i<4;i++)
1467 pa.Vertices[i].unpack(p.Vertices[i], PatchBias, PatchScale);
1468 for(i=0;i<8;i++)
1469 pa.Tangents[i].unpack(p.Tangents[i], PatchBias, PatchScale);
1470 for(i=0;i<4;i++)
1471 pa.Interiors[i].unpack(p.Interiors[i], PatchBias, PatchScale);
1474 // 1. apply heightfield on bezier patchs.
1475 //===================================
1476 for(j=0;j<(sint)patchs.size();j++)
1478 CBezierPatch &p= patchs[j];
1480 // apply delta.
1481 for(i=0;i<4;i++)
1482 p.Vertices[i]+= landScape.getHeightFieldDeltaZ(p.Vertices[i].x, p.Vertices[i].y);
1483 for(i=0;i<8;i++)
1484 p.Tangents[i]+= landScape.getHeightFieldDeltaZ(p.Tangents[i].x, p.Tangents[i].y);
1485 for(i=0;i<4;i++)
1486 p.Interiors[i]+= landScape.getHeightFieldDeltaZ(p.Interiors[i].x, p.Interiors[i].y);
1490 // 2. Re-compute Patch Scale/Bias, and Zone BBox.
1491 //===================================
1492 CAABBox bb;
1493 bb.setCenter(patchs[0].Vertices[0]);
1494 bb.setHalfSize(CVector::Null);
1495 for(j=0;j<(sint)patchs.size();j++)
1497 // extend bbox.
1498 const CBezierPatch &p= patchs[j];
1499 for(i=0;i<4;i++)
1500 bb.extend(p.Vertices[i]);
1501 for(i=0;i<8;i++)
1502 bb.extend(p.Tangents[i]);
1503 for(i=0;i<4;i++)
1504 bb.extend(p.Interiors[i]);
1506 // Compute BBox, and Patch Scale Bias, according to Noise.
1507 computeBBScaleBias(bb);
1510 // 3. Re-pack patchs.
1511 //===================================
1512 for(j=0;j<(sint)patchs.size();j++)
1514 CBezierPatch &p= patchs[j];
1515 CPatch &pa= Patchs[j];
1517 // Build the packed patch.
1518 for(i=0;i<4;i++)
1519 pa.Vertices[i].pack(p.Vertices[i], PatchBias, PatchScale);
1520 for(i=0;i<8;i++)
1521 pa.Tangents[i].pack(p.Tangents[i], PatchBias, PatchScale);
1522 for(i=0;i<4;i++)
1523 pa.Interiors[i].pack(p.Interiors[i], PatchBias, PatchScale);
1527 // ***************************************************************************
1528 void CZone::setupColorsFromTileFlags(const NLMISC::CRGBA colors[4])
1530 for (uint k = 0; k < Patchs.size(); ++k)
1532 Patchs[k].setupColorsFromTileFlags(colors);
1537 // ***************************************************************************
1538 void CZone::copyTilesFlags(sint destPatchId, const CPatch *srcPatch)
1540 CPatch *destPatch = getPatch(destPatchId);
1542 destPatch->copyTileFlagsFromPatch(srcPatch);
1546 // ***************************************************************************
1547 bool CPatchInfo::getNeighborTile (uint patchId, uint edge, sint position, uint &patchOut, sint &sOut, sint &tOut,
1548 const vector<CPatchInfo> &patchInfos) const
1550 nlassert (edge<4);
1552 // S or T ?
1553 uint length = (edge&1) ? OrderS : OrderT;
1554 nlassert ((uint)position<length);
1556 // What kind of case ?
1557 switch (BindEdges[edge].NPatchs)
1559 case 1:
1560 case 2:
1561 case 4:
1563 // Get neighbor index and position in neighbor
1564 uint neighborLength = (length / BindEdges[edge].NPatchs);
1565 uint neighbor = position / neighborLength;
1566 uint neighborPosition = neighborLength - (position % neighborLength) - 1;
1567 uint neighborEdge = BindEdges[edge].Edge[neighbor];
1569 // Patch id
1570 patchOut = BindEdges[edge].Next[neighbor];
1572 // Check neighbor
1573 uint neighborRealLength = (neighborEdge&1) ? patchInfos[patchOut].OrderS : patchInfos[patchOut].OrderT;
1574 if (neighborRealLength == neighborLength)
1576 // Get final coordinate
1577 switch (neighborEdge)
1579 case 0:
1580 sOut = 0;
1581 tOut = neighborPosition;
1582 break;
1583 case 1:
1584 sOut = neighborPosition;
1585 tOut = patchInfos[patchOut].OrderT-1;
1586 break;
1587 case 2:
1588 sOut = patchInfos[patchOut].OrderS-1;
1589 tOut = patchInfos[patchOut].OrderT-neighborPosition-1;
1590 break;
1591 case 3:
1592 sOut = patchInfos[patchOut].OrderS-neighborPosition-1;
1593 tOut = 0;
1594 break;
1597 // Ok todo remove
1598 return true;
1601 break;
1603 case 5:
1605 // Find in the neighbor where we are
1606 patchOut = BindEdges[edge].Next[0];
1607 uint neighborEdge = BindEdges[edge].Edge[0];
1608 uint neighborEdgeCount = patchInfos[patchOut].BindEdges[neighborEdge].NPatchs;
1610 // Check neighbor
1611 uint neighborRealLength = (neighborEdge&1) ? patchInfos[patchOut].OrderS : patchInfos[patchOut].OrderT;
1613 // Good length ?
1614 if ((neighborRealLength / neighborEdgeCount) == length)
1616 // Find us in the neighbor
1617 uint neighborPosition;
1618 for (neighborPosition=0; neighborPosition<neighborEdgeCount; neighborPosition++)
1620 // Found ?
1621 if (patchInfos[patchOut].BindEdges[neighborEdge].Next[neighborPosition] == patchId)
1622 break;
1625 // Must be found
1626 nlassert (neighborPosition!=neighborEdgeCount);
1627 neighborPosition = (neighborPosition + 1) * (neighborRealLength / neighborEdgeCount) - position - 1;
1629 // Get final coordinate
1630 switch (neighborEdge)
1632 case 0:
1633 sOut = 0;
1634 tOut = neighborPosition;
1635 break;
1636 case 1:
1637 sOut = neighborPosition;
1638 tOut = patchInfos[patchOut].OrderT-1;
1639 break;
1640 case 2:
1641 sOut = patchInfos[patchOut].OrderS-1;
1642 tOut = patchInfos[patchOut].OrderT-neighborPosition-1;
1643 break;
1644 case 3:
1645 sOut = patchInfos[patchOut].OrderS-neighborPosition-1;
1646 tOut = 0;
1647 break;
1650 // Ok
1651 return true;
1654 break;
1657 return false;
1661 // ***************************************************************************
1663 bool CPatchInfo::getTileSymmetryRotate (const CTileBank &bank, uint tile, bool &symmetry, uint &rotate)
1665 // Need check the tile ?
1666 if ( (symmetry || (rotate != 0)) && (tile != 0xffffffff) )
1668 // Tile exist ?
1669 if (tile < (uint)bank.getTileCount())
1671 // Get xref
1672 int tileSet;
1673 int number;
1674 CTileBank::TTileType type;
1676 // Get tile xref
1677 bank.getTileXRef ((int)tile, tileSet, number, type);
1679 if ((tileSet < 0) || (tileSet >= bank.getTileSetCount()))
1681 nlwarning("tile %d has an unknown tileSet (%d)",tile, tileSet);
1682 return false;
1685 // Is it an oriented tile ?
1686 if (bank.getTileSet (tileSet)->getOriented())
1688 // New rotation value
1689 rotate = 0;
1692 // Ok
1693 return true;
1696 return false;
1698 else
1699 return true;
1702 // ***************************************************************************
1704 bool CPatchInfo::transformTile (const CTileBank &bank, uint &tile, uint &tileRotation, bool symmetry, uint rotate, bool goofy)
1706 // Tile exist ?
1707 if ( (rotate!=0) || symmetry )
1709 if (tile < (uint)bank.getTileCount())
1711 // Get xref
1712 int tileSet;
1713 int number;
1714 CTileBank::TTileType type;
1716 // Get tile xref
1717 bank.getTileXRef ((int)tile, tileSet, number, type);
1719 // Transition ?
1720 if (type == CTileBank::transition)
1722 // Rotation for transition
1723 uint transRotate = rotate;
1725 // Number should be ok
1726 nlassert (number>=0);
1727 nlassert (number<CTileSet::count);
1729 // Tlie set number
1730 const CTileSet *pTileSet = bank.getTileSet (tileSet);
1732 // Get border desc
1733 CTileSet::TFlagBorder oriented[4] =
1735 pTileSet->getOrientedBorder (CTileSet::left, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::left)),
1736 pTileSet->getOrientedBorder (CTileSet::bottom, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::bottom)),
1737 pTileSet->getOrientedBorder (CTileSet::right, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::right)),
1738 pTileSet->getOrientedBorder (CTileSet::top, CTileSet::getEdgeType ((CTileSet::TTransition)number, CTileSet::top))
1741 // Symmetry ?
1742 if (symmetry)
1744 if ( (tileRotation & 1) ^ goofy )
1746 CTileSet::TFlagBorder tmp = oriented[1];
1747 oriented[1] = CTileSet::getInvertBorder (oriented[3]);
1748 oriented[3] = CTileSet::getInvertBorder (tmp);
1749 oriented[2] = CTileSet::getInvertBorder (oriented[2]);
1750 oriented[0] = CTileSet::getInvertBorder (oriented[0]);
1752 else
1754 CTileSet::TFlagBorder tmp = oriented[0];
1755 oriented[0] = CTileSet::getInvertBorder (oriented[2]);
1756 oriented[2] = CTileSet::getInvertBorder (tmp);
1757 oriented[1] = CTileSet::getInvertBorder (oriented[1]);
1758 oriented[3] = CTileSet::getInvertBorder (oriented[3]);
1762 // Rotation
1763 CTileSet::TFlagBorder edges[4];
1764 edges[0] = pTileSet->getOrientedBorder (CTileSet::left, oriented[(0 + transRotate )&3]);
1765 edges[1] = pTileSet->getOrientedBorder (CTileSet::bottom, oriented[(1 + transRotate )&3]);
1766 edges[2] = pTileSet->getOrientedBorder (CTileSet::right, oriented[(2 + transRotate )&3]);
1767 edges[3] = pTileSet->getOrientedBorder (CTileSet::top, oriented[(3 + transRotate )&3]);
1769 // Get the good tile number
1770 CTileSet::TTransition transition = pTileSet->getTransitionTile (edges[3], edges[1], edges[0], edges[2]);
1771 nlassert ((CTileSet::TTransition)transition != CTileSet::notfound);
1772 tile = (uint)(pTileSet->getTransition (transition)->getTile ());
1775 // Transform rotation: invert rotation
1776 tileRotation += rotate;
1778 // If goofy, add +2
1779 if (goofy && symmetry)
1780 tileRotation += 2;
1782 // Mask the rotation
1783 tileRotation &= 3;
1785 else
1786 return false;
1789 // Ok
1790 return true;
1793 // ***************************************************************************
1795 void CPatchInfo::transform256Case (const CTileBank &bank, uint8 &case256, uint tileRotation, bool symmetry, uint rotate, bool goofy)
1797 // Tile exist ?
1798 if ( (rotate!=0) || symmetry )
1800 // Symmetry ?
1801 if (symmetry)
1803 // Take the symmetry
1804 uint symArray[4] = {3, 2, 1, 0};
1805 case256 = symArray[case256];
1807 if (goofy && ((tileRotation & 1) ==0))
1808 case256 += 2;
1809 if ((!goofy) && (tileRotation & 1))
1810 case256 += 2;
1813 // Rotation ?
1814 case256 -= rotate;
1815 case256 &= 3;
1819 // ***************************************************************************
1821 bool CPatchInfo::transform (std::vector<CPatchInfo> &patchInfo, NL3D::CZoneSymmetrisation &zoneSymmetry, const NL3D::CTileBank &bank, bool symmetry, uint rotate, float snapCell, float weldThreshold, const NLMISC::CMatrix &toOriginalSpace)
1823 uint patchCount = (uint)patchInfo.size ();
1824 uint i;
1826 // --- Export tile info Symmetry of the bind info.
1827 // --- Parse each patch and each edge
1829 // For each patches
1830 NL3D::CZoneSymmetrisation::CError error;
1832 // Build the structure
1833 if (!zoneSymmetry.build (patchInfo, snapCell, weldThreshold, bank, error, toOriginalSpace))
1835 return false;
1838 // Symmetry ?
1839 if (symmetry)
1841 for(i=0 ; i<patchCount; i++)
1843 // Ref on the current patch
1844 CPatchInfo &pi = patchInfo[i];
1846 // --- Symmetry vertex indexes
1848 // Vertices
1849 CVector tmp = pi.Patch.Vertices[0];
1850 pi.Patch.Vertices[0] = pi.Patch.Vertices[3];
1851 pi.Patch.Vertices[3] = tmp;
1852 tmp = pi.Patch.Vertices[1];
1853 pi.Patch.Vertices[1] = pi.Patch.Vertices[2];
1854 pi.Patch.Vertices[2] = tmp;
1856 // Tangents
1857 tmp = pi.Patch.Tangents[0];
1858 pi.Patch.Tangents[0] = pi.Patch.Tangents[5];
1859 pi.Patch.Tangents[5] = tmp;
1860 tmp = pi.Patch.Tangents[1];
1861 pi.Patch.Tangents[1] = pi.Patch.Tangents[4];
1862 pi.Patch.Tangents[4] = tmp;
1863 tmp = pi.Patch.Tangents[2];
1864 pi.Patch.Tangents[2] = pi.Patch.Tangents[3];
1865 pi.Patch.Tangents[3] = tmp;
1866 tmp = pi.Patch.Tangents[6];
1867 pi.Patch.Tangents[6] = pi.Patch.Tangents[7];
1868 pi.Patch.Tangents[7] = tmp;
1870 // Interior
1871 tmp = pi.Patch.Interiors[0];
1872 pi.Patch.Interiors[0] = pi.Patch.Interiors[3];
1873 pi.Patch.Interiors[3] = tmp;
1874 tmp = pi.Patch.Interiors[1];
1875 pi.Patch.Interiors[1] = pi.Patch.Interiors[2];
1876 pi.Patch.Interiors[2] = tmp;
1878 // ** Symmetries tile colors
1880 uint u,v;
1881 uint countU = pi.OrderS/2+1;
1882 uint countV = pi.OrderT+1;
1883 for (v=0; v<countV; v++)
1884 for (u=0; u<countU; u++)
1886 // Store it in the tile info
1887 uint index0 = u+v*(pi.OrderS+1);
1888 uint index1 = (pi.OrderS-u)+v*(pi.OrderS+1);
1890 // XChg
1891 uint16 tmp = pi.TileColors[index0].Color565;
1892 pi.TileColors[index0].Color565 = pi.TileColors[index1].Color565;
1893 pi.TileColors[index1].Color565 = tmp;
1896 // Smooth flags
1897 uint flags = (uint)(pi.getSmoothFlag (0))<<2;
1898 flags |= (uint)(pi.getSmoothFlag (2))<<0;
1899 flags |= (uint)(pi.getSmoothFlag (1))<<1;
1900 flags |= (uint)(pi.getSmoothFlag (3))<<3;
1901 pi.Flags &= ~3;
1902 pi.Flags |= flags;
1905 // --- Symmetry of the bind info.
1906 // --- Parse each patch and each edge
1907 // For each patches
1908 for (i=0 ; i<patchCount; i++)
1910 // Ref on the patch info
1911 CPatchInfo &pi = patchInfo[i];
1913 // Xchg left and right
1914 swap (pi.BindEdges[0], pi.BindEdges[2]);
1915 swap (pi.BaseVertices[0], pi.BaseVertices[3]);
1916 swap (pi.BaseVertices[1], pi.BaseVertices[2]);
1918 // Flip edges
1919 for (uint edge=0; edge<4; edge++)
1921 // Ref on the patch info
1922 CPatchInfo::CBindInfo &bindEdge = pi.BindEdges[edge];
1924 uint next;
1925 // Look if it is a bind ?
1926 if ( (bindEdge.NPatchs>1) && (bindEdge.NPatchs!=5) )
1928 for (next=0; next<(uint)bindEdge.NPatchs/2; next++)
1930 swap (bindEdge.Next[bindEdge.NPatchs - next - 1], bindEdge.Next[next]);
1931 swap (bindEdge.Edge[bindEdge.NPatchs - next - 1], bindEdge.Edge[next]);
1935 // Look if we are binded on a reversed edge
1936 uint bindCount = (bindEdge.NPatchs==5) ? 1 : bindEdge.NPatchs;
1937 for (next=0; next<bindCount; next++)
1939 // Left or right ?
1940 if ( (bindEdge.Edge[next] & 1) == 0)
1942 // Invert
1943 bindEdge.Edge[next] += 2;
1944 bindEdge.Edge[next] &= 3;
1951 // For each patches
1952 for (i=0 ; i<patchCount; i++)
1954 // Tile infos
1955 CPatchInfo &pi = patchInfo[i];
1957 // Backup tiles
1958 std::vector<CTileElement> tiles = pi.Tiles;
1960 int u,v;
1961 for (v=0; v<pi.OrderT; v++)
1962 for (u=0; u<pi.OrderS; u++)
1964 // U tile
1965 int uSymmetry = symmetry ? (pi.OrderS-u-1) : u;
1967 // Destination tile
1968 CTileElement &element = pi.Tiles[u+v*pi.OrderS];
1970 // Copy the orginal symmetrical element
1971 element = tiles[uSymmetry+v*pi.OrderS];
1973 // For each layer
1974 for (int l=0; l<3; l++)
1976 // Empty ?
1977 if (element.Tile[l] != 0xffff)
1979 // Get the tile index
1980 uint tile = element.Tile[l];
1981 uint tileRotation = element.getTileOrient (l);
1983 // Get rot and symmetry for this tile
1984 uint tileRotate = rotate;
1985 bool tileSymmetry = symmetry;
1986 bool goofy = symmetry && (zoneSymmetry.getTileState (i, uSymmetry+v*pi.OrderS, l) == CZoneSymmetrisation::Goofy);
1988 // Transform the transfo
1989 if (getTileSymmetryRotate (bank, tile, tileSymmetry, tileRotate))
1991 // Transform the tile
1992 if (!transformTile (bank, tile, tileRotation, tileSymmetry, (4-tileRotate)&3, goofy))
1994 // Info
1995 nlwarning ("Error getting symmetrical / rotated zone tile.");
1996 return false;
1999 else
2001 // Info
2002 nlwarning ("Error getting symmetrical / rotated zone tile.");
2003 return false;
2006 // Set the tile
2007 element.Tile[l] = tile;
2008 element.setTileOrient (l, (uint8)tileRotation);
2012 // Empty ?
2013 if (element.Tile[0]!=0xffff)
2015 // Get 256 info
2016 bool is256x256;
2017 uint8 uvOff;
2018 element.getTile256Info (is256x256, uvOff);
2020 // 256 ?
2021 if (is256x256)
2023 // Get rot and symmetry for this tile
2024 uint tileRotate = rotate;
2025 bool tileSymmetry = symmetry;
2026 uint tileRotation = tiles[uSymmetry+v*pi.OrderS].getTileOrient (0);
2027 bool goofy = symmetry && (zoneSymmetry.getTileState (i, uSymmetry+v*pi.OrderS, 0) == CZoneSymmetrisation::Goofy);
2029 // Transform the transfo
2030 getTileSymmetryRotate (bank, element.Tile[0], tileSymmetry, tileRotate);
2032 // Transform the case
2033 transform256Case (bank, uvOff, tileRotation, tileSymmetry, (4-tileRotate)&3, goofy);
2035 element.setTile256Info (true, uvOff);
2041 // Ok
2042 return true;
2045 // ***************************************************************************
2047 } // NL3D