Line data Source code
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 4 : Blend4(BlendShape4 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
37 :
38 : BlendShape4 m_Shape;
39 : int m_AlphaMap;
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 44 : Blend8(BlendShape8 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
47 :
48 : BlendShape8 m_Shape;
49 : int m_AlphaMap;
50 : };
51 :
52 : ///////////////////////////////////////////////////////////////////////////////
53 : // Data tables for mapping between shapes and blend maps
54 : ///////////////////////////////////////////////////////////////////////////////
55 :
56 1 : const Blend4 Blends1Neighbour[] =
57 : {
58 : Blend4(BlendShape4(1,0,0,0), 12)
59 1 : };
60 :
61 :
62 1 : const Blend4 Blends2Neighbour[] =
63 : {
64 : Blend4(BlendShape4(0,1,1,0), 7),
65 : Blend4(BlendShape4(1,0,1,0), 10)
66 1 : };
67 :
68 1 : const Blend8 Blends2Neighbour8[] =
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 1 : };
75 :
76 1 : const Blend4 Blends3Neighbour[] =
77 : {
78 : Blend4(BlendShape4(1,1,1,0), 4)
79 1 : };
80 :
81 1 : const Blend8 Blends3Neighbour8[] =
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 1 : };
94 :
95 1 : const Blend8 Blends4Neighbour8[] =
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 1 : };
110 :
111 1 : const Blend8 Blends5Neighbour8[] =
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 1 : };
124 :
125 1 : const Blend8 Blends6Neighbour8[] =
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 1 : };
134 :
135 1 : const Blend8 Blends7Neighbour8[] =
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 1 : };
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 0 : bool MatchBlendShapeFlipped(const T& templateshape,const T& shape,unsigned int& flags)
150 : {
151 : // test unrotated shape
152 0 : if (shape==templateshape) {
153 0 : return true;
154 : }
155 :
156 : // test against shape flipped in U
157 0 : T tstShape;
158 0 : templateshape.FlipU(tstShape);
159 0 : if (shape==tstShape) {
160 0 : flags|=BLENDMAP_FLIPU;
161 0 : return true;
162 : }
163 :
164 : // test against shape flipped in V
165 0 : templateshape.FlipV(tstShape);
166 0 : if (shape==tstShape) {
167 0 : flags|=BLENDMAP_FLIPV;
168 0 : return true;
169 : }
170 :
171 : // no joy; no match by flipping
172 0 : 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 0 : int MatchBlendShape(const T& templateshape,const T& shape,unsigned int& flags)
180 : {
181 : // try matching unrotated shape first using just flipping
182 0 : if (MatchBlendShapeFlipped(templateshape,shape,flags)) {
183 0 : return true;
184 : }
185 :
186 : // now try iterating through rotations of 90,180,270 degrees
187 0 : T tstShape;
188 0 : templateshape.Rotate90(tstShape);
189 0 : 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 0 : flags|=flags ? BLENDMAP_ROTATE270 : BLENDMAP_ROTATE90;
193 0 : return true;
194 : }
195 :
196 0 : templateshape.Rotate180(tstShape);
197 0 : if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
198 0 : flags|=BLENDMAP_ROTATE180;
199 0 : return true;
200 : }
201 :
202 0 : templateshape.Rotate270(tstShape);
203 0 : 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 0 : flags|=flags ? BLENDMAP_ROTATE90 : BLENDMAP_ROTATE270;
207 0 : return true;
208 : }
209 :
210 0 : 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 0 : int LookupBlend(int tableSize,const S* table,const T& shape,unsigned int& flags)
219 : {
220 : // iterate through known blend shapes
221 0 : for (int b=0;b<tableSize;b++) {
222 0 : const S& blend=table[b];
223 0 : if (MatchBlendShape(blend.m_Shape,shape,flags)) {
224 0 : 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 0 : 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 0 : int Calculate(BlendShape8 shape,unsigned int& flags)
239 : {
240 : // assume we're not going to require flipping or rotating
241 0 : flags=0;
242 :
243 : // count number of neighbours
244 0 : int count=0;
245 0 : for (int i=0;i<8;i++) {
246 0 : if (shape[i]) count++;
247 : }
248 :
249 0 : if (count==0) {
250 : // no neighbours, just the centre tile has the given texture; use blend circle
251 0 : return 0;
252 0 : } else if (count==8) {
253 : // all neighbours have same texture; return code to signal no alphamap required
254 0 : return -1;
255 : } else {
256 0 : if (count<=4) {
257 : // check if we can consider this a BlendShape4 - ie are any of the diagonals (NE,SE,SW,NW) set?
258 0 : if (!shape[1] && !shape[3] && !shape[5] && !shape[7]) {
259 : // ok, build a BlendShape4 and use that
260 0 : BlendShape4 shape4;
261 0 : shape4[0]=shape[0];
262 0 : shape4[1]=shape[2];
263 0 : shape4[2]=shape[4];
264 0 : shape4[3]=shape[6];
265 :
266 0 : switch (count) {
267 0 : case 1:
268 0 : return LookupBlend(sizeof(Blends1Neighbour)/sizeof(Blend4),Blends1Neighbour,shape4,flags);
269 :
270 0 : case 2:
271 0 : return LookupBlend(sizeof(Blends2Neighbour)/sizeof(Blend4),Blends2Neighbour,shape4,flags);
272 :
273 0 : case 3:
274 0 : return LookupBlend(sizeof(Blends3Neighbour)/sizeof(Blend4),Blends3Neighbour,shape4,flags);
275 :
276 0 : case 4:
277 : // N,S,E,W have same texture, NE,SE,SW,NW don't; use a blend 4 corners
278 0 : 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 0 : switch (count) {
287 0 : case 1:
288 : // trivial case - just return a circle blend
289 0 : return 0;
290 :
291 0 : case 2:
292 0 : return LookupBlend(sizeof(Blends2Neighbour8)/sizeof(Blend8),Blends2Neighbour8,shape,flags);
293 :
294 0 : case 3:
295 0 : return LookupBlend(sizeof(Blends3Neighbour8)/sizeof(Blend8),Blends3Neighbour8,shape,flags);
296 :
297 0 : case 4:
298 0 : return LookupBlend(sizeof(Blends4Neighbour8)/sizeof(Blend8),Blends4Neighbour8,shape,flags);
299 :
300 0 : case 5:
301 0 : return LookupBlend(sizeof(Blends5Neighbour8)/sizeof(Blend8),Blends5Neighbour8,shape,flags);
302 :
303 0 : case 6:
304 0 : return LookupBlend(sizeof(Blends6Neighbour8)/sizeof(Blend8),Blends6Neighbour8,shape,flags);
305 :
306 0 : case 7:
307 0 : 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 0 : return 13;
316 : }
317 :
318 3 : } // end of namespace
|