/*****************************************************************************/
/* Disp for WonderWitch                                                      */
/* ディスプレイ関連を扱うクラス                                              */
/*****************************************************************************/

#include "dspp.h"

#include <sys/text.h>

#include "etc.h"

int Disp_GetRollX(Disp disp) { return (disp->roll_x); }
int Disp_GetRollY(Disp disp) { return (disp->roll_y); }

/*---------------------------------------------------------------------------*/
/* 内部で使用する関数                                                        */
/*---------------------------------------------------------------------------*/

static unsigned char ClearBit(unsigned char bitmap[], int number)
{
  unsigned char mask;

  mask = ((unsigned char)0x01) << (number % 8);
  bitmap[number / 8] &= ~mask;
  return (bitmap[number / 8]);
}

static unsigned char SetBit(unsigned char bitmap[], int number)
{
  unsigned char mask;

  mask = ((unsigned char)0x01) << (number % 8);
  bitmap[number / 8] |= mask;
  return (bitmap[number / 8]);
}

static int GetBit(unsigned char bitmap[], int number)
{
  unsigned char mask;

  mask = ((unsigned char)0x01) << (number % 8);
  return ((bitmap[number / 8] & mask) != 0);
}

static SpriteSetRange(unsigned char bitmap[])
{
  int i;
  int n = DISP_SPRITE_OFFSET - 1;

  for (i = DISP_SPRITE_OFFSET; i < DISP_SPRITES_NUMBER; i++) {
    if (GetBit(bitmap, i)) n = i;
  }

  sprite_set_range(DISP_SPRITE_OFFSET, n - DISP_SPRITE_OFFSET + 1);
}

/*---------------------------------------------------------------------------*/
/* オブジェクトの作成                                                        */
/*---------------------------------------------------------------------------*/

Disp Disp_Create(Disp disp)
{
  int i;
  unsigned short int bits1;
  unsigned short int bits2;

  bits1 = 0x0000;
  bits1 |=  0x0001; /* スクリーン1表示 */
  bits1 |=  0x0002; /* スクリーン2表示 */
  bits1 |=  0x0004; /* スプライト表示有効 */
  bits1 &= ~0x0008; /* スプライトウインドウ機能無効 */
  bits1 &= ~0x0010; /* スクリーン2ウインドウ機能有効(内側を表示) */
  bits1 |=  0x0020; /* スクリーン2ウインドウ機能有効(内側を表示) */
  bits1 &= ~0x0040; /* 未使用 */
  bits1 &= ~0x0080; /* 未使用 */
  bits1 &= ~0x0100; /* ボーダーカラー */
  bits1 &= ~0x0200; /* ボーダーカラー */
  bits1 &= ~0x0400; /* ボーダーカラー */
  bits1 &= ~0x0800; /* ボーダーカラー */
  bits1 &= ~0x1000; /* 未使用 */
  bits1 &= ~0x2000; /* 未使用 */
  bits1 &= ~0x4000; /* 未使用 */
  bits1 &= ~0x8000; /* 未使用 */

  display_control(bits1);

  /* LCDカラーパレットの設定(単純な階調カラーにする) */
  bits1  = 0x0000;
  bits1 |= 0x0      ; /* LCD カラーパレット 0 */
  bits1 |= 0x2 <<  4; /* LCD カラーパレット 1 */
  bits1 |= 0x4 <<  8; /* LCD カラーパレット 2 */
  bits1 |= 0x6 << 12; /* LCD カラーパレット 3 */

  bits2  = 0x0000;
  bits2 |= 0x8      ; /* LCD カラーパレット 4 */
  bits2 |= 0xa <<  4; /* LCD カラーパレット 5 */
  bits2 |= 0xc <<  8; /* LCD カラーパレット 6 */
  bits2 |= 0xf << 12; /* LCD カラーパレット 7 */

  lcd_set_color(bits1, bits2);

  /* キャラクタカラーパレットの設定 */
  bits1  = 0x0000;
  bits1 |= 0x0      ; /* 00 の色 */
  bits1 |= 0x2 <<  4; /* 01 の色 */
  bits1 |= 0x4 <<  8; /* 10 の色 */
  bits1 |= 0x7 << 12; /* 11 の色 */
  for (i = 0; i < 16; i++) {
    palette_set_color(i, bits1);
  }

  font_set_color(0x0003 << 0);

  for (i = 0; i < DISP_SPRITES_NUMBER; i++) {
    if (i < DISP_SPRITE_OFFSET) SetBit(disp->sprites, i);
    else ClearBit(disp->sprites, i);
  }

  for (i = 0; i < DISP_CHARACTERS_NUMBER; i++) {
    if (i < DISP_CHARACTER_OFFSET) SetBit(disp->characters, i);
    else ClearBit(disp->characters, i);
  }

  disp->roll_x = 0;
  disp->roll_y = 0;

  screen_set_scroll(SCREEN1, disp->roll_x, disp->roll_y);
  screen_set_scroll(SCREEN2, disp->roll_x, disp->roll_y);

  screen2_set_window(DISP_GAME_X, DISP_GAME_Y,
		     DISP_GAME_WIDTH - 1, DISP_GAME_HEIGHT - 1);

  SpriteSetRange(disp->sprites);

  key_set_repeat(4, 0); /* オートリピート無効 */

  text_set_screen(SCREEN1);
  text_screen_init();
  text_set_mode(TEXT_MODE_ANK);
  Disp_ClearTextScreen(disp);

  return (disp);
}

