Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
weldmesh.cpp
Go to the documentation of this file.
1 // Slightly modified version of weldmesh, by Wildfire Games, for 0 A.D.
2 //
3 // Motivation for changes:
4 // * Fix build on *BSD (including malloc.h produces an error)
5 
6 #include "precompiled.h"
7 
8 /**
9  * Copyright (C) 2011 by Morten S. Mikkelsen
10  *
11  * This software is provided 'as-is', without any express or implied
12  * warranty. In no event will the authors be held liable for any damages
13  * arising from the use of this software.
14  *
15  * Permission is granted to anyone to use this software for any purpose,
16  * including commercial applications, and to alter it and redistribute it
17  * freely, subject to the following restrictions:
18  *
19  * 1. The origin of this software must not be misrepresented; you must not
20  * claim that you wrote the original software. If you use this software
21  * in a product, an acknowledgment in the product documentation would be
22  * appreciated but is not required.
23  * 2. Altered source versions must be plainly marked as such, and must not be
24  * misrepresented as being the original software.
25  * 3. This notice may not be removed or altered from any source distribution.
26  */
27 
28 
29 #include "weldmesh.h"
30 #include <string.h>
31 #include <assert.h>
32 
33 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
34 #include <stdlib.h> /* BSD-based OSes get their malloc stuff through here */
35 #else
36 #include <malloc.h>
37 #endif
38 
39 static void MergeVertsFast(int * piCurNrUniqueVertices, int * piRemapTable, float * pfVertexDataOut, int * piVertexIDs,
40  const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert,
41  const int iL_in, const int iR_in, const int iChannelNum);
42 
43 int WeldMesh(int * piRemapTable, float * pfVertexDataOut,
44  const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert)
45 {
46  int iUniqueVertices = 0, i=0;
47  int * piVertexIDs = NULL;
48  if(iNrVerticesIn<=0) return 0;
49 
50 
51  iUniqueVertices = 0;
52  piVertexIDs = (int *) malloc(sizeof(int)*iNrVerticesIn);
53  if(piVertexIDs!=NULL)
54  {
55  for(i=0; i<iNrVerticesIn; i++)
56  {
57  piRemapTable[i] = -1;
58  piVertexIDs[i] = i;
59  }
60 
61  MergeVertsFast(&iUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
62  pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, 0, iNrVerticesIn-1, 0);
63 
64  free(piVertexIDs);
65 
66  // debug check
67  for(i=0; i<iUniqueVertices; i++)
68  assert(piRemapTable[i]>=0);
69  }
70 
71  return iUniqueVertices;
72 }
73 
74 
75 
76 
77 
78 static void MergeVertsFast(int * piCurNrUniqueVertices, int * piRemapTable, float * pfVertexDataOut, int * piVertexIDs,
79  const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert,
80  const int iL_in, const int iR_in, const int iChannelNum)
81 {
82  const int iCount = iR_in-iL_in+1;
83  int l=0;
84  float fMin, fMax, fAvg;
85  assert(iCount>0);
86  // make bbox
87  fMin = pfVertexDataIn[ piVertexIDs[iL_in]*iFloatsPerVert + iChannelNum]; fMax = fMin;
88  for(l=(iL_in+1); l<=iR_in; l++)
89  {
90  const int index = piVertexIDs[l]*iFloatsPerVert + iChannelNum;
91  const float fVal = pfVertexDataIn[index];
92  if(fMin>fVal) fMin=fVal;
93  else if(fMax<fVal) fMax=fVal;
94  }
95 
96  // terminate recursion when the separation/average value
97  // is no longer strictly between fMin and fMax values.
98  fAvg = 0.5f*(fMax + fMin);
99  if(fAvg<=fMin || fAvg>=fMax || iCount==1)
100  {
101  if((iChannelNum+1) == iFloatsPerVert || iCount==1) // we are done, weld by hand
102  {
103  int iUniqueNewVertices = 0;
104  float * pfNewUniVertsOut = &pfVertexDataOut[ piCurNrUniqueVertices[0]*iFloatsPerVert ];
105 
106  for(l=iL_in; l<=iR_in; l++)
107  {
108  const int index = piVertexIDs[l]*iFloatsPerVert;
109 
110  int iFound = 0; // didn't find copy yet.
111  int l2=0;
112  while(l2<iUniqueNewVertices && iFound==0)
113  {
114  const int index2 = l2*iFloatsPerVert;
115 
116  int iAllSame = 1;
117  int c=0;
118  while(iAllSame!=0 && c<iFloatsPerVert)
119  {
120  iAllSame &= (pfVertexDataIn[index+c] == pfNewUniVertsOut[index2+c] ? 1 : 0);
121  ++c;
122  }
123 
124  iFound = iAllSame;
125  if(iFound==0) ++l2;
126  }
127 
128  // generate new entry
129  if(iFound==0)
130  {
131  memcpy(pfNewUniVertsOut+iUniqueNewVertices*iFloatsPerVert, pfVertexDataIn+index, sizeof(float)*iFloatsPerVert);
132  ++iUniqueNewVertices;
133  }
134 
135  assert(piRemapTable[piVertexIDs[l]] == -1); // has not yet been assigned
136  piRemapTable[piVertexIDs[l]] = piCurNrUniqueVertices[0] + l2;
137  }
138 
139  piCurNrUniqueVertices[0] += iUniqueNewVertices;
140  }
141  else
142  {
143  MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
144  pfVertexDataIn, iNrVerticesIn, iFloatsPerVert,
145  iL_in, iR_in, iChannelNum+1);
146  }
147  }
148  else
149  {
150  int iL=iL_in, iR=iR_in, index;
151 
152  // seperate (by fSep) all points between iL_in and iR_in in pTmpVert[]
153  while(iL < iR)
154  {
155  int iReadyLeftSwap = 0;
156  int iReadyRightSwap = 0;
157  while(iReadyLeftSwap==0 && iL<iR)
158  {
159  assert(iL>=iL_in && iL<=iR_in);
160  index = piVertexIDs[iL]*iFloatsPerVert+iChannelNum;
161  iReadyLeftSwap = !(pfVertexDataIn[index]<fAvg) ? 1 : 0;
162  if(iReadyLeftSwap==0) ++iL;
163  }
164  while(iReadyRightSwap==0 && iL<iR)
165  {
166  assert(iR>=iL_in && iR<=iR_in);
167  index = piVertexIDs[iR]*iFloatsPerVert+iChannelNum;
168  iReadyRightSwap = pfVertexDataIn[index]<fAvg ? 1 : 0;
169  if(iReadyRightSwap==0) --iR;
170  }
171  assert( (iL<iR) || (iReadyLeftSwap==0 || iReadyRightSwap==0));
172 
173  if(iReadyLeftSwap!=0 && iReadyRightSwap!=0)
174  {
175  int iID=0;
176  assert(iL<iR);
177  iID = piVertexIDs[iL];
178  piVertexIDs[iL] = piVertexIDs[iR];
179  piVertexIDs[iR] = iID;
180  ++iL; --iR;
181  }
182  }
183 
184  assert(iL==(iR+1) || (iL==iR));
185  if(iL==iR)
186  {
187  const int index = piVertexIDs[iR]*iFloatsPerVert+iChannelNum;
188  const int iReadyRightSwap = pfVertexDataIn[index]<fAvg ? 1 : 0;
189  if(iReadyRightSwap!=0) ++iL;
190  else --iR;
191  }
192 
193  // recurse
194  if(iL_in <= iR)
195  MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
196  pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, iL_in, iR, iChannelNum); // weld all left of fSep
197  if(iL <= iR_in)
198  MergeVertsFast(piCurNrUniqueVertices, piRemapTable, pfVertexDataOut, piVertexIDs,
199  pfVertexDataIn, iNrVerticesIn, iFloatsPerVert, iL, iR_in, iChannelNum); // weld all right of (or equal to) fSep
200  }
201 }
202 
int WeldMesh(int *piRemapTable, float *pfVertexDataOut, const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert)
Copyright (C) 2011 by Morten S.
Definition: weldmesh.cpp:43
static void MergeVertsFast(int *piCurNrUniqueVertices, int *piRemapTable, float *pfVertexDataOut, int *piVertexIDs, const float pfVertexDataIn[], const int iNrVerticesIn, const int iFloatsPerVert, const int iL_in, const int iR_in, const int iChannelNum)
Copyright (C) 2011 by Morten S.
Definition: weldmesh.cpp:78