Logo Search packages:      
Sourcecode: tatan version File versions  Download package

hell2.d

module util.hell2;
private import std.string;
private import std.file;
private import std.path;
private import std.cstream;
private import std.ctype;
private import std.math;
private import std.math2;
private import std.c.stdio;
private import std.format;
private import std.utf;
private import std.random;
private import SDL;
private import SDL_mixer;
private import opengl;
private import openglu;

private:
static int g_width;
static int g_height;
static int g_videoBpp;
static int g_videoFlags;
static SDL_Surface* g_screen;
static Texture [char[]] g_poolTexture;
static Texture g_fontTexture;
static Mix_Chunk* [char[]] g_poolChunk;
static Mix_Music* g_music = null;
static SDL_Surface* [int] g_poolFont;
static bool g_quit = false;
static bool g_init = false;
static ubyte g_pressMouseButtonPrev = 0;
static ubyte g_pressMouseButton = 0;
static bool[SDLK_LAST] g_pressKeyButtonPrev;
static bool[SDLK_LAST] g_pressKeyButton;
static const char[] g_logname = "run.log";
// OpenGL
//static GLUquadricObj* g_quadricObj; // 2次曲面オブジェクト

/**
 * 十字キーのプラス方向の入力判定
 */
static const AXIS_PRESSED_PLUS  =  32768 * 8 / 10;
/**
 * 十字キーのマイナス方向の入力判定
 */
static const AXIS_PRESSED_MINUS = -32768 * 8 / 10;
bool _isLeftJ(Sint16 axisX)
{
      return axisX < AXIS_PRESSED_MINUS;
}
bool _isUpJ(Sint16 axisY)
{
      return axisY < AXIS_PRESSED_MINUS;
}
bool _isRightJ(Sint16 axisX)
{
      return axisX > AXIS_PRESSED_PLUS;
}
bool _isDownJ(Sint16 axisY)
{
      return axisY > AXIS_PRESSED_PLUS;
}
static Sint16 g_joyXPrev;
static Sint16 g_joyYPrev;
static Sint16 g_joyX;
static Sint16 g_joyY;
static bool[] g_joyButtonPrev;
static bool[] g_joyButton;
static SDL_Joystick* g_joy;
static int g_joyButtonNum;
static char[] FONT_PATH = "resource/font/font.bmp";

static int fps_cnt;
static int fps_view;
static Uint32 fps_lastTick;

/**
 * ウィンドウ・フルスクリーンモードの切り替え
 */
void _toggleFullScreen()
{
      g_videoFlags ^= SDL_FULLSCREEN;
      // スクリーン初期化
      if((g_screen = SDL_SetVideoMode(g_width, g_height, g_videoBpp, g_videoFlags)) is null)
      {
            throw new Error("_toggleFullScreen: Couldn't set video mode");
      }
      glOrtho(0, g_width, g_height, 0, -1, 1); 
      glViewport(0, 0, g_width, g_height);
      glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
      _reloadTexture();
      Hell_setAlpha(g_alpha_prev);
}

/**
 * マウスカーソル表示切替
 */
void _toggleShowCursor()
{
      if(SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) SDL_ShowCursor(SDL_DISABLE);
      else                                        SDL_ShowCursor(SDL_ENABLE);
}
/**
 * フォントの読み込み
 */
public void Hell_loadFont()
{
      g_fontTexture = new Texture(FONT_PATH, 0x00, 0xff, 0x00); // 緑を抜き色で
}

public:
const static uint HELL_BUTTON_LEFT   = SDL_PRESSED << (SDL_BUTTON_LEFT-1);
const static uint HELL_BUTTON_MIDDLE = SDL_PRESSED << (SDL_BUTTON_MIDDLE-1);
const static uint HELL_BUTTON_RIGHT  = SDL_PRESSED << (SDL_BUTTON_RIGHT-1);
enum {
      HELL_RETURN = SDLK_RETURN,
      HELL_ESCAPE = SDLK_ESCAPE,
      HELL_SPACE  = SDLK_SPACE,
      HELL_c      = SDLK_c,
      HELL_x      = SDLK_x,
      HELL_z      = SDLK_z,
      HELL_UP     = SDLK_UP,
      HELL_DOWN   = SDLK_DOWN,
      HELL_RIGHT  = SDLK_RIGHT,
      HELL_LEFT   = SDLK_LEFT,
}
enum {
      HELL_J_UP,
      HELL_J_DOWN,
      HELL_J_RIGHT,
      HELL_J_LEFT,
      HELL_J_MAX,
}

/**
 * テクスチャを全て読み直し
 */
void _reloadTexture()
{
      delete g_fontTexture;
      Hell_loadFont();
      foreach(key; g_poolTexture.keys)
      {
            char[] path = g_poolTexture[key].getPath();
            int mask[]  = g_poolTexture[key].getMaskInfo();
            Hell_loadTexture(key, path, [mask[0], mask[1], mask[2]]);
      }
}

