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/>.
19 #include "nel/3d/patchuv_locator.h"
22 using namespace NLMISC
;
32 // ***************************************************************************
33 void CPatchUVLocator::build(const CPatch
*patchCenter
, sint edgeCenter
, CPatch::CBindInfo
&bindInfo
)
35 nlassert(bindInfo
.Zone
);
36 // copy basic. NB: NPatchs==0 means patchCenter is binded on a 1/X patch.
37 _CenterPatch
= const_cast<CPatch
*>(patchCenter
);
38 _CenterPatchEdge
= edgeCenter
;
39 _NPatchs
= bindInfo
.NPatchs
;
42 // set it to true. false-d if one of the neighbor patch does not have same number of tile.
46 // For all patchs binded to me.
47 for(sint i
=0; i
<_NPatchs
; i
++)
49 // The edge of the neihbor on which we are binded.
50 sint edgeNeighbor
= bindInfo
.Edge
[i
];
51 CPatch
*paNeighbor
= bindInfo
.Next
[i
];
52 _NeighborPatch
[i
]= paNeighbor
;
55 // Find uvI, uvJ, uvP such that:
56 // uvOut= uvIn.x * uvI + uvIn.y * uvJ + uvP.
57 CVector2f
&uvI
= _NeighborBasis
[i
].UvI
;
58 CVector2f
&uvJ
= _NeighborBasis
[i
].UvJ
;
59 CVector2f
&uvP
= _NeighborBasis
[i
].UvP
;
62 // Find the basis MeToNeighbor.
63 //=============================
64 sint rotation
= (edgeCenter
- edgeNeighbor
+ 4) & 3;
65 // Find scale to apply.
67 // If our neighbor edge is a vertical edge
68 if( (edgeNeighbor
&1)==0 )
72 // Manage difference of Order at the edge.
73 scY
= (float)paNeighbor
->getOrderForEdge(edgeNeighbor
) / (float)patchCenter
->getOrderForEdge(edgeCenter
);
74 // Manage bind on the edge.
75 // If patchCenter is binded on a bigger
76 if(bindInfo
.MultipleBindNum
!=0)
77 scY
/= bindInfo
.MultipleBindNum
;
80 // same TileOrder on the edge??
82 _SameEdgeOrder
= false;
88 // Manage difference of Order at the edge.
89 scX
= (float)paNeighbor
->getOrderForEdge(edgeNeighbor
) / (float)patchCenter
->getOrderForEdge(edgeCenter
);
90 // Manage bind on the edge.
91 // If patchCenter is binded on a bigger
92 if(bindInfo
.MultipleBindNum
!=0)
93 scX
/= bindInfo
.MultipleBindNum
;
96 // same TileOrder on the edge??
98 _SameEdgeOrder
= false;
100 // Find rotation to apply.
103 case 0: uvI
.set(-scX
, 0); uvJ
.set(0, -scY
); break;
104 case 1: uvI
.set(0, -scY
); uvJ
.set(scX
, 0); break;
105 case 2: uvI
.set(scX
, 0); uvJ
.set(0, scY
); break;
106 case 3: uvI
.set(0, scY
); uvJ
.set(-scX
, 0); break;
110 // Find the position.
111 //=============================
112 // Find the uv coord at start of the edge, for 2 patchs.
113 CVector2f
uvCenter(0.f
, 0.f
);
114 CVector2f
uvNeighbor(0.f
, 0.f
);
117 // find the uv at start of edgeCenter, + decal due to bind 1/X.
118 float ocS
= patchCenter
->getOrderS();
119 float ocT
= patchCenter
->getOrderT();
123 // Move uvCenter, so it is near the position at start of edgeNeighbor.
124 decal
= (float)i
/ _NPatchs
;
131 case 0: uvCenter
.set(0, decal
*ocT
); break;
132 case 1: uvCenter
.set(decal
*ocS
, ocT
); break;
133 case 2: uvCenter
.set(ocS
, (1-decal
)*ocT
); break;
134 case 3: uvCenter
.set((1-decal
)*ocS
, 0); break;
137 // find the uv at start of edgeNeighbor, + decal due to bind X/1.
138 float onS
= paNeighbor
->getOrderS();
139 float onT
= paNeighbor
->getOrderT();
141 if(bindInfo
.MultipleBindNum
!=0)
143 // Must invert the id, because of mirror.... (make a draw).
144 sint id
= (bindInfo
.MultipleBindNum
-1) - bindInfo
.MultipleBindId
;
145 // Move uvNeighbor, so it is near the position at start of edgeCenter.
146 decal
= (float)id
/ bindInfo
.MultipleBindNum
;
153 case 0: uvNeighbor
.set(0, (1-decal
)*onT
); break;
154 case 1: uvNeighbor
.set((1-decal
)*onS
, onT
); break;
155 case 2: uvNeighbor
.set(onS
, decal
*onT
); break;
156 case 3: uvNeighbor
.set(decal
*onS
, 0); break;
161 // uvOut= uvIn.x * uvI + uvIn.y * uvJ + uvP.
162 // So uvP = uvOut - uvIn.x * uvI - uvIn.y * uvJ
163 uvP
= uvNeighbor
- uvCenter
.x
* uvI
- uvCenter
.y
* uvJ
;
169 // ***************************************************************************
170 uint
CPatchUVLocator::selectPatch(const CVector2f
&uvIn
)
176 // Choice before on which patch we must go.
178 uint os
= _CenterPatch
->getOrderS();
179 uint ot
= _CenterPatch
->getOrderT();
180 switch(_CenterPatchEdge
)
182 case 0: selection
= uvIn
.y
/ ot
; break;
183 case 1: selection
= uvIn
.x
/ os
; break;
184 case 2: selection
= (ot
-uvIn
.y
) / ot
; break;
185 case 3: selection
= (os
-uvIn
.x
) / os
; break;
188 sint sel
= (sint
)floor(selection
*_NPatchs
);
189 clamp(sel
, 0, _NPatchs
-1);
196 // ***************************************************************************
197 void CPatchUVLocator::locateUV(const CVector2f
&uvIn
, uint patch
, CPatch
*&patchOut
, CVector2f
&uvOut
)
201 // Change basis and select good patch.
202 _NeighborBasis
[0].mulPoint(uvIn
, uvOut
);
203 patchOut
= _NeighborPatch
[0];
207 // Change basis and select good patch.
208 _NeighborBasis
[patch
].mulPoint(uvIn
, uvOut
);
209 patchOut
= _NeighborPatch
[patch
];