Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / patchuv_locator.cpp
blobb4743c4c132a0fa74b71e3a9fdcf84209f361682
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/patchuv_locator.h"
21 using namespace std;
22 using namespace NLMISC;
24 #ifdef DEBUG_NEW
25 #define new DEBUG_NEW
26 #endif
28 namespace NL3D
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.
43 _SameEdgeOrder= true;
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.
66 float scX, scY;
67 // If our neighbor edge is a vertical edge
68 if( (edgeNeighbor&1)==0 )
70 scX= 1;
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;
78 if(_NPatchs>1)
79 scY*= _NPatchs;
80 // same TileOrder on the edge??
81 if(scY!=1)
82 _SameEdgeOrder= false;
84 else
86 scY= 1;
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;
94 if(_NPatchs>1)
95 scX*= _NPatchs;
96 // same TileOrder on the edge??
97 if(scX!=1)
98 _SameEdgeOrder= false;
100 // Find rotation to apply.
101 switch(rotation)
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);
115 float decal;
117 // find the uv at start of edgeCenter, + decal due to bind 1/X.
118 float ocS= patchCenter->getOrderS();
119 float ocT= patchCenter->getOrderT();
120 // Manage Bind 1/X.
121 if(_NPatchs>1)
123 // Move uvCenter, so it is near the position at start of edgeNeighbor.
124 decal= (float)i / _NPatchs;
126 else
127 decal= 0;
128 // Manage rotation.
129 switch(edgeCenter)
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();
140 // Manage Bind X/1.
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;
148 else
149 decal= 0;
150 // Manage rotation.
151 switch(edgeNeighbor)
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)
172 if(_NPatchs==1)
173 return 0;
174 else
176 // Choice before on which patch we must go.
177 float selection=0.0;
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);
191 return sel;
196 // ***************************************************************************
197 void CPatchUVLocator::locateUV(const CVector2f &uvIn, uint patch, CPatch *&patchOut, CVector2f &uvOut)
199 if(_NPatchs==1)
201 // Change basis and select good patch.
202 _NeighborBasis[0].mulPoint(uvIn, uvOut);
203 patchOut= _NeighborPatch[0];
205 else
207 // Change basis and select good patch.
208 _NeighborBasis[patch].mulPoint(uvIn, uvOut);
209 patchOut= _NeighborPatch[patch];
215 } // NL3D