/**
 * スクリーンショットをBMPで保存
 */
void _saveBmp()
{
      auto line = g_width*3; // スキャンライン
      // メモリ確保
      scope pixels = new GLubyte[g_width*line];
      // データ格納のサイズを設定
      glPixelStorei(GL_PACK_ALIGNMENT, 1);
      // データの読み出し
      glReadPixels(0, 0, g_width, g_height, GL_RGB, GL_UNSIGNED_BYTE, pixels.ptr);
      
      // 上下反転
      for(int j = 0; j < g_height/2; j++)
      {
            for(int i = 0; i < line; i++)
            {
                  auto ptr1 = line*j + i;
                  auto ptr2 = line*(g_height-1-j) + i;
                  auto tmp  = pixels[ptr1];
                  pixels[ptr1] = pixels[ptr2];
                  pixels[ptr2] = tmp;
            }
      }
      if(auto surface = SDL_CreateRGBSurfaceFrom(
            pixels.ptr,
            g_width, g_height, 24, line,
            0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000))
      {
            SDL_SaveBMP(surface, "hellshot.bmp");
            SDL_FreeSurface(surface);
      }
}

/**
 * SDL初期化
 */
void Hell_init(char[] caption, int width=640, int height=480, bool fullscreen=false)
{
      if(g_init) return;
      g_width      = width;
      g_height     = height;
      g_videoBpp   = 0;
      g_videoFlags = SDL_OPENGL;
      if(fullscreen)
      {
            g_videoFlags |= SDL_FULLSCREEN;
      }
      
      if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0)
      {
            throw new Error("Hell_init: Couldn't initialize SDL");
      }
      // スクリーン初期化
      if((g_screen = SDL_SetVideoMode(g_width, g_height, g_videoBpp, g_videoFlags)) is null)
      {
            throw new Error("Hell_init: Couldn't set video mode");
      }
      if(fullscreen)
      {
            _toggleShowCursor(); // フルスクリーン時はマウスカーソルを消す
      }
      
      glOrtho(0, g_width, g_height, 0, -1, 1); 
      glViewport(0, 0, g_width, g_height);
      glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
      Hell_setCaption(caption);
      // アイコン設定
      SDL_Surface* icon = SDL_LoadBMP("resource/hell.bmp");
      SDL_WM_SetIcon(icon, null);
      // サウンド初期化(音を良くしたい場合、下のコメントを外す)
//    if(Mix_OpenAudio(44100, AUDIO_S16, 2, 8192) < 0)
      if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) < 0)
      {
            throw new Error("Hell_init: " ~ toString(SDL_GetError()));
      }
      
      // ログ初期化
      write(g_logname, "");
      if(SDL_NumJoysticks() > 0)
      {
            // ジョイスティック生成
            g_joy = SDL_JoystickOpen(0);
            if(!g_joy)
            {
                  throw new Error(toString(SDL_GetError()));
            }
            g_joyButtonNum = SDL_JoystickNumButtons(g_joy);
            g_joyButtonPrev = new bool[g_joyButtonNum];
            g_joyButton = new bool[g_joyButtonNum];
      }
      else
      {
            g_joy = null;
            g_joyButtonNum = 0;
      }
      
      // フォントの読込
      Hell_loadFont();
      
      // 曲面オブジェクト生成
//    g_quadricObj = gluNewQuadric();
      
      glEnable(GL_BLEND);
      g_init = true;
}

/**
 * 終了処理
 */
void Hell_quit()
{
      // 曲面オブジェクト破棄
//    gluDeleteQuadric(g_quadricObj);
      
      // テクスチャ破棄
      delete g_fontTexture;
      Hell_disposeTexture();
      
      if(g_joy) SDL_JoystickClose(g_joy);
      Hell_stopWAV();
      Mix_HaltMusic();
      if(!g_music)
      {
            Mix_FreeMusic(g_music);
      }
      Hell_disposeWAV();
      Mix_CloseAudio();
      SDL_Quit();
}

/**
 * キャプション設定(※日本語不可)
 */
void Hell_setCaption(...)
{
      char[] _caption = "";
      void _putc(dchar c)
      {
            auto tmp = [c];
            _caption ~= toUTF8(tmp);
      }
      doFormat(&_putc, _arguments, _argptr);
      SDL_WM_SetCaption(toStringz(_caption), null);
}


/**
 * ログ書き込み
 */
void Hell_write(...)
{
      void _putc(dchar c)
      {
            fputc(c, stdout);
            auto tmp = [c];
            append(g_logname, toUTF8(tmp));
      }
      doFormat(&_putc, _arguments, _argptr);
}

void Hell_write(Exception e)
{
      dout.writeLine(e.toString());
      append(g_logname, e.toString() ~ "\n");
}

/**
 * 画面を消去
 */
void Hell_begin()
{
      glClear(GL_COLOR_BUFFER_BIT);
}
/**
 * 画面を更新
 */
