D2.0とSDL/OpenGLでライフゲーム作った。

のっけから余談ですが、先日発売になった"EeePC901"を買ってしまった。
6万であの性能なら、まぁ文句は無いでしょう。
Dの開発環境も乗っけたし、これで何処でもDと一緒(^q^)



スキルアップも兼ねてOpenGLも使ってみる事にした。


前回はD1.0を使っていたが、今回からはD2.0で行きます。
でも何故またD2.0に戻したか、といいますと。
少し前まではOpenGLのportingがデフォのままでは使えなかったのが
今回試してみたらバッチリ修正されていた為です。


(ちなみに問題だった部分は、D2.0から予約語登録された"ref"が
 portingの中で仮引数に使われていた所だったはず。)


では今回もビクビクしながら晒します。
前回と比べると、マウスによる生死の操作ができなくなっています。
だって面倒なんだもの。
後は、OpenGLで"頂点配列"というものを使ってみたつもりです。
全然美しくないけど・・・。

/* 頂点配列を使ったバージョン */
import std.stdio;
import std.conv;
import std.random;
import std.date;
import std.string;
import SDL;
import opengl;
import openglu;

invariant int g_Magnification = 2;

class fpsCounter {
private:
  Uint32 m_StartTick;
  Uint32 m_EndTick;
  int    m_Result;
  int    m_Counter;
public:
  this() {
    m_StartTick = SDL_GetTicks();
    m_EndTick   = 0;
    m_Result    = 0;
    m_Counter   = 0;
  }
	
  void calc() {
	
    m_EndTick = SDL_GetTicks();
    if( m_EndTick - m_StartTick > 1000 ) {			
      m_Result    = m_Counter;
      m_Counter   = 0;
      m_StartTick = m_EndTick;
    } else {
      m_Counter++;
    }
		
  }
	
  int Result() { return m_Result; }
};

class island {
private:
  typedef int[2]    vertex;
  typedef vertex[4] inhabitant;
	
  const uint m_Width;
  const uint m_Height;

  inhabitant[] m_Inhabits;
  bool[][]     m_Fields;
  bool         m_Freezing   = false;
  uint         m_Generation = 1;
public:

  this( int p_Width, int p_Height ) {
    m_Width  = p_Width;
    m_Height = p_Height;
		
    m_Fields.length     = m_Height;
    for( int y=0; y < m_Height; y++ ) {
      m_Fields[y].length     = m_Width;
      for( int x=0; x < m_Width; x++ ) {
        m_Fields[y][x]     = false;
      }
    }	
  }
	
  //Setter
  void Freezing( bool p_Freezing ) { m_Freezing = p_Freezing; }
  //Getter
  bool Freezing()                  { return m_Freezing; }
	
  //Setter
  void Generation( uint p_Generation ) { m_Generation = p_Generation; }
  //Getter
  uint Generation()                    { return m_Generation; }
	
  bool opIndex( int p_x, int p_y ) {
    return m_Fields[p_y][p_x];
  }

  void opIndexAssign( bool p_living, int p_x, int p_y ) {
    m_Fields[p_y][p_x] = p_living;
  }

  void randomize( int p_Probability ) {

    inhabitant l_Inhabit;
    bool       l_living;
	
    for( int y=0; y < m_Height; y++ ) {
      for( int x=0; x < m_Width; x++ ) {

        if( rand()%100 <= p_Probability ) {
          m_Inhabits ~= cast(inhabitant)([ [x,y],[x+1,y],[x+1,y+1],[x,y+1] ]);
          this[x,y] = true;					
        }

      }
    }

    m_Generation = 1;

  }
	
  void print() {

    clear();	

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2 , GL_INT, 0 , cast(int*)m_Inhabits);
    glDrawArrays(GL_QUADS , 0 , m_Inhabits.length*4);
			
    flip();	
  }
	
  void next() {
	
    int l=0,r=0,u=0,d=0,i=0;
    bool[][] l_NextFields;
		
    l_NextFields.length = m_Height;
    for( i=0; i < m_Height; i++ )
      l_NextFields[i].length = m_Width;

    if( ++m_Generation > 100000000 )
      m_Generation = 1;

    m_Inhabits.length = 0;

    for( int y=0; y < m_Height; y++ ) {
      for( int x=0; x < m_Width; x++ ) {

        i = 0;

        l = (x + m_Width - 1) % m_Width;
        r = (x + 1) % m_Width;
        u = (y + m_Height - 1) % m_Height;
        d = (y + 1) % m_Height;

        if(this[l,u]) i++; if(this[x,u]) i++; if(this[r,u]) i++;
        if(this[l,y]) i++;                    if(this[r,y]) i++;				
        if(this[l,d]) i++; if(this[x,d]) i++; if(this[r,d]) i++;

        if( ( (this[x,y]) && (i==2) ) ||(i==3) ) {				
          m_Inhabits ~= cast(inhabitant)([ [x,y], [x+1,y], [x+1,y+1], [x,y+1] ]);
          l_NextFields[y][x] = true;
        }
      }
    }
		
    m_Fields = l_NextFields;
		
  }

};

