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/tile_noise_map.h"
28 #include "nel/3d/patchuv_locator.h"
31 using namespace NLMISC
;
41 // ***************************************************************************
44 #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) && defined(NL_USE_FASTFLOOR)
46 /* This floor works only for floor with noise, because floor/ceil are only made on decimal coordinates:
47 sTile =1.25 .... NB: because of difference of mapping (rare case), we may have sometimes values with
48 precision < 1/4 (eg 1.125). Just use f*256 to compute the floor.
50 NB: using a fastFloor() (fistp changing the controlfp() is not very a good idea here, because
51 computeNoise() are not "packed", so change on controlFp() would bee too frequent...
52 And also because we need either floor() or ceil() here.
54 inline sint
noiseFloor(float f
)
56 // build a fixed 24:8.
60 // fast ftol. work if no decimal.
74 inline sint
noiseCeil(float f
)
76 // build a fixed 24:8.
80 // fast ftol. work if no decimal.
95 inline float noiseFloorF(float f
)
97 return (float)noiseFloor(f
);
99 inline float noiseCeilF(float f
)
101 return (float)noiseCeil(f
);
108 inline float noiseFloorF(float f
)
110 return (float)floor(f
);
112 inline float noiseCeilF(float f
)
114 return (float)ceil(f
);
117 inline sint
noiseFloor(float f
)
119 return (sint
)floor(f
);
121 inline sint
noiseCeil(float f
)
123 return (sint
)ceil(f
);
130 // ***************************************************************************
131 float CPatch::computeDisplaceRawInteger(sint ts
, sint tt
, sint ms
, sint mt
) const
133 // Choose the noiseMap.
134 // ===============================
135 clamp(ts
, 0, OrderS
-1);
136 clamp(tt
, 0, OrderT
-1);
138 uint tileId
= tt
*OrderS
+ ts
;
139 // Get the tile for pass0. This is the principal tile, and this one tells what noise to take.
140 sint tileNumber
= Tiles
[tileId
].Tile
[0];
141 // Get the subNoise from tileElement.
142 uint tileSubNoise
= Tiles
[tileId
].getTileSubNoise();
144 // retrieve the wanted noiseMap.
145 CTileNoiseMap
*noiseMap
;
146 noiseMap
= getZone()->getLandscape()->TileBank
.getTileNoiseMap (tileNumber
, tileSubNoise
);
148 if (noiseMap
== NULL
)
151 // Sample the noiseMap with (s,t).
152 // ===============================
155 sint8 pix
= noiseMap
->Pixels
[mt
*NL3D_TILE_NOISE_MAP_SIZE
+ ms
];
158 return (float)pix
* (NL3D_NOISE_MAX
/ 127.f
);
162 // ***************************************************************************
163 void CPatch::computeDisplaceRawCoordinates(float sTile
, float tTile
, float s
, float t
,
164 sint
&ts
, sint
&tt
, sint
&ms
, sint
&mt
) const
166 // Choose the noiseMap.
167 // ===============================
168 // Compute coordinate in the patch.
169 ts
= noiseFloor(sTile
);
170 tt
= noiseFloor(tTile
);
173 // Sample the noiseMap with (s,t).
174 // ===============================
177 float u
= s
* NL3D_TILE_NOISE_MAP_TILE_FACTOR
;
178 float v
= t
* NL3D_TILE_NOISE_MAP_TILE_FACTOR
;
182 switch(NoiseRotation
& 3)
189 uv
.U
= NL3D_TILE_NOISE_MAP_SIZE
-v
;
193 uv
.U
= NL3D_TILE_NOISE_MAP_SIZE
-u
;
194 uv
.V
= NL3D_TILE_NOISE_MAP_SIZE
-v
;
198 uv
.V
= NL3D_TILE_NOISE_MAP_SIZE
-u
;
202 // direct map (no bilinear, no round, the case where s,t < 1/4 of a tile is very rare).
203 ms
= noiseFloor(uv
.U
);
204 mt
= noiseFloor(uv
.V
);
206 // Manage Tiling (add NL3D_TILE_NOISE_MAP_SIZE*1 should be sufficient, but take margin).
207 ms
= (ms
+ (NL3D_TILE_NOISE_MAP_SIZE
*256)) & (NL3D_TILE_NOISE_MAP_SIZE
-1);
208 mt
= (mt
+ (NL3D_TILE_NOISE_MAP_SIZE
*256)) & (NL3D_TILE_NOISE_MAP_SIZE
-1);
213 // ***************************************************************************
214 float CPatch::computeDisplaceRaw(float sTile
, float tTile
, float s
, float t
) const
217 computeDisplaceRawCoordinates(sTile
, tTile
, s
, t
, ts
, tt
, ms
, mt
);
218 return computeDisplaceRawInteger(ts
, tt
, ms
, mt
);
222 // ***************************************************************************
223 static inline void computeDisplaceBilinear(float sTile
, float tTile
,
224 float &sInc
, float &tInc
, float &sa
, float &ta
, float &sa1
, float &ta1
)
226 float sDecimal
= sTile
-noiseFloor(sTile
);
227 float tDecimal
= tTile
-noiseFloor(tTile
);
230 // Do a bilinear centered on 0.5, 0.5.
232 // Compute increment, according to position against center.
242 // Compute weight factor.
243 sDist
= (float)fabs(0.5 - sDecimal
); // s distance from center.
244 tDist
= (float)fabs(0.5 - tDecimal
); // t distance from center.
252 // ***************************************************************************
253 float CPatch::computeDisplaceInteriorSmooth(float s
, float t
) const
259 // compute bi-linear weight factors.
260 float sInc
, tInc
, sa
, ta
, sa1
, ta1
;
261 computeDisplaceBilinear(sTile
, tTile
, sInc
, tInc
, sa
, ta
, sa1
, ta1
);
264 // NB: to have smooth transition, must keep the same (s,t), so we do a transition with the noise tile of
265 // our neigbhor, but under us.
267 // speed up, using just one computeDisplaceRawCoordinates(), and multiple computeDisplaceRawInteger().
269 computeDisplaceRawCoordinates(sTile
, tTile
, s
, t
, ts
, tt
, ms
, mt
);
271 sint sIncInt
= (sint
) sInc
;
272 sint tIncInt
= (sint
) tInc
;
273 ret
= computeDisplaceRawInteger(ts
, tt
, ms
,mt
) * sa
* ta
;
274 ret
+= computeDisplaceRawInteger(ts
+sIncInt
, tt
, ms
,mt
) * sa1
* ta
;
275 ret
+= computeDisplaceRawInteger(ts
, tt
+tIncInt
, ms
,mt
) * sa
* ta1
;
276 ret
+= computeDisplaceRawInteger(ts
+sIncInt
, tt
+tIncInt
, ms
,mt
) * sa1
* ta1
;
282 // ***************************************************************************
283 float CPatch::computeDisplaceEdgeSmooth(float s
, float t
, sint8 smoothBorderX
, sint8 smoothBorderY
) const
290 // only one must be not null
291 nlassert( (smoothBorderX
==0) != (smoothBorderY
==0) );
294 // Get the edge against we must share displace.
295 if(smoothBorderX
==-1) edge
=0;
296 else if(smoothBorderY
==1) edge
=1;
297 else if(smoothBorderX
==1) edge
=2;
298 else if(smoothBorderY
==-1) edge
=3;
301 // Build the bindInfo against this edge.
302 getBindNeighbor(edge
, bindInfo
);
304 // Fast reject: if no neighbor, just do a simple computeDisplaceInteriorSmooth.
306 return computeDisplaceInteriorSmooth(s
, t
);
307 // else, look for result in neighborhood.
313 // compute bi-linear weight factors.
314 float sInc
, tInc
, sa
, ta
, sa1
, ta1
;
315 computeDisplaceBilinear(sTile
, tTile
, sInc
, tInc
, sa
, ta
, sa1
, ta1
);
316 // Manage limit case: if bilinear has not chosen the good direction (because of floor and orientation).
317 // eg on Right edge: This case arise if sDecimal==0, so if sa==sa1==0.5f. result is that
318 // smoothBorderX is != than sInc on right border. same reasoning with downBorder (smoothBorderY=1).
320 // NO NEED TO DO HERE, because sInc or tInc is not used if it is bad (smoothBorder? used instead).
321 // and no need to correct sa, sa1, because in this case they are both equal to 0.5.
324 // compute Neighboring info.
325 CPatchUVLocator uvLocator
;
326 uvLocator
.build(this, edge
, bindInfo
);
328 /* NB: there is floor problems with neighbors:
329 - difference of orientation => uv.v=1. This point to the 1th tile. But this is not the same, if
330 v goes to up, or goes to down.
331 - if multiple bind, problem at limit (eg a bind 1/2 on edge 0 with OrdertT=8, when uv.v= 4).
332 because, selection of the patch is dependent of orientation too.
333 To avoid them, just take center of (sTile, tTile) to remove ambiguity.
334 This works because computeDisplaceRaw() use sTile, tTile to get the noiseMap, so the decimal part is not
337 Notice that we do this AFTER computeDisplaceBilinear() of course.
339 sTile
= noiseFloor(sTile
) + 0.5f
;
340 tTile
= noiseFloor(tTile
) + 0.5f
;
341 // If we were exactly on the superior edge, prec compute is false... so correct this here.
342 if(sTile
>OrderS
) sTile
--;
343 if(tTile
>OrderT
) tTile
--;
346 // Bilinear across an edge (enjoy!!).
347 CVector2f stTileIn
, stIn
;
348 CVector2f stTileOut
, stOut
;
356 // compute contribution of our patch.
357 ret
= computeDisplaceRaw(sTile
,tTile
, s
,t
) * sa
* ta
;
358 ret
+= computeDisplaceRaw(sTile
,tTile
+tInc
, s
,t
) * sa
* ta1
;
360 // compute contribution of next(s) patchs.
362 // contribution of next at tTile.
363 // Keep the same coordinate.
365 // But look for the neighbor noise tile.
366 stTileIn
.set(sTile
+smoothBorderX
, tTile
);
367 // change basis: find the s,t on the neighbor patch.
368 patchId
= uvLocator
.selectPatch(stTileIn
);
369 uvLocator
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
370 uvLocator
.locateUV(stIn
, patchId
, patchOut
, stOut
);
371 // Compute displace, and bi-linear on the neighbor patch.
372 ret
+= patchOut
->computeDisplaceRaw(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
) * sa1
* ta
;
374 // contribution of next at tTile+tInc (same reasoning).
376 stTileIn
.set(sTile
+smoothBorderX
, tTile
+tInc
);
377 patchId
= uvLocator
.selectPatch(stTileIn
);
378 uvLocator
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
379 uvLocator
.locateUV(stIn
, patchId
, patchOut
, stOut
);
380 ret
+= patchOut
->computeDisplaceRaw(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
) * sa1
* ta1
;
383 // else if horizontal edge.
386 // same reasoning as above.
388 // compute contribution of our patch.
389 ret
= computeDisplaceRaw(sTile
, tTile
, s
,t
) * sa
* ta
;
390 ret
+= computeDisplaceRaw(sTile
+sInc
,tTile
, s
,t
) * sa1
* ta
;
392 // compute contribution of next(s) patchs.
393 // contribution of next at tTile.
395 stTileIn
.set(sTile
, tTile
+smoothBorderY
);
396 patchId
= uvLocator
.selectPatch(stTileIn
);
397 uvLocator
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
398 uvLocator
.locateUV(stIn
, patchId
, patchOut
, stOut
);
399 ret
+= patchOut
->computeDisplaceRaw(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
) * sa
* ta1
;
401 // contribution of next at tTile+tInc (same reasoning).
403 stTileIn
.set(sTile
+sInc
, tTile
+smoothBorderY
);
404 patchId
= uvLocator
.selectPatch(stTileIn
);
405 uvLocator
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
406 uvLocator
.locateUV(stIn
, patchId
, patchOut
, stOut
);
407 ret
+= patchOut
->computeDisplaceRaw(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
) * sa1
* ta1
;
416 // ***************************************************************************
417 float CPatch::computeDisplaceRawOnNeighbor(float sTile
, float tTile
, float s
, float t
) const
421 // look on what neighbor patch we must find the value (if any).
423 else if(tTile
>OrderT
) edge
=1;
424 else if(sTile
>OrderS
) edge
=2;
425 else if(tTile
<0) edge
=3;
427 // If the location is In the patch, just return normal value.
429 return computeDisplaceRaw(sTile
, tTile
, s
, t
);
430 // else must find on neighbor.
434 getBindNeighbor(edge
, bindInfo
);
436 // Fast reject: if no neighbor on the edge, just do a simple computeDisplaceRaw()
439 return computeDisplaceRaw(sTile
, tTile
, s
, t
);
441 // else must find on neighbor.
444 CPatchUVLocator uvLocator
;
445 uvLocator
.build(this, edge
, bindInfo
);
447 CVector2f stTileIn
, stIn
;
448 CVector2f stTileOut
, stOut
;
452 // look on neighbor. same reasoning as in computeDisplaceEdgeSmooth();
454 stTileIn
.set(sTile
, tTile
);
455 patchId
= uvLocator
.selectPatch(stTileIn
);
456 uvLocator
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
457 uvLocator
.locateUV(stIn
, patchId
, patchOut
, stOut
);
458 return patchOut
->computeDisplaceRaw(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
);
465 // ***************************************************************************
466 float CPatch::computeDisplaceCornerSmooth(float s
, float t
, sint8 smoothBorderX
, sint8 smoothBorderY
) const
468 // compute the value across the corner (enjoy!!)
469 // NB: Only corners with Edges==4 and corners on a bind are correclty supported.
470 // ignore problems with corner which nbEdges!=4, because Blend of normals blend to 0 on corner (see computenoise()).
479 // both must be not null
480 nlassert( (smoothBorderX
!=0) && (smoothBorderY
!=0) );
483 // Get the edge against we must share displace.
484 if(smoothBorderX
==-1) edgeX
=0;
485 else if(smoothBorderX
==1) edgeX
=2;
487 if(smoothBorderY
==1) edgeY
=1;
488 else if(smoothBorderY
==-1) edgeY
=3;
491 // Build the bindInfo against those 2 edge.
492 getBindNeighbor(edgeX
, bindInfoX
);
493 getBindNeighbor(edgeY
, bindInfoY
);
495 // Fast reject: if no neighbor on one of the edge, just do a simple computeDisplaceInteriorSmooth.
496 if(!bindInfoX
.Zone
|| !bindInfoY
.Zone
)
497 return computeDisplaceInteriorSmooth(s
, t
);
503 // compute bi-linear weight factors.
504 float sInc
, tInc
, sa
, ta
, sa1
, ta1
;
505 computeDisplaceBilinear(sTile
, tTile
, sInc
, tInc
, sa
, ta
, sa1
, ta1
);
506 // Manage limit case: if bilinear has not chosen the good direction (because of floor and orientation).
507 // eg on Right edge: This case arise if sDecimal==0, so if sa==sa1==0.5f. result is that
508 // smoothBorderX is != than sInc on right border. same reasoning with downBorder (smoothBorderY=1).
510 // NO NEED TO DO HERE, because sInc or tInc are not used at all.
514 // compute Neighboring info.
515 CPatchUVLocator uvLocatorX
;
516 CPatchUVLocator uvLocatorY
;
517 uvLocatorX
.build(this, edgeX
, bindInfoX
);
518 uvLocatorY
.build(this, edgeY
, bindInfoY
);
521 /* NB: see floor problems note in computeDisplaceEdgeSmooth();
523 sTile
= noiseFloor(sTile
) + 0.5f
;
524 tTile
= noiseFloor(tTile
) + 0.5f
;
525 // If we were exactly on the superior edge, prec compute is false... so correct this here.
526 if(sTile
>OrderS
) sTile
--;
527 if(tTile
>OrderT
) tTile
--;
530 // Bilinear across a corner.
531 CVector2f stTileIn
, stIn
;
532 CVector2f stTileOut
, stOut
;
537 // compute contribution of our patch.
538 ret
= computeDisplaceRaw(sTile
,tTile
, s
,t
) * sa
* ta
;
540 // compute contribution of the patch on the left/right side. same reasoning as in computeDisplaceEdgeSmooth();
542 stTileIn
.set(sTile
+smoothBorderX
, tTile
);
543 patchId
= uvLocatorX
.selectPatch(stTileIn
);
544 uvLocatorX
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
545 uvLocatorX
.locateUV(stIn
, patchId
, patchOut
, stOut
);
546 ret
+= patchOut
->computeDisplaceRaw(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
) * sa1
* ta
;
549 // compute contribution of the patch on the up/down side. same reasoning as in computeDisplaceEdgeSmooth();
551 stTileIn
.set(sTile
, tTile
+smoothBorderY
);
552 patchId
= uvLocatorY
.selectPatch(stTileIn
);
553 uvLocatorY
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
554 uvLocatorY
.locateUV(stIn
, patchId
, patchOut
, stOut
);
555 ret
+= patchOut
->computeDisplaceRaw(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
) * sa
* ta1
;
558 /* compute contribution of the patch adjacent to me.
559 There is multiple case to consider here. Take example with corner=0 (ie smBdX=smBdY=-1):
560 - if we are a normal corner with 4 edges, take the result from the left patch of our top patch.
561 - if the corner is on a bind Edge, the top patch may be the bigger patch, so don't take the result
562 from his neighbor (of course).
563 - if we are a normal corner with N!=4 edges, just do same thing than if N==4. this is false but don't bother.
565 To solve smoothly cases 1 and 2, use computeDisplaceRawOnNeighbor().
566 This method, if nessecary, look on his neighbor to compute the value.
569 stTileIn
.set(sTile
+smoothBorderX
, tTile
+smoothBorderY
);
570 // look on our "top" patch (this is arbitrary).
571 patchId
= uvLocatorY
.selectPatch(stTileIn
);
572 uvLocatorY
.locateUV(stTileIn
, patchId
, patchOut
, stTileOut
);
573 uvLocatorY
.locateUV(stIn
, patchId
, patchOut
, stOut
);
574 ret
+= patchOut
->computeDisplaceRawOnNeighbor(stTileOut
.x
, stTileOut
.y
, stOut
.x
, stOut
.y
) * sa1
* ta1
;
582 // ***************************************************************************
583 CVector
CPatch::computeNormalEdgeSmooth(float s
, float t
, sint8 smoothBorderX
, sint8 smoothBorderY
) const
587 CBezierPatch
*bpatch
;
588 bpatch
= unpackIntoCache();
590 // only one must be not null
591 nlassert( (smoothBorderX
==0) != (smoothBorderY
==0) );
594 // Get the edge against we must share displace.
595 if(smoothBorderX
==-1) edge
=0;
596 else if(smoothBorderY
==1) edge
=1;
597 else if(smoothBorderX
==1) edge
=2;
598 else if(smoothBorderY
==-1) edge
=3;
601 // If the edge is smoothed, blend with neighbor.
602 if(getSmoothFlag(edge
))
604 // Build the bindInfo against this edge.
605 getBindNeighbor(edge
, bindInfo
);
607 // Fast reject: if no neighbor, just do a simple computeDisplaceInteriorSmooth.
609 return bpatch
->evalNormal(s
/getOrderS(), t
/getOrderT());
614 // Compute our contribution.
615 r0
= bpatch
->evalNormal(s
/getOrderS(), t
/getOrderT());
617 // Compute the coordinate on the border of the edge, and the coef of the blend.
621 if(smoothBorderX
==-1) se
= noiseFloorF(se
), coef
=s
-se
;
622 else if(smoothBorderX
==1) se
= noiseCeilF(se
), coef
=se
-s
;
623 else if(smoothBorderY
==-1) te
= noiseFloorF(te
), coef
=t
-te
;
624 else if(smoothBorderY
==1) te
= noiseCeilF(te
), coef
=te
-t
;
625 coef
= 0.5f
+ coef
*0.5f
;
627 // Compute contribution of the normal on the neighbor, on the border of the edge.
628 CPatchUVLocator uvLocator
;
629 CVector2f stIn
, stOut
;
633 uvLocator
.build(this, edge
, bindInfo
);
635 patchId
= uvLocator
.selectPatch(stIn
);
636 uvLocator
.locateUV(stIn
, patchId
, patchOut
, stOut
);
638 bpatch
= patchOut
->unpackIntoCache();
639 r1
= bpatch
->evalNormal(stOut
.x
/patchOut
->getOrderS(), stOut
.y
/patchOut
->getOrderT());
641 // NB: don't bother problems with bind 1/X and the choice of the patch, because bind are C1, so normal is C0.
643 // Blend 2 result. For speed optim, don't normalize.
644 return r0
*coef
+ r1
*(1-coef
);
647 // else blend with vector Null.
654 if(smoothBorderX
==-1) se
= noiseFloorF(se
), coef
=s
-se
;
655 else if(smoothBorderX
==1) se
= noiseCeilF(se
), coef
=se
-s
;
656 else if(smoothBorderY
==-1) te
= noiseFloorF(te
), coef
=t
-te
;
657 else if(smoothBorderY
==1) te
= noiseCeilF(te
), coef
=te
-t
;
659 // Compute our contribution.
661 r0
= bpatch
->evalNormal(s
/getOrderS(), t
/getOrderT());
669 // ***************************************************************************
670 CVector
CPatch::computeNormalOnNeighbor(float s
, float t
, uint edgeExclude
) const
674 // look on what neighbor patch we must find the value (if any).
675 if(s
<1 && edgeExclude
!=0) edge
=0;
676 else if(t
>OrderT
-1 && edgeExclude
!=1) edge
=1;
677 else if(s
>OrderS
-1 && edgeExclude
!=2) edge
=2;
678 else if(t
<1 && edgeExclude
!=3) edge
=3;
681 // If the location is In the patch, just return normal value. (case of a bind 1/X).
684 CBezierPatch
*bpatch
= unpackIntoCache();
685 return bpatch
->evalNormal(s
/getOrderS(), t
/getOrderT());
687 // else must find on neighbor.
691 getBindNeighbor(edge
, bindInfo
);
693 // Fast reject: if no neighbor on the edge, just do a simple computeDisplaceRaw()
696 CBezierPatch
*bpatch
= unpackIntoCache();
697 return bpatch
->evalNormal(s
/getOrderS(), t
/getOrderT());
699 // else must find on neighbor.
702 CPatchUVLocator uvLocator
;
703 uvLocator
.build(this, edge
, bindInfo
);
710 // look on neighbor. same reasoning as in computeDisplaceEdgeSmooth();
712 patchId
= uvLocator
.selectPatch(stIn
);
713 uvLocator
.locateUV(stIn
, patchId
, patchOut
, stOut
);
714 CBezierPatch
*bpatch
= patchOut
->unpackIntoCache();
715 return bpatch
->evalNormal(stOut
.x
/patchOut
->getOrderS(), stOut
.y
/patchOut
->getOrderT());
722 // ***************************************************************************
723 CVector
CPatch::computeNormalCornerSmooth(float s
, float t
, sint8 smoothBorderX
, sint8 smoothBorderY
) const
730 CBezierPatch
*bpatch
;
731 bpatch
= unpackIntoCache();
733 // both must be not null
734 nlassert( (smoothBorderX
!=0) && (smoothBorderY
!=0) );
737 // Get the edge against we must share displace.
738 if(smoothBorderX
==-1) edgeX
=0;
739 else if(smoothBorderX
==1) edgeX
=2;
741 if(smoothBorderY
==1) edgeY
=1;
742 else if(smoothBorderY
==-1) edgeY
=3;
745 // Get the corner against we must share displace.
746 if(smoothBorderX
==-1)
748 if(smoothBorderY
==-1) corner
=0;
753 if(smoothBorderY
==-1) corner
=3;
757 // If this corner is smoothed, blend with 4 neighbors patchs.
758 if(getCornerSmoothFlag(corner
))
760 // Build the bindInfo against the 2 edge.
761 getBindNeighbor(edgeX
, bindInfoX
);
762 getBindNeighbor(edgeY
, bindInfoY
);
764 // Fast reject: if no neighbor, just do a simple computeDisplaceInteriorSmooth.
765 if(!bindInfoX
.Zone
|| !bindInfoY
.Zone
)
766 return bpatch
->evalNormal(s
/getOrderS(), t
/getOrderT());
772 // Compute the coordinate on the border of the edge, and the coef of the blend.
777 if(smoothBorderX
==-1) se
= noiseFloorF(se
), coefX
=s
-se
;
778 else se
= noiseCeilF(se
), coefX
=se
-s
;
779 if(smoothBorderY
==-1) te
= noiseFloorF(te
), coefY
=t
-te
;
780 else te
= noiseCeilF(te
), coefY
=te
-t
;
781 coefX
= 0.5f
+ coefX
*0.5f
;
782 coefY
= 0.5f
+ coefY
*0.5f
;
785 // Compute our contribution.
786 ret
= bpatch
->evalNormal(s
/getOrderS(), t
/getOrderT()) *coefX
*coefY
;
789 // compute Neighboring info.
790 CPatchUVLocator uvLocatorX
;
791 CPatchUVLocator uvLocatorY
;
792 CVector2f stIn
, stOut
;
796 uvLocatorX
.build(this, edgeX
, bindInfoX
);
797 uvLocatorY
.build(this, edgeY
, bindInfoY
);
799 // Patch on our X side.
801 patchId
= uvLocatorX
.selectPatch(stIn
);
802 uvLocatorX
.locateUV(stIn
, patchId
, patchOut
, stOut
);
803 bpatch
= patchOut
->unpackIntoCache();
804 ret
+= bpatch
->evalNormal(stOut
.x
/patchOut
->getOrderS(), stOut
.y
/patchOut
->getOrderT()) *(1-coefX
)*coefY
;
806 // Patch on our Y side.
808 patchId
= uvLocatorY
.selectPatch(stIn
);
809 uvLocatorY
.locateUV(stIn
, patchId
, patchOut
, stOut
);
810 bpatch
= patchOut
->unpackIntoCache();
811 ret
+= bpatch
->evalNormal(stOut
.x
/patchOut
->getOrderS(), stOut
.y
/patchOut
->getOrderT()) *coefX
*(1-coefY
);
813 /* compute contribution of the patch adjacent to me.
814 Same reasoning as in computeDisplaceCornerSmooth().
817 patchId
= uvLocatorY
.selectPatch(stIn
);
818 uvLocatorY
.locateUV(stIn
, patchId
, patchOut
, stOut
);
819 // Because we compute the normal exactly on the edge, we must inform this method not to take us as neighbor.
821 ret
+= patchOut
->computeNormalOnNeighbor(stOut
.x
, stOut
.y
, bindInfoY
.Edge
[patchId
]) *(1-coefX
)*(1-coefY
);
826 // else must blend with 0.
834 if(smoothBorderX
==-1) se
= noiseFloorF(se
), coefX
=s
-se
;
835 else se
= noiseCeilF(se
), coefX
=se
-s
;
836 if(smoothBorderY
==-1) te
= noiseFloorF(te
), coefY
=t
-te
;
837 else te
= noiseCeilF(te
), coefY
=te
-t
;
840 // To have smooth continuities with smooth on edge (if any), we must do this.
842 // Compute a smooth with my X neighbor.
843 rx
= computeNormalEdgeSmooth(s
, t
, smoothBorderX
, 0);
844 // Compute a smooth with my Y neighbor.
845 ry
= computeNormalEdgeSmooth(s
, t
, 0, smoothBorderY
);
847 // Blend the 2 result.
850 // This the weight used to blend to 0.
851 float maxCoef
= max(coefY
, coefX
);
852 // This the weight used to blend beetween rx and ry.
853 float ooSum
= 1.0f
/ (coefY
+ coefX
);
854 float blendCoefX
= coefX
* ooSum
;
855 float blendCoefY
= coefY
* ooSum
;
857 return maxCoef
* (rx
*blendCoefY
+ ry
*blendCoefX
);
861 return CVector::Null
;
868 // ***************************************************************************
869 void CPatch::computeNoise(float s
, float t
, CVector
&displace
) const
875 // Pre-Compute Border Smothing.
876 //=========================
877 // If we are on a border, flag it.
878 sint8 smoothNormalBorderX
= 0;
879 sint8 smoothNormalBorderY
= 0;
880 // NB: because OrderS and OrderT >=2, smoothNormalBorderX=-1 and smoothNormalBorderX=1 are exclusive (as smoothNormalBorderY).
881 if(so
< 1) smoothNormalBorderX
= -1;
882 else if(so
> OrderS
-1) smoothNormalBorderX
= 1;
883 if(to
< 1) smoothNormalBorderY
= -1;
884 else if(to
> OrderT
-1) smoothNormalBorderY
= 1;
886 bool smoothNormalEdge
= (smoothNormalBorderX
!=0) != (smoothNormalBorderY
!=0);
887 bool smoothNormalCorner
= (smoothNormalBorderX
!=0) && (smoothNormalBorderY
!=0);
890 // Do same thing, but to know if we must compute a displace on an interior, on an edge or on a corner.
891 sint8 smoothDisplaceBorderX
= 0;
892 sint8 smoothDisplaceBorderY
= 0;
893 // NB: because OrderS and OrderT >=2, smoothBorderX=-1 and smoothBorderX=1 are exclusive (as smoothBorderY).
894 if(so
< 0.5) smoothDisplaceBorderX
= -1;
895 else if(so
> OrderS
-0.5) smoothDisplaceBorderX
= 1;
896 if(to
< 0.5) smoothDisplaceBorderY
= -1;
897 else if(to
> OrderT
-0.5) smoothDisplaceBorderY
= 1;
899 bool smoothDisplaceEdge
= (smoothDisplaceBorderX
!=0) != (smoothDisplaceBorderY
!=0);
900 bool smoothDisplaceCorner
= (smoothDisplaceBorderX
!=0) && (smoothDisplaceBorderY
!=0);
903 // Compute Displace value.
904 //=========================
907 if(smoothDisplaceCorner
)
908 displaceValue
= computeDisplaceCornerSmooth(so
, to
, smoothDisplaceBorderX
, smoothDisplaceBorderY
);
909 else if(smoothDisplaceEdge
)
910 displaceValue
= computeDisplaceEdgeSmooth(so
, to
, smoothDisplaceBorderX
, smoothDisplaceBorderY
);
912 displaceValue
= computeDisplaceInteriorSmooth(so
, to
);
916 // Compute Displace normal.
917 //=========================
919 // Evaluate the normal.
920 CVector displaceNormal
;
923 // smooth on edges and on corners.
924 if(smoothNormalCorner
)
925 displaceNormal
= computeNormalCornerSmooth(so
, to
, smoothNormalBorderX
, smoothNormalBorderY
);
926 else if(smoothNormalEdge
)
927 displaceNormal
= computeNormalEdgeSmooth(so
, to
, smoothNormalBorderX
, smoothNormalBorderY
);
931 CBezierPatch
*bpatch
= unpackIntoCache();
933 displaceNormal
= bpatch
->evalNormal(s
, t
);
939 //=========================
940 displace
= displaceNormal
* displaceValue
;
945 // ***************************************************************************
946 void CPatch::setCornerSmoothFlag(uint corner
, bool smooth
)
949 uint mask
= 1<<corner
;
951 _CornerSmoothFlag
|= mask
;
953 _CornerSmoothFlag
&= ~mask
;
956 // ***************************************************************************
957 bool CPatch::getCornerSmoothFlag(uint corner
) const
960 uint mask
= 1<<corner
;
961 return (_CornerSmoothFlag
& mask
)!=0;