void Hell_update()
{
      SDL_GL_SwapBuffers();
}

/**
 * いったん停止。入力を更新
 */
void Hell_wait(int ms)
{
      // ウエイト
      Uint32 nowTick , leftTick;
      static Uint32 prvTick = 0;
      
      if(prvTick == 0) prvTick = SDL_GetTicks();
      
      while (true){
            nowTick = SDL_GetTicks();
            leftTick = prvTick + ms - nowTick;
            if(leftTick < 1 || leftTick > 9999) break;
            SDL_Delay(1);
      }
      prvTick = nowTick;
      
      // マウス更新
      g_pressMouseButtonPrev = g_pressMouseButton;
      g_pressMouseButton     = SDL_GetMouseState(null, null);
      
      // キーボード更新
      foreach(i, key; g_pressKeyButton)
      {
            g_pressKeyButtonPrev[i] = key;
      }
      ubyte* keys = SDL_GetKeyState(null);
      for(int i = 0; i < SDLK_LAST; i++)
      {
            g_pressKeyButton[i] = keys[i] == SDL_PRESSED;
      }
      // ジョイスティック更新
      SDL_JoystickUpdate();
      for(int i = 0; i < g_joyButtonNum; i++)
      {
            g_joyButtonPrev[i] = g_joyButton[i];
            g_joyButton[i] = SDL_JoystickGetButton(g_joy, i) == SDL_PRESSED;
      }
      g_joyXPrev = g_joyX;
      g_joyYPrev = g_joyY;
      g_joyX = SDL_JoystickGetAxis(g_joy, 0);
      g_joyY = SDL_JoystickGetAxis(g_joy, 1);

      // イベント更新
      SDL_Event e;
      while(SDL_PollEvent(&e)) g_quit = (e.type == SDL_QUIT);
      if(Hell_isPushKey(SDLK_F4))      _reloadTexture();
      if(Hell_isPushKey(SDLK_F5))      SDL_WM_IconifyWindow();
      if(Hell_isPushKey(SDLK_F9))      _toggleFullScreen();
      if(Hell_isPushKey(SDLK_F10))     _toggleShowCursor();
      if(Hell_isPushKey(SDLK_F12))     _saveBmp();
      if(Hell_isPressKey(SDLK_ESCAPE)) g_quit = true;
      if(g_quit) throw new Error("dHell system quit.");
      
      // fps計測
      fps_cnt++;
      if(cast(int)fps_lastTick / 1000 != cast(int)nowTick / 1000){
            fps_view = fps_cnt;
            fps_cnt = 0;
            fps_lastTick = nowTick;
      }
}

/**
 * マウス座標Xの取得
 */
int Hell_getMouseX()
{
      int x, y;
      ubyte button = SDL_GetMouseState(&x, &y);
      return x;
}

/**
 * マウス座標Yの取得
 */
int Hell_getMouseY()
{
      int x, y;
      ubyte button = SDL_GetMouseState(&x, &y);
      return y;
}

/**
 * マウスを押し続けているかどうか
 */
ubyte Hell_isPressMouse()
{
      return g_pressMouseButton;
}

/**
 * マウスをその瞬間に押したかどうか
 * <br>
 * Hell_wait()で更新
 */
ubyte Hell_isPushMouse()
{
      return cast(ubyte)(g_pressMouseButton ^ (g_pressMouseButton & g_pressMouseButtonPrev));
}

/**
 * キーを押し続けているかどうか
 */
bool Hell_isPressKey(int id)
{
      if(id < 0 || SDLK_LAST <= id) return false;
      return g_pressKeyButton[id];
}

/**
 * キーをその瞬間に押したかどうか
 * <br>
 * Hell_wait()で更新
 */
bool Hell_isPushKey(int id)
{
      if(id < 0 || SDLK_LAST <= id) return false;
      return g_pressKeyButton[id] && !g_pressKeyButtonPrev[id];
}

/**
 * ジョイスティックの十字キーを押しているかどうか
 */
bool Hell_isPressJKey(int id)
{
      if(!g_joy) return false;
      if(id < 0 || HELL_J_MAX < id) return false;
      switch(id)
      {
      case HELL_J_UP:
            return _isUpJ(g_joyY);
      case HELL_J_DOWN:
            return _isDownJ(g_joyY);
      case HELL_J_LEFT:
            return _isLeftJ(g_joyX);
      case HELL_J_RIGHT:
            return _isRightJ(g_joyX);
      default:
            return false;
      }
      return false;
}

/**
 * ジョイスティックの十字キーを押したかどうか
 */
