Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / zone_tgt_smoother.cpp
blob1a49022035cda5f1c1c756e7b4f4420c65b32c63
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_tgt_smoother.h"
20 #include "nel/misc/plane.h"
22 using namespace std;
23 using namespace NLMISC;
25 #ifdef DEBUG_NEW
26 #define new DEBUG_NEW
27 #endif
29 namespace NL3D
34 // ***************************************************************************
35 void CZoneTgtSmoother::makeVerticesCoplanar(std::vector<CZoneInfo> &zones)
37 sint i,j, numZone;
38 sint centerZoneId;
40 nlassert(zones.size()>=1);
41 centerZoneId= zones[0].ZoneId;
43 // 0. CenterZone.
44 //===============
45 // First, make connectivity patch/vertex
46 for(i=0;i<(sint)zones[0].Patchs.size();i++)
48 CPatchInfo &pa= zones[0].Patchs[i];
50 for(j=0;j<4;j++)
52 sint vtx= pa.BaseVertices[j];
53 CPatchId pid;
54 pid.ZoneId= centerZoneId;
55 pid.PatchId= i;
56 pid.Patch= &pa;
57 pid.IdVert= j;
58 VertexMap[vtx].Patchs.push_back(pid);
61 // Second, what vertices of this zone are one border?
62 for(i=0;i<(sint)zones[0].BorderVertices.size();i++)
64 CBorderVertex &bv= zones[0].BorderVertices[i];
65 sint vtx= bv.CurrentVertex;
66 VertexMap[vtx].OnBorder= true;
69 // 1. Neighbor zones.
70 //===================
71 map<sint, sint> tempMap;
72 for(numZone= 1; numZone<(sint)zones.size(); numZone++)
74 sint adjZoneId= zones[numZone].ZoneId;
76 tempMap.clear();
77 // Tests which vertices points on the center zone.
78 for(i=0;i<(sint)zones[numZone].BorderVertices.size();i++)
80 CBorderVertex &bv= zones[numZone].BorderVertices[i];
82 if(bv.NeighborZoneId== centerZoneId)
84 tempMap[bv.CurrentVertex]= bv.NeighborVertex;
87 // Tests patchs which points on center zone.
88 for(i=0;i<(sint)zones[numZone].Patchs.size();i++)
90 CPatchInfo &pa= zones[numZone].Patchs[i];
92 for(j=0;j<4;j++)
94 sint vtx= pa.BaseVertices[j];
95 if(tempMap.find(vtx)!=tempMap.end())
97 CPatchId pid;
98 pid.ZoneId= adjZoneId;
99 pid.PatchId= i;
100 pid.Patch= &pa;
101 pid.IdVert= j;
102 // Fill the vertex of the center zone.
103 VertexMap[tempMap[vtx]].Patchs.push_back(pid);
110 // 2. Process each vertex.
111 //========================
112 ItVertexMap itVert;
113 for(itVert= VertexMap.begin(); itVert!=VertexMap.end(); itVert++)
115 CVertexInfo &vert= itVert->second;
117 // a. verify if coplanar is possible.
118 //===================================
120 // \todo yoyo: later: do it too on non border vertices if wanted (with a normal threshold...).
121 if(!vert.OnBorder)
122 continue;
123 // \todo yoyo: later: formula with 3, 5 ... patchs around the vertex.
124 if(vert.Patchs.size()!=4)
125 continue;
127 // Test if there is no bind 1/x on this patch, around this vertex.
128 // \todo yoyo: later: binds should works...
129 std::list<CPatchId>::iterator itPatch;
130 bool bindFound= false;
131 for(itPatch= vert.Patchs.begin(); itPatch!= vert.Patchs.end(); itPatch++)
133 // Tests the two edges around the vertex (before: e0, and after: e1).
134 sint e0= (itPatch->IdVert+4-1)%4;
135 sint e1= itPatch->IdVert;
137 if(itPatch->Patch->BindEdges[e0].NPatchs!= 1 || itPatch->Patch->BindEdges[e1].NPatchs!= 1)
139 bindFound= true;
140 break;
143 if(bindFound)
144 continue;
148 // b. maps patchs on tangents.
149 //=========================
150 vector<CTangentId> tangents;
151 for(itPatch= vert.Patchs.begin(); itPatch!= vert.Patchs.end(); itPatch++)
153 CPatchInfo &pa= *(itPatch->Patch);
154 // The edges, before and after the veterx.
155 sint edgeNum[2]= {(itPatch->IdVert+4-1)%4, itPatch->IdVert };
156 // The tangents, before and after the veterx.
157 sint tgtNum[2]= {(itPatch->IdVert*2+8-1)%8, itPatch->IdVert*2 };
159 // For the 2 edges around this vertex.
160 for(sint ed= 0; ed<2;ed++)
162 sint patchId, zoneId, edgeId;
163 sint tgt;
165 // get neighbor edge id.
166 zoneId= pa.BindEdges[ edgeNum[ed] ].ZoneId;
167 patchId= pa.BindEdges[ edgeNum[ed] ].Next[0];
168 edgeId= pa.BindEdges[ edgeNum[ed] ].Edge[0];
169 // Search if tangent already inserted, mapped to this "neighbor edge".
170 for(tgt= 0; tgt<(sint)tangents.size();tgt++)
172 if(tangents[tgt].ZoneId==zoneId && tangents[tgt].PatchId==patchId && tangents[tgt].EdgeId==edgeId)
173 break;
175 // If not found, add the tangent, and map ME to it.
176 if(tgt==(sint)tangents.size())
178 CTangentId tangent;
179 // Set OUR edge Id.
180 tangent.ZoneId= itPatch->ZoneId;
181 tangent.PatchId= itPatch->PatchId;
182 tangent.EdgeId= edgeNum[ed];
183 // Get the tangent, before or after the vertex.
184 tangent.Tangent= pa.Patch.Tangents[ tgtNum[ed] ];
185 // Which patchs this edge share. (0 is those which insert this tgt)
186 tangent.Patchs[0]= &pa;
187 tangents.push_back(tangent);
189 else
191 // Which patchs this edge share. (0 is those which access this tgt)
192 tangents[tgt].Patchs[1]= &pa;
194 // Map the patch to this tangent.
195 itPatch->Tangents[ed]= tgt;
200 // There should be 4 tangents.
201 if (tangents.size()!=4)
203 nlinfo ("ERROR: vertex %d should have 4 tangents. It got %d. (MAXINDICES +1!!)", itVert->first, tangents.size());
204 continue;
208 // c. get the vertex.
209 //===================
210 CVector vertexValue;
211 itPatch= vert.Patchs.begin();
212 vertexValue= itPatch->Patch->Patch.Vertices[itPatch->IdVert];
215 // d. project the tangents.
216 //=========================
217 // better coplanar than Max... (with orthogonal angles: use p0/p1).
218 for(i=0;i<(sint)tangents.size();i++)
220 // For following tangents, search the opposite.
221 // Begin at i+1 so we are sure to do this only one time.
222 for(j=i+1;j<(sint)tangents.size();j++)
224 if(tangents[i].isOppositeOf(tangents[j]))
226 CVector &tgt0= tangents[i].Tangent;
227 CVector &tgt1= tangents[j].Tangent;
228 // Colinear the tangents. Must keep the length of vectors.
229 float l0= (tgt0-vertexValue).norm();
230 float l1= (tgt1-vertexValue).norm();
231 // Average the tangents. Normalize them before, to keep much as possible the orientation.
232 CVector d0= (vertexValue-tgt0).normed();
233 CVector d1= (tgt1-vertexValue).normed();
234 CVector dir= (d0+d1).normed();
236 // Copy to tangents.
237 tgt0= vertexValue-dir*l0;
238 tgt1= vertexValue+dir*l1;
244 // e. assign tangents to patchs, rebuild interior.
245 //==============================
246 for(itPatch= vert.Patchs.begin(); itPatch!= vert.Patchs.end(); itPatch++)
248 CPatchInfo &pa= *(itPatch->Patch);
249 // The tangents, before and after the vertex.
250 sint tgtNum[2]= {(itPatch->IdVert*2+8-1)%8, itPatch->IdVert*2 };
251 sint t0= tgtNum[0];
252 sint t1= tgtNum[1];
253 sint smoothEdge0= pa.getSmoothFlag (t0/2);
254 sint smoothEdge1= pa.getSmoothFlag (t1/2);
256 // Smooth this edge ?
257 if (smoothEdge0)
258 pa.Patch.Tangents[t0]= tangents[itPatch->Tangents[0]].Tangent;
259 if (smoothEdge1)
260 pa.Patch.Tangents[t1]= tangents[itPatch->Tangents[1]].Tangent;
262 // Setup the coplanared interior. just the sum of 2 vector tangents.
263 if (smoothEdge0&&smoothEdge1)
264 pa.Patch.Interiors[itPatch->IdVert]= pa.Patch.Tangents[t0] + pa.Patch.Tangents[t1] - vertexValue;
271 // OLD CODE FOR 3DS MAX LIKE COPLANAR.
272 // WORKS, BUT NOT AS GOOD AS REAL COPLANAR.
274 // b. build the plane.
275 //====================
276 CVector planeNormal(0,0,0);
277 CVector planeCenter;
278 for(itPatch= vert.Patchs.begin(); itPatch!= vert.Patchs.end(); itPatch++)
280 CPatchInfo &pa= *(itPatch->Patch);
281 CVector a,b,c, pvect;
282 sint t0= (itPatch->IdVert*2+8-1)%8;
283 sint t1= itPatch->IdVert*2;
285 // CCW order.
286 a= pa.Patch.Tangents[t0];
287 b= pa.Patch.Vertices[itPatch->IdVert];
288 c= pa.Patch.Tangents[t1];
289 pvect= (b-a)^(c-b);
290 planeNormal+= pvect.normed();
292 // yes, done 4 times... :(
293 planeCenter= b;
295 // Average of all normals...
296 planeNormal.normalize();
297 CPlane plane;
298 plane.make(planeNormal, planeCenter);
301 // c. projects the tangents, rebuild interior.
302 //============================================
303 for(itPatch= vert.Patchs.begin(); itPatch!= vert.Patchs.end(); itPatch++)
305 CPatchInfo &pa= *(itPatch->Patch);
306 sint t0= (itPatch->IdVert*2+8-1)%8;
307 sint t1= itPatch->IdVert*2;
308 pa.Patch.Tangents[t0]= plane.project(pa.Patch.Tangents[t0]);
309 pa.Patch.Tangents[t1]= plane.project(pa.Patch.Tangents[t1]);
311 // Setup the coplanared interior. just the sum of 2 vector tangents.
312 pa.Patch.Interiors[itPatch->IdVert]= pa.Patch.Tangents[t0] + pa.Patch.Tangents[t1] - planeCenter;
317 } // NL3D