Airport/Source/LoadMenu.c

536 lines
14 KiB
C

/* **************************************
* Includes *
* *************************************/
#include "LoadMenu.h"
#include "Gfx.h"
#include "System.h"
#include "PltParser.h"
#include "Font.h"
#include "Sfx.h"
/* **************************************
* Defines *
* *************************************/
/* **************************************
* Structs and enums *
* *************************************/
enum
{
SMALL_FONT_SIZE = 8,
SMALL_FONT_SPACING = 6
};
enum
{
BG_BLUE_TARGET_VALUE = 0xC0,
BG_WHITE_TARGET_VALUE = /*0x40*/ 0,
BG_INCREASE_STEP = 0x10
};
enum
{
LOADING_BAR_X = 64,
LOADING_BAR_Y = 200,
LOADING_BAR_N_LINES = 4,
LOADING_BAR_WIDTH = 256,
LOADING_BAR_HEIGHT = 16,
LOADING_BAR_LUMINANCE_TARGET = NORMAL_LUMINANCE,
LOADING_BAR_LUMINANCE_STEP = 10
};
enum
{
LOADING_TITLE_CLUT_X = 384,
LOADING_TITLE_CLUT_Y = 496,
LOADING_TITLE_X = 128,
LOADING_TITLE_Y = 32,
LOADING_TITLE_U = 0,
LOADING_TITLE_V = 0,
LOADING_TITLE_LUMINANCE_STEP = 10,
LOADING_TITLE_LUMINANCE_TARGET = NORMAL_LUMINANCE
};
enum
{
PLANE_START_X = 56,
PLANE_START_Y = 200,
PLANE_U = 0,
PLANE_V = 32,
PLANE_SIZE = 16,
PLANE_LUMINANCE_STEP = 0x10,
PLANE_LUMINANCE_TARGET_VALUE = NORMAL_LUMINANCE
};
/* *************************************
* Local Prototypes
* *************************************/
static void LoadMenuInit(void);
static void ISR_LoadMenuVBlank(void);
static bool LoadMenuISRHasEnded(void);
static bool LoadMenuISRHasStarted(void);
static void LoadMenuLoadFileList(const char* const fileList[], void* const dest[],
uint8_t szFileList, uint8_t szDestList);
/* *************************************
* Local Variables
* *************************************/
static GsGPoly4 loadMenuBg;
static GsSprite LoadMenuPlaneSpr;
static GsSprite LoadMenuTitleSpr;
static GsLine LoadMenuBarLines[LOADING_BAR_N_LINES];
static GsRectangle LoadMenuBarRect;
static const char* LoadMenuFiles[] =
{
"DATA\\SPRITES\\PLANE.TIM",
"DATA\\SPRITES\\LOADING.TIM",
"DATA\\FONTS\\FONT_2.FNT"
};
static void* const LoadMenuDest[] =
{
&LoadMenuPlaneSpr,
&LoadMenuTitleSpr,
&SmallFont
};
static const char* strCurrentFile;
// Flags to communicate with ISR state
// * startup_flag: background fades in from black to blue.
// * end_flag: tells the background to fade out to black.
// * isr_ended: background has totally faded out to black.
// * isr_started: tells the ISR has finished starting up.
static volatile bool startup_flag;
static volatile bool isr_started;
static volatile bool end_flag;
static volatile bool isr_ended;
// Set to true when LoadMenuInit() has been called, and set to false
// once LoadMenuEnd() is called.
// It's used when multiple modules call LoadMenu() at the same time,
// so load menu does not have to be initialised each time;
static bool load_menu_running;
void LoadMenuInit(void)
{
int i;
static bool first_load = false;
if (first_load == false)
{
first_load = true;
LoadMenuLoadFileList( LoadMenuFiles,
LoadMenuDest,
sizeof (LoadMenuFiles) / sizeof (char*),
sizeof (LoadMenuDest) / sizeof (void*));
}
FontSetSize(&SmallFont, SMALL_FONT_SIZE);
FontSetSpacing(&SmallFont, SMALL_FONT_SPACING);
LoadMenuPlaneSpr.r = 0;
LoadMenuPlaneSpr.g = 0;
LoadMenuPlaneSpr.b = 0;
LoadMenuPlaneSpr.x = PLANE_START_X;
LoadMenuPlaneSpr.y = PLANE_START_Y;
// "Loading..." title init
LoadMenuTitleSpr.r = 0;
LoadMenuTitleSpr.g = 0;
LoadMenuTitleSpr.b = 0;
LoadMenuTitleSpr.x = LOADING_TITLE_X;
LoadMenuTitleSpr.y = LOADING_TITLE_Y;
LoadMenuTitleSpr.cx = LOADING_TITLE_CLUT_X;
LoadMenuTitleSpr.cy = LOADING_TITLE_CLUT_Y;
LoadMenuTitleSpr.u = LOADING_TITLE_U;
LoadMenuTitleSpr.v = LOADING_TITLE_V;
startup_flag = true;
isr_started = false;
end_flag = false;
isr_ended = false;
// Background init
loadMenuBg.x[0] = 0;
loadMenuBg.x[1] = X_SCREEN_RESOLUTION;
loadMenuBg.x[2] = 0;
loadMenuBg.x[3] = X_SCREEN_RESOLUTION;
loadMenuBg.y[0] = 0;
loadMenuBg.y[1] = 0;
loadMenuBg.y[2] = Y_SCREEN_RESOLUTION;
loadMenuBg.y[3] = Y_SCREEN_RESOLUTION;
// Colour components adjustment (default to zero)
for (i = 0; i < 4 ; i++)
{
loadMenuBg.r[i] = 0;
loadMenuBg.g[i] = 0;
loadMenuBg.b[i] = 0;
}
// "Loading" bar line 0 (up left - up right)
LoadMenuBarLines[0].x[0] = LOADING_BAR_X;
LoadMenuBarLines[0].x[1] = LOADING_BAR_X + LOADING_BAR_WIDTH;
LoadMenuBarLines[0].y[0] = LOADING_BAR_Y;
LoadMenuBarLines[0].y[1] = LOADING_BAR_Y;
// "Loading" bar line 1 (up left - down left)
LoadMenuBarLines[1].x[0] = LOADING_BAR_X;
LoadMenuBarLines[1].x[1] = LOADING_BAR_X;
LoadMenuBarLines[1].y[0] = LOADING_BAR_Y;
LoadMenuBarLines[1].y[1] = LOADING_BAR_Y + LOADING_BAR_HEIGHT;
// "Loading" bar line 2 (down left - down right)
LoadMenuBarLines[2].x[0] = LOADING_BAR_X;
LoadMenuBarLines[2].x[1] = LOADING_BAR_X + LOADING_BAR_WIDTH;
LoadMenuBarLines[2].y[0] = LOADING_BAR_Y + LOADING_BAR_HEIGHT;
LoadMenuBarLines[2].y[1] = LOADING_BAR_Y + LOADING_BAR_HEIGHT;
// "Loading" bar line 3 (up right - down right)
LoadMenuBarLines[3].x[0] = LOADING_BAR_X + LOADING_BAR_WIDTH;
LoadMenuBarLines[3].x[1] = LOADING_BAR_X + LOADING_BAR_WIDTH;
LoadMenuBarLines[3].y[0] = LOADING_BAR_Y;
LoadMenuBarLines[3].y[1] = LOADING_BAR_Y + LOADING_BAR_HEIGHT;
for (i = 0; i < LOADING_BAR_N_LINES ; i++)
{
LoadMenuBarLines[i].r = 0;
LoadMenuBarLines[i].g = 0;
LoadMenuBarLines[i].b = 0;
}
LoadMenuBarRect.r = 0;
LoadMenuBarRect.g = 0;
LoadMenuBarRect.b = 0;
// LoadMenuBarRect.attribute |= ENABLE_TRANS | TRANS_MODE(0);
LoadMenuBarRect.x = LOADING_BAR_X;
LoadMenuBarRect.y = LOADING_BAR_Y;
LoadMenuBarRect.w = 0;
LoadMenuBarRect.h = LOADING_BAR_HEIGHT;
LoadMenuBarRect.attribute |= ENABLE_TRANS | TRANS_MODE(0);
load_menu_running = true;
SmallFont.spr.r = 0;
SmallFont.spr.g = 0;
SmallFont.spr.b = 0;
GfxSetGlobalLuminance(0);
SetVBlankHandler(&ISR_LoadMenuVBlank);
}
void LoadMenuEnd(void)
{
end_flag = true;
load_menu_running = false;
while (LoadMenuISRHasEnded() == false);
while (GfxIsGPUBusy());
SetVBlankHandler(&ISR_SystemDefaultVBlank);
GfxSetGlobalLuminance(NORMAL_LUMINANCE);
}
void ISR_LoadMenuVBlank(void)
{
uint8_t i;
SystemIncreaseGlobalTimer();
if ( (SystemIsBusy())
||
(GfxIsGPUBusy())
||
(SerialIsBusy()) )
{
return;
}
if (startup_flag)
{
// "Loading..." text
if (LoadMenuTitleSpr.r < LOADING_TITLE_LUMINANCE_TARGET)
{
LoadMenuTitleSpr.r += LOADING_TITLE_LUMINANCE_STEP;
LoadMenuTitleSpr.g += LOADING_TITLE_LUMINANCE_STEP;
LoadMenuTitleSpr.b += LOADING_TITLE_LUMINANCE_STEP;
}
if (loadMenuBg.g[0] < BG_WHITE_TARGET_VALUE)
{
loadMenuBg.r[0] += BG_INCREASE_STEP;
loadMenuBg.r[1] += BG_INCREASE_STEP;
loadMenuBg.g[0] += BG_INCREASE_STEP;
loadMenuBg.g[1] += BG_INCREASE_STEP;
loadMenuBg.b[0] += BG_INCREASE_STEP;
loadMenuBg.b[1] += BG_INCREASE_STEP;
}
// Blue background
if (loadMenuBg.b[2] < BG_BLUE_TARGET_VALUE)
{
loadMenuBg.b[2] += BG_INCREASE_STEP;
loadMenuBg.b[3] += BG_INCREASE_STEP;
}
if (LoadMenuBarRect.r < LOADING_BAR_LUMINANCE_TARGET)
{
LoadMenuBarRect.r += LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarRect.g += LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarRect.b += LOADING_BAR_LUMINANCE_STEP;
}
else
{
startup_flag = false;
isr_started = true;
}
for (i = 0;i < LOADING_BAR_N_LINES ; i++)
{
if (LoadMenuBarLines[i].r < LOADING_BAR_LUMINANCE_TARGET)
{
LoadMenuBarLines[i].r += LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarLines[i].g += LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarLines[i].b += LOADING_BAR_LUMINANCE_STEP;
}
}
if (LoadMenuPlaneSpr.r < PLANE_LUMINANCE_TARGET_VALUE)
{
LoadMenuPlaneSpr.r += PLANE_LUMINANCE_STEP;
LoadMenuPlaneSpr.g += PLANE_LUMINANCE_STEP;
LoadMenuPlaneSpr.b += PLANE_LUMINANCE_STEP;
}
}
else if (end_flag)
{
LoadMenuTitleSpr.r -= LOADING_TITLE_LUMINANCE_STEP;
LoadMenuTitleSpr.g -= LOADING_TITLE_LUMINANCE_STEP;
LoadMenuTitleSpr.b -= LOADING_TITLE_LUMINANCE_STEP;
if (loadMenuBg.g[0] > 0)
{
loadMenuBg.r[0] -= BG_INCREASE_STEP;
loadMenuBg.r[1] -= BG_INCREASE_STEP;
loadMenuBg.g[0] -= BG_INCREASE_STEP;
loadMenuBg.g[1] -= BG_INCREASE_STEP;
loadMenuBg.b[0] -= BG_INCREASE_STEP;
loadMenuBg.b[1] -= BG_INCREASE_STEP;
}
if (loadMenuBg.b[2] > 0)
{
loadMenuBg.b[2] -= BG_INCREASE_STEP;
loadMenuBg.b[3] -= BG_INCREASE_STEP;
}
if (loadMenuBg.b[2] == 0)
{
end_flag = false;
isr_ended = true;
}
if (LoadMenuPlaneSpr.r > 0)
{
LoadMenuPlaneSpr.r -= PLANE_LUMINANCE_STEP;
LoadMenuPlaneSpr.g -= PLANE_LUMINANCE_STEP;
LoadMenuPlaneSpr.b -= PLANE_LUMINANCE_STEP;
}
LoadMenuPlaneSpr.x = (PLANE_START_X + LOADING_BAR_WIDTH);
LoadMenuPlaneSpr.y = PLANE_START_Y;
LoadMenuBarRect.w = LOADING_BAR_WIDTH;
if (LoadMenuBarRect.r > 0)
{
LoadMenuBarRect.r -= LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarRect.g -= LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarRect.b -= LOADING_BAR_LUMINANCE_STEP;
}
for (i = 0;i < LOADING_BAR_N_LINES ; i++)
{
if (LoadMenuBarLines[i].r > 0)
{
LoadMenuBarLines[i].r -= LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarLines[i].g -= LOADING_BAR_LUMINANCE_STEP;
LoadMenuBarLines[i].b -= LOADING_BAR_LUMINANCE_STEP;
}
}
}
GsSortGPoly4(&loadMenuBg);
GsSortRectangle(&LoadMenuBarRect);
for (i = 0 ; i < LOADING_BAR_N_LINES ; i++)
{
GsSortLine(&LoadMenuBarLines[i]);
}
GsSortSprite(&LoadMenuTitleSpr);
LoadMenuPlaneSpr.w = PLANE_SIZE;
LoadMenuPlaneSpr.h = PLANE_SIZE;
GsSortSprite(&LoadMenuPlaneSpr);
FontSetFlags(&SmallFont, FONT_BLEND_EFFECT);
FontPrintText( &SmallFont,
LOADING_BAR_X,
LOADING_BAR_Y + LOADING_BAR_HEIGHT + 8,
strCurrentFile );
GfxDrawScene_Fast();
}
bool LoadMenuISRHasEnded(void)
{
return isr_ended;
}
bool LoadMenuISRHasStarted(void)
{
return isr_started;
}
void LoadMenu( const char* const fileList[],
void* const dest[],
uint8_t szFileList , uint8_t szDestList)
{
if (load_menu_running == false)
{
LoadMenuInit();
while (LoadMenuISRHasStarted() == false);
}
LoadMenuLoadFileList(fileList, dest, szFileList, szDestList);
}
void LoadMenuLoadFileList( const char* const fileList[], void* const dest[],
uint8_t szFileList, uint8_t szDestList)
{
char* extension;
short x_increment;
uint8_t fileLoadedCount;
if (szFileList != szDestList)
{
Serial_printf("File list size different from dest list size! %d vs %d\n",
szFileList, szDestList);
return;
}
for (fileLoadedCount = 0; fileLoadedCount < szFileList ; fileLoadedCount++)
{
strCurrentFile = fileList[fileLoadedCount];
if (strCurrentFile == NULL)
{
continue;
}
x_increment = LOADING_BAR_WIDTH / szFileList;
// Calculate new X position for loading menu plane sprite.
// This is not calculated on ISR as to avoid longer ISR time.
LoadMenuPlaneSpr.x = (PLANE_START_X + (fileLoadedCount* x_increment) );
LoadMenuBarRect.w = fileLoadedCount * x_increment;
static char auxstr[256];
strncpy(auxstr, strCurrentFile, sizeof (auxstr));
//We want to get file extension, so split into tokens
strtok(auxstr, ".");
extension = strtok(NULL, ".");
Serial_printf("File extension: .%s\n", extension);
if (strncmp(extension, "TIM", 3) == 0)
{
if (GfxSpriteFromFile(strCurrentFile, dest[fileLoadedCount]) == false)
{
Serial_printf("Could not load image file \"%s\"!\n", strCurrentFile);
}
}
else if (strncmp(extension, "CLT", 3) == 0)
{
if (dest[fileLoadedCount] != NULL)
{
Serial_printf("WARNING: File %s linked to non-NULL destination pointer!\n", dest[fileLoadedCount]);
}
if (GfxCLUTFromFile(strCurrentFile) == false)
{
Serial_printf("Could not load CLUT file \"%s\"!\n", strCurrentFile);
}
}
else if (strncmp(extension, "VAG", 3) == 0)
{
if (SfxUploadSound(strCurrentFile, dest[fileLoadedCount]) == false)
{
Serial_printf("Could not load sound file \"%s\"!\n", strCurrentFile);
}
}
else if (strncmp(extension, "FNT", 3) == 0)
{
if (FontLoadImage(strCurrentFile, dest[fileLoadedCount]) == false)
{
Serial_printf("Could not load font file \"%s\"!\n", strCurrentFile);
}
}
else if (strncmp(extension, "PLT", 3) == 0)
{
if (PltParserLoadFile(strCurrentFile, dest[fileLoadedCount]) == false)
{
Serial_printf("Could not load pilots file \"%s\"!\n", strCurrentFile);
}
}
else
{
Serial_printf("LoadMenu does not recognize following extension: %s\n",extension);
}
}
}