bool Hell_isPushJKey(int id)
{
      if(!g_joy) return false;
      if(id < 0 || HELL_J_MAX < id) return false;
      switch(id)
      {
      case HELL_J_UP:
            return _isUpJ(g_joyY) && !_isUpJ(g_joyYPrev);
      case HELL_J_DOWN:
            return _isDownJ(g_joyY) && !_isDownJ(g_joyYPrev);
      case HELL_J_LEFT:
            return _isLeftJ(g_joyX) && !_isLeftJ(g_joyXPrev);
      case HELL_J_RIGHT:
            return _isRightJ(g_joyX) && !_isRightJ(g_joyXPrev);
      default:
            return false;
      }
      return false;
}

/**
 * ジョイスティックのボタンを押しているかどうか
 */
bool Hell_isPressJButton(int id)
{
      if(!g_joy) return false;
      if(id < 0 || g_joyButtonNum < id) return false;
      return g_joyButton[id];
}

/**
 * ジョイスティックのボタンを押したかどうか
 * <br>
 * Hell_wait()で更新
 */
bool Hell_isPushJButton(int id)
{
      if(!g_joy) return false;
      if(id < 0 || g_joyButtonNum < id) return false;
      return g_joyButton[id] && !g_joyButtonPrev[id];
}

/**
 * SE(WAVファイル)の読み込み
 * @param key  キー
 * @param path サウンドファイルのパス
 */
void Hell_loadWAV(char[] key, char[] path)
{
      if(key in g_poolChunk)
      {
            Hell_disposeWAV(key);
      }
      Mix_Chunk* chunk = Mix_LoadWAV(toStringz(path));
      if(!chunk)         { throw new Error(format("Hell_loadWAV: %s(%.*s)", SDL_GetError(), path)); }
      g_poolChunk[key] = chunk;
}

/**
 * SE(WAVファイル)の再生
 * @param key     キー
 * @param loops   ループ回数(-1で無限ループ)
 * @param channel チャンネル番号(-1であいているチャンネルを自動で使う)
 */
void Hell_playWAV(char[] key, int loops=0, int channel=-1)
{
      if(!(key in g_poolChunk)) { throw new Error("Hell_playWAV: Has not exist key: " ~ key); }
      Mix_PlayChannel(channel, g_poolChunk[key], loops);
}

/**
 * SE(WAVファイル)を停止
 * @param channel 停止チャンネル番号(-1で全て停止)
 */
void Hell_stopWAV(int channel=-1)
{
      Mix_HaltChannel(channel);
}

/**
 * SEを破棄
 * @param key   キー(nullで全て破棄)
 */
void Hell_disposeWAV(char[] key=null)
{
      if(key is null)
      {
            foreach(k, chunk; g_poolChunk)
            {
                  Mix_FreeChunk(chunk);
                  g_poolChunk.remove(k);
            }
            return;
      }
      if(!(key in g_poolChunk)) { throw new Error("Hell_disposeWAV: Has not exist key: " ~ key); }
      Mix_Chunk* chunk = g_poolChunk[key];
      Mix_FreeChunk(chunk);
      g_poolChunk.remove(key);
}

/**
 * BGMを再生する
 * @param path  ファイルパス
 * @param loops ループ回数(-1で無限ループ)
 * @param ms    フェードイン時間(ms)
 */
void Hell_playBgm(char[] path, int loops=-1, int ms=0)
{
      if(g_music)
      {
            Mix_HaltMusic();
            Mix_FreeMusic(g_music);
      }
      g_music = Mix_LoadMUS(cast(char*)(path ~ "\0"));
      if(!g_music)
      {
            throw new Error("Hell_playBgm: " ~ toString(SDL_GetError()));
      }
      if(ms <= 0)
      {
            if(Mix_PlayMusic(g_music, loops) != 0)
            {
                  throw new Error("Hell_playBgm: " ~ toString(SDL_GetError()));
            }
      }
      else
      {
            if(Mix_FadeInMusic(g_music, loops, ms) != 0)
            {
                  throw new Error("Hell_playBgm: " ~ toString(SDL_GetError()));
            }
      }
}

/**
 * BGMを停止する
 * @param ms    フェードアウト時間(ms)
 */
void Hell_stopBgm(int ms)
{
      if(g_music)
      {
            if(ms <= 0)
            {
                  Mix_HaltMusic();
                  Mix_FreeMusic(g_music);
                  g_music = null;
            }
            else
            {
                  Mix_FadeOutMusic(ms);
            }
      }
}

/**
 * 矩形の描画
 * @param x     X座標
 * @param y     Y座標
 * @param dx    幅
 * @param dy    高さ
 * @param width 線の太さ(0で塗りつぶし)
 * @param r     R成分
 * @param g     G成分
 * @param b     B成分
 * @param a     A成分
 */
