LCOV - code coverage report
Current view: top level - source/renderer - AlphaMapCalculator.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 21 98 21.4 %
Date: 2023-01-19 00:18:29 Functions: 4 11 36.4 %

          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

Generated by: LCOV version 1.13