画像の無限平面化

テクスチャなどに使う画像は有限の大きさを持つが、これを無限平面として扱えるようになると便利だ。
たとえば画像の任意のピクセルを参照するときX,Yでその位置を指定するが、X,Yの範囲値はそれぞれ
0 <= X < Width, 0 <= Y < Height (Width:画像の幅,Height:画像の高さ)
になる。
この範囲を超えてアクセスした場合、エラーとなってしまう。

画像を無限の空間を持つものとして処理できるようになれば、任意のX,Yでもアクセスできる。
これには任意のX,Yを画像の幅、高さに収める処理が必要となる。これをコレスポンダと呼ぶ。
コレスポンダには以下のようなものが挙げられる。
・リピート:繰り返す

・ミラー:端で折り返す

・クランプ:端を超えていたら端の値とする

コレスポンダは任意の位置xと幅wから0 <= x' < w になる値x'を返す関数が定義できればいよい。
上記のリピート、ミラー、クランプについては以下のよう定義できる。

  int correspond_repeat (int x, int w){
    int n = x%w;
    if(n>=0)return   n;
    else    return   n+w;
  }

  int correspond_mirror (int x, int w){
    if(x<0){x = -x-1;}
    int s = (x/w)&1;
    int n = correspond_repeat(x,w);
    if(s)  return w-1-n;
    else   return n;
    
  }

  int correspond_clamp  (int x, int w){
    if(x<0)return 0;
    if(w-1<x)return w-1;
    return x;
  }

さらに幅wが2の累乗であったときリピートとミラーは高速化できる。

  bool is_powerof2(unsigned int x){
    return ((x-1)&x)==0;
  }
  int correspond_repeat_powerof2(int x, int w){
    assert(is_powerof2(w));//w is 2x

    int n = x&(w-1);// rem
    return n;
  }

  int correspond_mirror_powerof2(int x, int w){
    assert(is_powerof2(w));//w is 2x

    int n = x&(w-1);
    if(x&w) return w-1-n;
    else        return n;
  }

あとは画像の参照にコレスポンダを埋め込んであげればよい。

  template<class T>
  class repeaet_image:public image<T>{
  public:
    T get(int x, int y){
      x = correspond_repeat(x,get_width());
      y = correspond_repeat(y,get_height());
      return img->get(x,y);//内部のイメージにアクセス
    }  
    //略
  };