void Hell_drawRect(int x=0, int y=0, int dx=0, int dy=0, int width=0, float rot=0, ubyte r=0x00, ubyte g=0x00, ubyte b=0x00, ubyte a=0xff)
{
      Texture.unbind();
      
      if(dx == 0 || dy == 0)
      {
            dx = g_width;
            dy = g_height;
      }
      
      glPushMatrix();
      glColor4ub(r, g, b, a);
      glTranslatef(x, y, 0);
      if(rot != 0)
      {
            glTranslatef(dx/2, dy/2, 0);
            // 左回り
            glRotatef(rot, 0, 0, -1);
            glTranslatef(-dx/2, -dy/2, 0);
      }
      if(width <= 0)
      {
            // 塗りつぶし
            glBegin(GL_POLYGON);
      }
      else
      {
            // 塗りつぶしなし
            glLineWidth(width);
            glBegin(GL_LINE_LOOP);
      }
      
      {
            {
                  glVertex3f(0,  0, 0);
                  glVertex3f(dx, 0, 0);
                  glVertex3f(dx, dy, 0);
                  glVertex3f(0,  dy, 0);
            }
            glEnd();
      }
      glPopMatrix();
}
void Hell_drawRectEx(int cx=0, int cy=0, int dx=0, int dy=0, int width=0, float rot=0, ubyte r=0x00, ubyte g=0x00, ubyte b=0x00, ubyte a=0xff)
{
      Hell_drawRect(cx-dx, cy-dy, dx*2, dy*2, width, rot, r, g, b, a);
}

/**
 * 線分の描画
 * @param x1    開始X座標
 * @param y1    開始Y座標
 * @param x2    終了X座標
 * @param y2    終了Y座標
 * @param width 線の太さ
 * @param r     R成分
 * @param g     G成分
 * @param b     B成分
 * @param a     A成分
 */
void Hell_drawLine(float x1, float y1, float x2, float y2, int width=1, ubyte r=0x00, ubyte g=0x00, ubyte b=0x00, ubyte a=0xff)
{
      if(width < 1) return;
      Texture.unbind();
      glPushMatrix();
      glColor4ub(r, g, b, a);
      glTranslatef(x1, y1, 0);

      glLineWidth(width);
      glBegin(GL_LINES);
      {
            glVertex3f(x1, y1, 0);
            glVertex3f(x2, y2, 0);
      }
      glEnd();

      glPopMatrix();
}

/**
 * 三角形の描画
 * @param x      X座標(中心)
 * @param y      Y座標(中心)
 * @param radius 半径
 * @param rot    回転角度(0~360)
 * @param width  線の太さ(0で塗りつぶし)
 * @param r     R成分
 * @param g     G成分
 * @param b     B成分
 * @param a     A成分
 */
void Hell_drawTriangle(float x, float y, float radius, float rot=0, int width=1, ubyte r=0x00, ubyte g=0x00, ubyte b=0x00, ubyte a=0xff)
{
      if(radius < 1) return;
      Texture.unbind();
      glPushMatrix();
      glColor4ub(r, g, b, a);
      glTranslatef(x, y, 0);
      if(rot != 0) glRotatef(rot, 0, 0, -1);
      if(width <= 0)
      {
            // 塗りつぶし
            glBegin(GL_POLYGON);
      }
      else
      {
            // 塗りつぶしなし
            glLineWidth(width);
            glBegin(GL_POINTS);
      }
      
      {
            {
                  glVertex3f(0,                -radius,  0);
                  glVertex3f(-radius*1.713f/2, radius/2, 0);
                  glVertex3f( radius*1.713f/2, radius/2, 0);
            }
            glEnd();
      }
      glPopMatrix();
}

/**
 * 円の描画
 * @param cx 中心座標X
 * @param cy 中心座標Y
 * @param radius 半径
 * @param width  線の太さ(0で塗りつぶし)
 * @param r     R成分
 * @param g     G成分
 * @param b     B成分
 * @param a     A成分
 */
void Hell_drawCircle(float cx, float cy, float radius, int width=1, ubyte r=0x00, ubyte g=0x00, ubyte b=0x00, ubyte a=0xff)
{
      if(radius <= 0) return;
      Texture.unbind();
      glPushMatrix();
      glColor4ub(r, g, b, a);
      if(width <= 0)
      {
            // 塗りつぶし
            glBegin(GL_POLYGON);
      }
      else
      {
            // 塗りつぶしなし
            glLineWidth(width);
            glBegin(GL_LINE_LOOP);
      }
      
      {
            {
                  // 超遅い円描画ルーチン
                  for(float i = 0; i < 3.1421356f*2; i+=0.3f)
                  {
                        glVertex3f(cx + radius*cos(i), cy + radius*sin(i), 0);
                  }
            }
            glEnd();
      }
      glPopMatrix();
}

/**
 * テクスチャの描画(左上から描画)
 * <pre>
 * ※抜き色を有効にする場合、Hell_setAlpha()に「HELL_ALPHA_NORMAL/HELL_ALPHA_ADD」を指定する必要があります。
 * </pre>
 * @param key キー(Hell_loadTextureで読み込み済みのもの)
 * @param x   X座標
 * @param y   Y座標
 * @param ox  切り取り開始X座標
 * @param oy  切り取り開始Y座標
 * @param ow  切り取る幅
 * @param oh  切り取る高さ
 * @param dx  拡大サイズ(X)
 * @param dy  拡大サイズ(Y)
 * @param rot 回転角度(0~360。左回り)
 * @param r   マスク色(赤)
 * @param g   マスク色(緑)
 * @param b   マスク色(青)
 */
