/* vim: ts=4 sw=4 sts=4 :
 * =============================================================================
 *  SDL sample  for  C
 * =============================================================================
 */

#include <stdio.h>

#include <SDL.h>
#include <SDL_image.h>


/* エラーメッセージ出力. */
#define ERROR(x)     printError(x, __FILE__, __LINE__)
#define SDL_ERROR(x) printSDLError(x, __FILE__, __LINE__)


/* プロトタイプ宣言 */
int  init(void);
void quit(void);
SDL_Surface* setVideoMode(void);
void mainLoop(void);

/* プロトタイプ宣言 [画像表示]. */
void showImages(SDL_Surface* screen);
void showImage(SDL_Surface* screen, const char* file, SDL_Rect* pos);

/* プロトタイプ宣言 [エラー表示用]. */
void printError(const char* msg, const char* file, int line);
void printSDLError(const char* msg, const char* file, int line);


/**
 * MAIN.
 *
 * @param argc   起動引数の数
 * @param argv[] 起動引数 (未使用)
 */
int main(int argc, char* argv[])
{
	int ret;
	SDL_Surface* screen;

	/* SDL初期化. */
	ret = init();
	if (ret < 0) { return -1; }

	/* SDL終了処理を終了時に自動実行するよう登録. */
	atexit(quit);

	/* ビデオモード設定. */
	screen = setVideoMode();
	if (screen == NULL) { return -1; }

	/* 画像表示 */
	showImages(screen);

	/* メインループ */
	mainLoop();

	return 0;
}


/**
 * SDL初期化.
 */
int init(void)
{
	/* 初期化 */
	int ret = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
	if (ret < 0)
	{	/* 初期化エラー */
		SDL_ERROR("can't init sdl.");
		return -1;
	}

	/*
	 * SDL_Init 後にまだ初期化していないサブシステムを
	 * 初期化する場合は, 下記関数を使用する.
	 * int SDL_InitSubSystem(Uint32 flags);
	 */

	return 0;
}


/**
 * SDL終了処理.
 */
void quit(void)
{
	SDL_Quit();
}


/**
 * ビデオ表示初期化.
 * @return SDL_Screen
 */
SDL_Surface* setVideoMode(void)
{
	SDL_Surface* screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
	if (screen == NULL)
	{	/* ビデオモード設定エラー */
		SDL_ERROR("can't set video mode.");
		return NULL;
	}
	return screen;
}


/**
 * 画像表示.
 *
 * @param screen スクリーン
 * @param file   ファイル
 */
void showImages(SDL_Surface* screen)
{
	SDL_Rect pos;
	pos.x = 0;
	pos.y = 0;
	pos.h = 50;
	pos.w = 200;
	showImage(screen, "sample/resource/sample.bmp", &pos);

	pos.y += 50;
	showImage(screen, "sample/resource/sample.png", &pos);

	pos.y += 50;
	showImage(screen, "sample/resource/sample.jpg", &pos);

	pos.y += 50;
	showImage(screen, "sample/resource/sample.gif", &pos);

	pos.y += 50;
	showImage(screen, "sample/resource/sample.tif", &pos);
}


/**
 * ★SDL_image 使用.
 * 指定されたイメージファイルをロード・表示します.
 * @param screen スクリーン
 * @param file   イメージファイル
 * @param pos    表示位置
 */
void showImage(SDL_Surface* screen, const char* file, SDL_Rect* pos)
{
	int ret;

	/* イメージのロード.
	 * SDL_LoadBMP : BMPをロード.
	 * IMG_Load    : いろんな形式をロード. SDL_image が必要.
	 */
	SDL_Surface* image = IMG_Load(file);
	if (image == NULL)
	{	/* イメージロードエラー. */
		SDL_ERROR("can't load image.");
		return;
	}

	/* 画像がパレット表現なら, そのパレットを使う. */
	if (image->format->palette && screen->format->palette)
	{
		SDL_SetColors(screen,
				image->format->palette->colors,
				0,
				image->format->palette->ncolors);
	}

	/* 高速Blit転送
	 * 参照: http://www.tacoworks.jp/software/SDLdoc-jp/html/sdlblitsurface.html
	 */
	ret = SDL_BlitSurface(image, NULL, screen, pos);
	if (ret < 0)
	{	/* 転送失敗 */
		SDL_ERROR("can't blit.");
		return;
	}

	/* 指定領域の更新 */
	SDL_UpdateRect(screen, pos->x, pos->y, image->w, image->h);

	/* サーフェス開放 */
	SDL_FreeSurface(image);
}


/**
 * イベントループ.
 */
void mainLoop(void)
{
	int quit = 0;
	SDL_Event event;

	/* unicode 変換を有効にする. */
	SDL_EnableUNICODE(1);

	while (!quit)
	{
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				/* SDL_QUIT イベント (ウィンドウが閉じられた) */
				case SDL_QUIT:
					quit = 1;
					break;

				default:
					break;
			}
		}
	}
}


/* =============================================================================
 *  以下, エラーメッセージ表示や, ユーティリティなど.
 *  本質ではないので・・・あんま見なくて良いかと.
 * =============================================================================
 */
/**
 * エラーメッセージ表示.
 *
 * @param msg  メッセージ
 * @param file ファイル名
 * @param line 行番号
 */
void printError(const char* msg, const char* file, int line)
{
	fprintf(stderr, "%s:%d %s\n", file, line, msg);
}


/**
 * SDLエラーメッセージを含む, エラーメッセージ表示.
 *
 * @param msg  メッセージ
 * @param file ファイル名
 * @param line 行番号
 */
void printSDLError(const char* msg, const char* file, int line)
{
	char* sdlerr = SDL_GetError();
	fprintf(stderr, "%s:%d %s [%s]\n", file, line, msg, sdlerr);
}

