Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AlphaMapCalculator.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2009 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. 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 General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Determine which alpha blend map fits a given shape.
20  */
21 
22 #include "precompiled.h"
23 
24 #include "AlphaMapCalculator.h"
25 #include <string.h>
26 #include <stdio.h>
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 // CAlphaMapCalculator: functionality for calculating which alpha blend map
30 // fits a given shape
31 namespace CAlphaMapCalculator {
32 
33 ///////////////////////////////////////////////////////////////////////////////
34 // Blend4: structure mapping a blend shape for N,E,S,W to a particular map
35 struct Blend4 {
36  Blend4(BlendShape4 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
37 
40 };
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 // Blend8: structure mapping a blend shape for N,NE,E,SE,S,SW,W,NW to a
44 // particular map
45 struct Blend8 {
46  Blend8(BlendShape8 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
47 
50 };
51 
52 ///////////////////////////////////////////////////////////////////////////////
53 // Data tables for mapping between shapes and blend maps
54 ///////////////////////////////////////////////////////////////////////////////
55 
57 {
58  Blend4(BlendShape4(1,0,0,0), 12)
59 };
60 
61 
63 {
64  Blend4(BlendShape4(0,1,1,0), 7),
65  Blend4(BlendShape4(1,0,1,0), 10)
66 };
67 
69 {
70  Blend8(BlendShape8(1,1,0,0,0,0,0,0), 12),
71  Blend8(BlendShape8(1,0,0,0,0,1,0,0), 12),
72  Blend8(BlendShape8(0,1,0,1,0,0,0,0), 0) ,
73  Blend8(BlendShape8(0,1,0,0,0,1,0,0), 0)
74 };
75 
77 {
78  Blend4(BlendShape4(1,1,1,0), 4)
79 };
80 
82 {
83  Blend8(BlendShape8(1,1,0,0,1,0,0,0), 10),
84  Blend8(BlendShape8(1,1,0,0,0,0,0,1), 12),
85  Blend8(BlendShape8(1,1,1,0,0,0,0,0), 1),
86  Blend8(BlendShape8(0,1,1,0,1,0,0,0), 7),
87  Blend8(BlendShape8(0,0,1,0,1,0,1,0), 4),
88  Blend8(BlendShape8(1,1,0,0,0,1,0,0), 12),
89  Blend8(BlendShape8(1,1,0,1,0,0,0,0), 12),
90  Blend8(BlendShape8(0,0,1,0,1,0,0,1), 7),
91  Blend8(BlendShape8(1,0,0,1,0,1,0,0), 12),
92  Blend8(BlendShape8(0,1,0,1,0,1,0,0), 0)
93 };
94 
96 {
97  Blend8(BlendShape8(1,1,0,0,1,0,0,1), 10),
98  Blend8(BlendShape8(1,1,0,1,1,0,0,0), 10),
99  Blend8(BlendShape8(1,1,0,0,1,1,0,0), 10),
100  Blend8(BlendShape8(1,1,0,1,0,0,0,1), 12),
101  Blend8(BlendShape8(0,1,1,0,1,1,0,0), 7),
102  Blend8(BlendShape8(1,1,1,1,0,0,0,0), 1),
103  Blend8(BlendShape8(1,1,1,0,1,0,0,0), 3),
104  Blend8(BlendShape8(0,0,1,0,1,1,0,1), 7),
105  Blend8(BlendShape8(1,0,1,0,1,1,0,0), 4),
106  Blend8(BlendShape8(1,1,1,0,0,1,0,0), 1),
107  Blend8(BlendShape8(1,1,0,1,0,1,0,0), 12),
108  Blend8(BlendShape8(0,1,0,1,0,1,0,1), 0)
109 };
110 
112 {
113  Blend8(BlendShape8(1,1,1,1,1,0,0,0), 2),
114  Blend8(BlendShape8(1,1,1,1,0,0,0,1), 1),
115  Blend8(BlendShape8(1,1,1,0,1,0,0,1), 3),
116  Blend8(BlendShape8(1,1,1,0,1,0,1,0), 11),
117  Blend8(BlendShape8(1,1,1,0,0,1,0,1), 1),
118  Blend8(BlendShape8(1,1,0,1,1,1,0,0), 10),
119  Blend8(BlendShape8(1,1,1,0,1,1,0,0), 3),
120  Blend8(BlendShape8(1,0,1,0,1,1,0,1), 4),
121  Blend8(BlendShape8(1,1,0,1,0,1,0,1), 12),
122  Blend8(BlendShape8(0,1,1,0,1,1,0,1), 7)
123 };
124 
126 {
127  Blend8(BlendShape8(1,1,1,1,1,1,0,0), 2),
128  Blend8(BlendShape8(1,1,1,1,1,0,1,0), 8),
129  Blend8(BlendShape8(1,1,1,1,0,1,0,1), 1),
130  Blend8(BlendShape8(1,1,1,0,1,1,1,0), 6),
131  Blend8(BlendShape8(1,1,1,0,1,1,0,1), 3),
132  Blend8(BlendShape8(1,1,0,1,1,1,0,1), 10)
133 };
134 
136 {
137  Blend8(BlendShape8(1,1,1,1,1,1,0,1), 2),
138  Blend8(BlendShape8(1,1,1,1,1,1,1,0), 9)
139 };
140 
141 ///////////////////////////////////////////////////////////////////////////////
142 
143 
144 
145 ///////////////////////////////////////////////////////////////////////////////
146 // MatchBlendShapeFlipped: test if the given shape can be made to fit the
147 // template in either unflipped state, or by flipping the shape in U or V
148 template<class T>
149 bool MatchBlendShapeFlipped(const T& templateshape,const T& shape,unsigned int& flags)
150 {
151  // test unrotated shape
152  if (shape==templateshape) {
153  return true;
154  }
155 
156  // test against shape flipped in U
157  T tstShape;
158  templateshape.FlipU(tstShape);
159  if (shape==tstShape) {
160  flags|=BLENDMAP_FLIPU;
161  return true;
162  }
163 
164  // test against shape flipped in V
165  templateshape.FlipV(tstShape);
166  if (shape==tstShape) {
167  flags|=BLENDMAP_FLIPV;
168  return true;
169  }
170 
171  // no joy; no match by flipping
172  return false;
173 }
174 
175 ///////////////////////////////////////////////////////////////////////////////
176 // MatchBlendShape: try and find a matching blendmap, and the required flip/
177 // rotation flags, to fit the given shape to the template
178 template<class T>
179 int MatchBlendShape(const T& templateshape,const T& shape,unsigned int& flags)
180 {
181  // try matching unrotated shape first using just flipping
182  if (MatchBlendShapeFlipped(templateshape,shape,flags)) {
183  return true;
184  }
185 
186  // now try iterating through rotations of 90,180,270 degrees
187  T tstShape;
188  templateshape.Rotate90(tstShape);
189  if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
190  // update flags - note if we've flipped in u or v, we need to rotate in
191  // the opposite direction
192  flags|=flags ? BLENDMAP_ROTATE270 : BLENDMAP_ROTATE90;
193  return true;
194  }
195 
196  templateshape.Rotate180(tstShape);
197  if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
198  flags|=BLENDMAP_ROTATE180;
199  return true;
200  }
201 
202  templateshape.Rotate270(tstShape);
203  if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
204  // update flags - note if we've flipped in u or v, we need to rotate in
205  // the opposite direction
206  flags|=flags ? BLENDMAP_ROTATE90 : BLENDMAP_ROTATE270;
207  return true;
208  }
209 
210  return false;
211 }
212 
213 ///////////////////////////////////////////////////////////////////////////////
214 // LookupBlend: find and return the blendmap fitting the given shape by
215 // iterating through the given data table and testing each shape in flipped and
216 // rotated forms until a match is found
217 template<class S,class T>
218 int LookupBlend(int tableSize,const S* table,const T& shape,unsigned int& flags)
219 {
220  // iterate through known blend shapes
221  for (int b=0;b<tableSize;b++) {
222  const S& blend=table[b];
223  if (MatchBlendShape(blend.m_Shape,shape,flags)) {
224  return blend.m_AlphaMap;
225  }
226  }
227 
228  // eh? shouldn't get here if we've correctly considered all possible cases;
229  // keep the compiler happy, and, while we're still debugging possible shapes,
230  // return bad blend to highlight suspect alphamap logic
231  return 13;
232 }
233 
234 
235 ///////////////////////////////////////////////////////////////////////////////
236 // Calculate: return the index of the blend map that fits the given shape,
237 // and the set of flip/rotation flags to get the shape correctly oriented
238 int Calculate(BlendShape8 shape,unsigned int& flags)
239 {
240  // assume we're not going to require flipping or rotating
241  flags=0;
242 
243  // count number of neighbours
244  int count=0;
245  for (int i=0;i<8;i++) {
246  if (shape[i]) count++;
247  }
248 
249  if (count==0) {
250  // no neighbours, just the centre tile has the given texture; use blend circle
251  return 0;
252  } else if (count==8) {
253  // all neighbours have same texture; return code to signal no alphamap required
254  return -1;
255  } else {
256  if (count<=4) {
257  // check if we can consider this a BlendShape4 - ie are any of the diagonals (NE,SE,SW,NW) set?
258  if (!shape[1] && !shape[3] && !shape[5] && !shape[7]) {
259  // ok, build a BlendShape4 and use that
260  BlendShape4 shape4;
261  shape4[0]=shape[0];
262  shape4[1]=shape[2];
263  shape4[2]=shape[4];
264  shape4[3]=shape[6];
265 
266  switch (count) {
267  case 1:
268  return LookupBlend(sizeof(Blends1Neighbour)/sizeof(Blend4),Blends1Neighbour,shape4,flags);
269 
270  case 2:
271  return LookupBlend(sizeof(Blends2Neighbour)/sizeof(Blend4),Blends2Neighbour,shape4,flags);
272 
273  case 3:
274  return LookupBlend(sizeof(Blends3Neighbour)/sizeof(Blend4),Blends3Neighbour,shape4,flags);
275 
276  case 4:
277  // N,S,E,W have same texture, NE,SE,SW,NW don't; use a blend 4 corners
278  return 5;
279  }
280  }
281  }
282 
283 
284  // we've got this far, so now we've got to consider the remaining choices, all containing
285  // diagonal elements
286  switch (count) {
287  case 1:
288  // trivial case - just return a circle blend
289  return 0;
290 
291  case 2:
292  return LookupBlend(sizeof(Blends2Neighbour8)/sizeof(Blend8),Blends2Neighbour8,shape,flags);
293 
294  case 3:
295  return LookupBlend(sizeof(Blends3Neighbour8)/sizeof(Blend8),Blends3Neighbour8,shape,flags);
296 
297  case 4:
298  return LookupBlend(sizeof(Blends4Neighbour8)/sizeof(Blend8),Blends4Neighbour8,shape,flags);
299 
300  case 5:
301  return LookupBlend(sizeof(Blends5Neighbour8)/sizeof(Blend8),Blends5Neighbour8,shape,flags);
302 
303  case 6:
304  return LookupBlend(sizeof(Blends6Neighbour8)/sizeof(Blend8),Blends6Neighbour8,shape,flags);
305 
306  case 7:
307  return LookupBlend(sizeof(Blends7Neighbour8)/sizeof(Blend8),Blends7Neighbour8,shape,flags);
308  }
309 
310  }
311 
312  // Shouldn't get here if we've correctly considered all possible cases;
313  // keep the compiler happy, and, while we're still debugging possible shapes,
314  // return bad blend to highlight suspect alphamap logic
315  return 13;
316 }
317 
318 } // end of namespace
#define BLENDMAP_ROTATE90
#define BLENDMAP_FLIPU
#define BLENDMAP_FLIPV
const Blend8 Blends6Neighbour8[]
const Blend8 Blends4Neighbour8[]
const Blend8 Blends2Neighbour8[]
const Blend4 Blends3Neighbour[]
int MatchBlendShape(const T &templateshape, const T &shape, unsigned int &flags)
const Blend8 Blends7Neighbour8[]
const Blend4 Blends1Neighbour[]
Blend8(BlendShape8 shape, int alphamap)
#define T(string_literal)
Definition: secure_crt.cpp:70
int Calculate(BlendShape8 shape, unsigned int &flags)
bool MatchBlendShapeFlipped(const T &templateshape, const T &shape, unsigned int &flags)
const Blend4 Blends2Neighbour[]
const Blend8 Blends5Neighbour8[]
#define BLENDMAP_ROTATE270
int LookupBlend(int tableSize, const S *table, const T &shape, unsigned int &flags)
#define BLENDMAP_ROTATE180
Blend4(BlendShape4 shape, int alphamap)
const Blend8 Blends3Neighbour8[]