void Hell_drawTexture(
      char[] key,
      float x, float y,
      int ox=0, int oy=0, int ow=0, int oh=0,
      float dx=1.0f, float dy=1.0f,
      float rot=0,
      ubyte r=255, ubyte g=255, ubyte b=255)
{
      if(!(key in g_poolTexture)) { throw new Error("Hell_drawTexture: Has not exist key: " ~ key); }
      Texture tex = g_poolTexture[key];
      if(ow == 0 || oh == 0)
      {
            ow = tex._width;
            oh = tex._height;
      }
      float w  = ow * dx;
      float h  = oh * dy;
      tex.bind();
      
      glPushMatrix();
      glColor3ub(r, g, b);
      glTranslatef(x, y, -800);
      if(rot != 0)
      {
            glTranslatef(w/2, h/2, -800);
            // 左回り
            glRotatef(rot, 0, 0, -1);
            glTranslatef(-w/2, -h/2, 0);
      }
      
      float s = cast(float)ox / cast(float)tex._width;
      float t = cast(float)oy / cast(float)tex._height;
      float u = cast(float)ow / cast(float)tex._width;
      float v = cast(float)oh / cast(float)tex._height;
      
      glBegin(GL_POLYGON);
      {
            glTexCoord2f(s,     t);     glVertex3f(0, 0, 0);
            glTexCoord2f(s + u, t);     glVertex3f(w, 0, 0);
            glTexCoord2f(s + u, t + v); glVertex3f(w, h, 0);
            glTexCoord2f(s,     t + v); glVertex3f(0, h, 0);
      }
      glEnd();
      
      glPopMatrix();
      tex.unbind();
}
/**
 * 中心座標を指定して描画
 */
void Hell_drawTextureEx(char[] key, float cx, float cy,  int ox=0, int oy=0, int ow=0, int oh=0, float dx=1.0f, float dy=1.0f, float rot=0, ubyte r=255, ubyte g=255, ubyte b=255)
{
      if(!(key in g_poolTexture)) { throw new Error("Hell_drawTexture: Has not exist key: " ~ key); }
      Texture tex = g_poolTexture[key];
      if(ow == 0 || oh == 0)
      {
            ow = tex._width;
            oh = tex._height;
      }
      float w  = ow * dx;
      float h  = oh * dy;
      Hell_drawTexture(key, cx-w/2, cy-h/2,  ox, oy, ow, oh, dx, dy, rot, r, g, b);
}

/**
 * フォントの描画(ascii文字のみ)
 * @param msg   描画文字列
 * @param x     X座標
 * @param y     Y座標
 * @param zoom  拡大サイズ(1.0fで32x48)
 * @param r     R成分
 * @param g     G成分
 * @param b     B成分
 * @param a     A成分
 */
void Hell_drawFont(char[] msg, int x, int y, float zoom=1.0f, ubyte r=0xff, ubyte g=0xff, ubyte b=0xff, ubyte a=0xff)
{
      const int WIDTH  = 32; // フォントの幅
      const int HEIGHT = 48; // フォントの高さ
      const int COLUMN = 16; // フォントテクスチャの一行の文字数
      char decoder[]   = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.()[]#$%&'\"!?^+-*/=;:";
      Texture tex = g_fontTexture;
      tex.bind();
      glColor4ub(r, g, b, a);
      
      float u = WIDTH  / cast(float)tex._width;  // テクスチャ座標の幅
      float v = HEIGHT / cast(float)tex._height; // テクスチャ座標の高さ
      float w = WIDTH  * zoom; // 実際の幅
      float h = HEIGHT * zoom; // 実際の高さ
      foreach(c; msg)
      {
            if(!isascii(c)) continue;    // ascii文字じゃないです
            int idx = find(decoder, c); // 文字のインデックスを取得
            if(c == ' ' | idx < 0)
            {
                  x += cast(int)(WIDTH * zoom); // スペース
                  continue;
            }
            
            glPushMatrix();
            glTranslatef(x, y, -800);
            
            // テクスチャ座標を取得
            float s = (idx % COLUMN) * u;
            float t = (idx / COLUMN) * v;
            
            glBegin(GL_POLYGON);
            glTexCoord2f(s,     t);     glVertex3f(0, 0, 0);
            glTexCoord2f(s + u, t);     glVertex3f(w, 0, 0);
            glTexCoord2f(s + u, t + v); glVertex3f(w, h, 0);
            glTexCoord2f(s,     t + v); glVertex3f(0, h, 0);
            glEnd();
            
            glPopMatrix();
            
            x += cast(int)(WIDTH * zoom);
      }
      tex.unbind();
}