/*---------------------------------------------------------------------------*/
/* オブジェクトの削除                                                        */
/*---------------------------------------------------------------------------*/

Disp Disp_Destroy(Disp disp)
{
  /* ディスプレイの後始末があったらここに書く */

  return (NULL);
}

/*---------------------------------------------------------------------------*/
/* 使用可能なスプライト番号を取得する                                        */
/*---------------------------------------------------------------------------*/

int Disp_GetSpriteNumber(Disp disp)
{
  int i;

  for (i = 0; i < DISP_SPRITES_NUMBER; i++) {
    if (!GetBit(disp->sprites, i)) {
      SetBit(disp->sprites, i);
      SpriteSetRange(disp->sprites);
      return (i);
    }
  }
  return (-1);
}

/*---------------------------------------------------------------------------*/
/* スプライト番号を返却する                                                  */
/*---------------------------------------------------------------------------*/

int Disp_ReturnSpriteNumber(Disp disp, int number)
{
  if (!GetBit(disp->sprites, number))
    Error("Disp_ReturnSpriteNumber", "This number has already returned");
  ClearBit(disp->sprites, number);
  SpriteSetRange(disp->sprites);
  return (0);
}

/*---------------------------------------------------------------------------*/
/* 使用可能なキャラクター番号を取得する                                      */
/*---------------------------------------------------------------------------*/

int Disp_GetCharacterNumber(Disp disp)
{
  int i;

  for (i = 0; i < DISP_CHARACTERS_NUMBER; i++) {
    if (!GetBit(disp->characters, i)) {
      SetBit(disp->characters, i);
      return (i);
    }
  }
  return (-1);
}

/*---------------------------------------------------------------------------*/
/* キャラクター番号を返却する                                                */
/*---------------------------------------------------------------------------*/

int Disp_ReturnCharacterNumber(Disp disp, int number)
{
  if (!GetBit(disp->characters, number))
    Error("Disp_ReturnCharacterNumber", "This number has already returned");
  ClearBit(disp->characters, number);
  return (0);
}

/*---------------------------------------------------------------------------*/
/* キー入力                                                                  */
/*---------------------------------------------------------------------------*/

int Disp_GetButtonStatus(Disp disp)
{
#if 0
  return (key_hit_check_with_repeat());
#else
  return (key_hit_check());
#endif
}

/*---------------------------------------------------------------------------*/
/* 指定した座標を画面の中央にもってくる                                      */
/*---------------------------------------------------------------------------*/