void clear() {
  glClear(GL_COLOR_BUFFER_BIT);
  return;
}

void flip() {
  SDL_GL_SwapBuffers();
  return;
}

bool PropertysCheck( string[] p_args, out int p_Width, out int p_Height, out int p_Probability, out int p_StopCount ) {

  if( p_args.length <> 5 ) {
    writefln("Parameters Disposition Failed.\n1:Width, 2:Height, 3:Probability, 4:StopCount.");
    return false;		
  }

  p_Width         = toInt(p_args[1]);
  p_Height        = toInt(p_args[2]);
  p_Probability   = toInt(p_args[3]);
  p_StopCount     = toInt(p_args[4]);

  if( (p_Width < 100) || (p_Width > 500) ) {
    writefln("Please Wedth length between 100 and 300.");
    return false;
  }

  if( (p_Height < 100) || (p_Height > 500) ) {
    writefln("Please Height length between 100 and 300.");
    return false;
  }

  if( (p_Probability <= 0) || (p_Probability >= 100) ) {
    writefln("Please Probability Value between 1 and 99.");
    return false;
  }

  if( p_StopCount < 0 ) {
    writefln("Please StopCount value over 0.");
    return false;
  }

  return true;

}

bool Init( int p_Width, int p_Height ) {

  SDL_VideoInfo* l_Info = null;

  writefln("SDL Initialize.");

  if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
    writefln("SDL Initialize Failed. : %s.", SDL_GetError());
    return false;
  }

  l_Info = SDL_GetVideoInfo();

  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
  //SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 0);


  if( SDL_SetVideoMode( p_Width * g_Magnification,
                        p_Height * g_Magnification,
                        l_Info.vfmt.BitsPerPixel,
                        SDL_OPENGL                  ) == null ) {
    writefln("Set Video Mode Failed. :%s", SDL_GetError() );
    return false;
  }
	
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, p_Width , 0, p_Height, 0, 10);

  glViewport(0, 0, p_Width * g_Magnification, p_Height * g_Magnification);
  glClearColor( 0, 0, 0, 0 );
	
  //SDL_ShowCursor( SDL_DISABLE );

  return true;

}

void End() {

  writefln("SDL Finalise.");

  SDL_Quit();

}

bool PollEvent( ref island p_Island ) {

  SDL_Event l_Event;
  SDLKey*   l_Key;

  while( SDL_PollEvent(&l_Event) ) {

    switch( l_Event.type ) {

      case SDL_QUIT:{
        return false;
      }break;

      case SDL_KEYDOWN:{
        l_Key = &(l_Event.key.keysym.sym);				
        switch (*l_Key) {

          case SDLK_SPACE:{
            p_Island.Freezing = !p_Island.Freezing;
          }break;

          case SDLK_ESCAPE:{
            return false;
          }break;

          default:{
          }break;				
        }				
      }break;

      default:{
      }break;

    }
  }
  return true;
}

int main( string[] args ) {

  int l_Width = 0, l_Height = 0, l_Probability = 0, l_StopCount = 0;
  rand_seed( getUTCtime(), 0 );	

  //引数チェック
  if( !PropertysCheck( args, l_Width, l_Height, l_Probability, l_StopCount ) ) return -1;

  if( !Init( l_Width, l_Height ) ) return 0;

  fpsCounter l_FPS = new fpsCounter();

  island l_Island = new island( l_Width, l_Height );
  l_Island.randomize( l_Probability );

  while( true ) {

    l_FPS.calc();		
    SDL_WM_SetCaption( cast(char*)toStringz(format("lifegame Generation:%d FPS:%6d",
                                                   l_Island.Generation,
                                                   l_FPS.Result)), null);

    l_Island.print();

    if( !l_Island.Freezing)
      l_Island.next();

    if( l_Island.Generation == l_StopCount )
      l_Island.Freezing = true;

    if( !PollEvent( l_Island ) ) break;
		
  }

  End();

  return 0;

}


一応こんな感じになりました。
SDL版とFPS比較しても、そんな差は出ませんでした。
俺のコーディングが悪いんだ・・・。


とりあえずこれからも、ぼちぼちOpenGLを触って行こうかと思います。