void Hell_drawFontEx(int x, int y, float zoom=1.0f, ubyte r=0xff, ubyte g=0xff, ubyte b=0xff, ubyte a=0xff, ...)
{
      char[] _tmpString = "";
      void _putc(dchar c)
      {
            auto tmp = [c];
            _tmpString ~= toUTF8(tmp);
      }
      doFormat(&_putc, _arguments, _argptr);
      Hell_drawFont(_tmpString, x, y, zoom, r, g, b, a);
}

/**
 * αブレンド定数
 */
enum {
      HELL_ALPHA_DISABLE, // αブレンドしない
      HELL_ALPHA_NORMAL,  // 半透明
      HELL_ALPHA_ADD,     // 加算
}

static int g_alpha_prev = HELL_ALPHA_DISABLE;
int Hell_getAlpha()
{
      return g_alpha_prev;
}
/**
 * αブレンドの設定
 * @parma flag 設定値(HELL_ALPHA_XXX)
 */
void Hell_setAlpha(int flag)
{
//    if(g_alpha_prev == flag) return; // 前と同じ
      switch(flag)
      {
      case HELL_ALPHA_DISABLE:
            glDisable(GL_BLEND);
            break;
      case HELL_ALPHA_NORMAL:
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA);
            break;
      case HELL_ALPHA_ADD:
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA , GL_ONE);
            break;
      default:
            break;
      }
      g_alpha_prev = flag;
}

/**
 * FPS値の取得
 */
int Hell_getFPS()
{
      return fps_view;
}

/**
 * FPSの描画
 */
void Hell_drawFPS(int x=10, int y=-1)
{
      if(x < 0 || y < 0)
      {
            x = 10;
            y = g_height - 48; // フォントの高さ
      }
      Hell_drawFont("FPS:" ~ toString(Hell_getFPS()), x, y);
}


/**
 * テクスチャ読み込み
 * @parma key      キー(Hell_drawTextureで使用する)
 * @param filepath ファイルパス
 * @param mask     抜き色(mask[0]に「-1」で抜き色なし。「-2」で座標指定)
 */
void Hell_loadTexture(char[] key, char[] filepath, int[3] mask=[-1, 0, 0])
{
      //if(key in g_poolTexture) { throw new Error("Hell_loadTexture: Has exist key: " ~ key); }
      if(key in g_poolTexture)
      {
            // 同じキーがある場合、そのテクスチャを破棄
            Hell_disposeTexture(key);
      }
      if(mask is null) { throw new Error("Hell_loadTexture: PARAMETER 'mask' is null"); }
      if(mask[0] >= 0)
      {
            // 抜き色指定
            g_poolTexture[key] = new Texture(filepath, mask[0], mask[1], mask[2]);
      }
      else if(mask[0] == -1)
      {
            // 抜き色なし
            g_poolTexture[key] = new Texture(filepath);
      }
      else if(mask[0] == -2)
      {
            // 座標指定
            g_poolTexture[key] = new Texture(filepath, mask[1], mask[2]);
      }
      else
      {
            throw new Error("Hell_loadTexture: Invalid parameter 'mask'");
      }
}

/**
 * テクスチャの破棄
 * @param key キー(Hell_loadTextureで指定したもの)「null」で全て破棄
 */
public void Hell_disposeTexture(char[] key=null)
{
      if(key is null)
      {
            foreach(k; g_poolTexture.keys)
            {
                  Texture tex = g_poolTexture[k];
                  delete tex;
                  g_poolTexture.remove(key);
            }
      }
      else
      {
            if(!(key in g_poolTexture)) { throw new Error("Hell_disposeTexture: Has exist key: " ~ key); }
            Texture tex = g_poolTexture[key];
            delete tex;
            g_poolTexture.remove(key);
      }
}

/**
 * テスクチャクラス(BMPのみ)
 */