int Disp_PutPointAtCenterOfScreen(Disp disp, int x, int y)
{
  x = x - (DISP_GAME_WIDTH  / 2) - DISP_GAME_X;
  y = y - (DISP_GAME_HEIGHT / 2) - DISP_GAME_Y;

  if (x < -DISP_GAME_X) x = -DISP_GAME_X;
  if (y < -DISP_GAME_Y) y = -DISP_GAME_Y;

  if (x > DISP_SCREEN_WIDTH  - (DISP_GAME_X + DISP_GAME_WIDTH))
    x   = DISP_SCREEN_WIDTH  - (DISP_GAME_X + DISP_GAME_WIDTH);
  if (y > DISP_SCREEN_HEIGHT - (DISP_GAME_Y + DISP_GAME_HEIGHT))
    y   = DISP_SCREEN_HEIGHT - (DISP_GAME_Y + DISP_GAME_HEIGHT);

  disp->roll_x = x;
  disp->roll_y = y;
  screen_set_scroll(SCREEN2, disp->roll_x, disp->roll_y);

  return (0);
}

/*---------------------------------------------------------------------------*/
/* グラフィックスクリーンに切替え                                            */
/*---------------------------------------------------------------------------*/

int Disp_GraphicScreen(Disp disp)
{
  unsigned short int bits;

  bits = display_status();

  bits |=  0x0001; /* スクリーン1表示 */
  bits |=  0x0002; /* スクリーン2表示 */
  bits |=  0x0004; /* スプライト表示有効 */

  display_control(bits);

  return (0);
}

/*---------------------------------------------------------------------------*/
/* テキストスクリーンに切替え                                                */
/*---------------------------------------------------------------------------*/

int Disp_TextScreen(Disp disp)
{
  unsigned short int bits;

  bits = display_status();

  bits |=  0x0001; /* スクリーン1表示 */
  bits &= ~0x0002; /* スクリーン2非表示 */
  bits &= ~0x0004; /* スプライト表示無効 */

  display_control(bits);

  return (0);
}

/*---------------------------------------------------------------------------*/
/* テキストスクリーンクリア                                                  */
/*---------------------------------------------------------------------------*/

int Disp_ClearTextScreen(Disp disp)
{
  int x, y;

  for (y = 0; y < DISP_TEXT_HEIGHT; y++) {
    for (x = 0; x < DISP_TEXT_WIDTH; x++) {
      Disp_PutCharacter(disp, x, y, ' ');
    }
  }

  return (0);
}

/*---------------------------------------------------------------------------*/
/* 文字描画                                                                  */
/*---------------------------------------------------------------------------*/

int Disp_PutCharacter(Disp disp, int x, int y, unsigned int c)
{
  text_put_char(x, y, c);
  return (0);
}

/*---------------------------------------------------------------------------*/
/* 文字列描画                                                                */
/*---------------------------------------------------------------------------*/

int Disp_PutString(Disp disp, int x, int y, char * s)
{
  text_put_string(x, y, s);
  return (0);
}

/*---------------------------------------------------------------------------*/
/* 数値描画                                                                  */
/*---------------------------------------------------------------------------*/

int Disp_PutNumber(Disp disp, int x, int y, int len, int number)
{
  text_put_numeric(x, y, len, NUM_ALIGN_RIGHT, number);
  return (0);
}

/*---------------------------------------------------------------------------*/
/*                                                                           */
/*---------------------------------------------------------------------------*/

int Disp_ClearBar(Disp disp)
{
  int x;

  for (x = 0; x < DISP_TEXT_WIDTH; x++) {
    Disp_PutCharacter(disp, x, DISP_BAR_CHARACTER_Y, ' ');
  }

  return (0);
}

/*---------------------------------------------------------------------------*/
/*                                                                           */
/*---------------------------------------------------------------------------*/

int Disp_PrintScore(Disp disp, int hi_score, int score)
{
  Disp_PutString(disp, DISP_BAR_CHARACTER_X +  2, DISP_BAR_CHARACTER_Y,
		 "HiScore");
  Disp_PutNumber(disp, DISP_BAR_CHARACTER_X + 10, DISP_BAR_CHARACTER_Y, 5,
		 hi_score);
  Disp_PutString(disp, DISP_BAR_CHARACTER_X + 16, DISP_BAR_CHARACTER_Y,
		 "Score");
  Disp_PutNumber(disp, DISP_BAR_CHARACTER_X + 22, DISP_BAR_CHARACTER_Y, 5,
		 score);
  return (0);
}

/*---------------------------------------------------------------------------*/
/*                                                                           */
/*---------------------------------------------------------------------------*/

/*****************************************************************************/
/* End of File.                                                              */
/*****************************************************************************/