01089 class Texture
{
private:
      /**
       * テクスチャ番号
       */
01095       GLuint id;
      /**
       * 高さ
       */
01099       int _width;
      /**
       * 幅
       */
01103       int _height;
      /**
       * パス
       */
01107       char[] _path;
      /**
       * マスク情報
       */
01111       int[] _maskInfo;
      SDL_Surface* _surface;
public:
      /**
       * コンストラクタ(抜き色なし)
       * @param filename  ファイルパス
       * @param maskColor 抜き色
       */
01119       this(char[] filename)
      {
            _maskInfo = [-1, 0, 0];
            SDL_Surface* s = loadBMP(filename);
            create(s);
      }
      /**
       * コンストラクタ(抜き色指定)
       * @param filename  ファイルパス
       * @param maskColor 抜き色
       */
01130       this(char[] filename, int r, int g, int b)
      {
            _maskInfo = [r, g, b];
            SDL_Surface* s = loadBMP(filename);
            Uint32 maskColor = (r << 16) | (g << 8) | (b);
            s = setColorKey(s, maskColor); // 抜き色設定
            create(s);
      }
      /**
       * コンストラクタ(指定座標の色を抜き色に)
       * @param filename  ファイルパス
       * @param maskColor 抜き色
       */
01143       this(char[] filename, int x, int y)
      {
            _maskInfo = [-2, x, y];
            SDL_Surface* s = loadBMP(filename);
            if((0 <= x && x < s.w) && (0 <= y && y < s.h))
            {
                  // 座標が画像の範囲内
                  SDL_LockSurface(s);     
                  Uint32* surfacepixels = cast(Uint32*) s.pixels;
                  Uint32 maskColor = surfacepixels[y * s.pitch / 4  + x];
                  SDL_UnlockSurface(s);
                  s = setColorKey(s, maskColor); // 抜き色設定
            }
            create(s);
      }
      char[] getPath()     { return _path;     }
      int[] getMaskInfo()  { return _maskInfo; }
      /**
       * 生成
       */
01163       void create(SDL_Surface* s)
      {
            glGenTextures(1, &id);
            glBindTexture(GL_TEXTURE_2D, id);
            gluBuild2DMipmaps(GL_TEXTURE_2D, 4, s.w, s.h, GL_RGBA, GL_UNSIGNED_BYTE, s.pixels);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            
            _width   = s.w;
            _height  = s.h;
            _surface = s;
      }
      /**
       * 抜き色設定
       */
01178       SDL_Surface* setColorKey(SDL_Surface* s, Uint32 maskColor)
      {
            maskColor |= 0xff000000u;
            Uint32* surfacepixels = cast(Uint32*) s.pixels;
            SDL_LockSurface(s);
            for(int y = 0; y < s.h; y++)
            {
                  for(int x = 0; x < s.w; x++)
                  {
                        Uint32* p = &(surfacepixels[y * s.pitch / 4  + x]);
                        if(*p == maskColor) *p = 0x00000000u;
                  }
            }
            SDL_UnlockSurface(s);
            return s;
      }
      
      /**
       * デストラクタ
       */
01198       ~this()
      {
            glDeleteTextures(1 , &id);
            SDL_FreeSurface(_surface);
      }
      
      /**
       * BMP読み込み
       */
01207       SDL_Surface* loadBMP(char[] filename)
      {
            // ファイルパス
            _path = filename;
            // サーフェース生成
            SDL_Surface *s = SDL_LoadBMP(toStringz(filename));
            if(!s) { throw new Error("Hell_Texture::loadBmp : not found file: " ~ filename); }
            SDL_PixelFormat format;
            format.palette       = null;
            format.BitsPerPixel  = 32;
            format.BytesPerPixel = 4;
            format.Rmask         = 0x000000ff;
            format.Gmask         = 0x0000ff00;
            format.Bmask         = 0x00ff0000;
            format.Amask         = 0xff000000;
            format.Rshift        = 0;
            format.Gshift        = 8;
            format.Bshift        = 16;
            format.Ashift        = 24;
            format.Rloss         = 0;
            format.Gloss         = 0;
            format.Bloss         = 0;
            format.Aloss         = 0;
            format.alpha         = 0;
            SDL_Surface *ret = SDL_ConvertSurface(s, &format, SDL_SWSURFACE);
            SDL_FreeSurface(s);
            return ret;
      }
      /**
       * バインド
       */
01238       void bind()
      {
            glBindTexture(GL_TEXTURE_2D, id);
            glEnable(GL_TEXTURE_2D);
      }
      /**
       * バインド解除
       */
01246       static void unbind()
      {
            glDisable(GL_TEXTURE_2D);
      }
}

// 数学関係
const float HELL_PI = PI;
float Hell_sin(float rad)            { return sin(rad);             }
float Hell_cos(float rad)            { return cos(rad);             }
float Hell_atan2(float y, float x)   { return atan2(y, x);          }
float Hell_sinEx(float deg)          { return sin(deg2rad(deg));    }
float Hell_cosEx(float deg)          { return cos(deg2rad(deg));    }
float Hell_atan2Ex(float y, float x) { return rad2deg(atan2(y, x)); }
float Hell_deg2rad(float deg)        { return deg2rad(deg);         }
float Hell_rad2deg(float rad)        { return rad2deg(rad);         }
// 乱数
/**
 * 乱数の初期化
 * <pre>
 * わざわざ呼ばなくてもプログラム開始時に乱数は初期化されます。
 * 再現性のある乱数を生成したい場合にコールします。
 * </pre>
 * @param seed  種
 * @param index 次の乱数インデックスへの増分
 */
void Hell_randSeed(uint seed, uint index)
{
      rand_seed(seed, index);
}
/**
 * begin <= x < endの範囲で乱数を生成
 * @param begin 開始値
 * @param end   終了値
 */
int Hell_randInt(int begin, int end)
{
      auto range = end - begin;
      if(range < 1) return -1;
      return begin + rand()%range;
}

Generated by  Doxygen 1.6.0   Back to index