Subversion Repositories psp

Compare Revisions

Rev 343 → Rev 348

/race/2.15/psp/emulate.h
0,0 → 1,44
#ifndef PSP_EMULATE_H
#define PSP_EMULATE_H
 
int InitEmulation();
void RunEmulation();
void TrashEmulation();
 
#define DISPLAY_MODE_UNSCALED 0
#define DISPLAY_MODE_FIT_HEIGHT 1
#define DISPLAY_MODE_FILL_SCREEN 2
 
#define MAP_BUTTONS 20
 
#define JST 0x100
#define AFI 0x200
#define SPC 0x400
 
#define SPC_MENU 1
 
#define CODE_MASK(x) (x & 0xff)
 
typedef struct psp_ctrl_map_t
{
uint32_t button_map[MAP_BUTTONS];
} psp_ctrl_map_t;
 
typedef struct psp_ctrl_mask_to_index_map_t
{
uint64_t mask;
uint8_t index;
} psp_ctrl_mask_to_index_map_t;
 
typedef struct psp_options_t
{
uint8_t display_mode;
uint8_t show_fps;
uint8_t frame_skip;
uint16_t clock_freq;
uint8_t autofire;
} psp_options_t;
 
extern psp_options_t psp_options;
 
#endif
/race/2.15/psp/menu.cpp
0,0 → 1,1124
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <psptypes.h>
#include <pspkernel.h>
#include <pspgu.h>
 
#include "StdAfx.h"
#include "main.h"
#include "input.h"
#include "neopopsound.h"
#include "flash.h"
 
#include "menu.h"
#include "emulate.h"
 
#include "pl_psp.h"
#include "pl_snd.h"
#include "image.h"
#include "video.h"
#include "pl_perf.h"
#include "ctrl.h"
#include "pl_util.h"
#include "pl_file.h"
#include "pl_ini.h"
#include "ui.h"
#include "state.h"
 
#undef u32
 
extern PspImage *Screen;
 
pl_file_path CurrentGame = "",
GamePath,
SaveStatePath,
ScreenshotPath;
static PspImage *Background;
static PspImage *NoSaveIcon;
static int TabIndex;
static int ResumeEmulation;
 
psp_ctrl_map_t current_map;
psp_options_t psp_options;
 
/* Default configuration */
static psp_ctrl_map_t default_map =
{
{
JST|0x01, /* Analog Up */
JST|0x02, /* Analog Down */
JST|0x04, /* Analog Left */
JST|0x08, /* Analog Right */
JST|0x01, /* D-pad Up */
JST|0x02, /* D-pad Down */
JST|0x04, /* D-pad Left */
JST|0x08, /* D-pad Right */
0, /* Square */
JST|0x10, /* Cross */
JST|0x20, /* Circle */
0, /* Triangle */
0, /* L Trigger */
0, /* R Trigger */
JST|0x40, /* Select */
0, /* Start */
SPC|SPC_MENU, /* L+R Triggers */
0, /* Start+Select */
0, /* Select + L */
0, /* Select + R */
}
};
 
/* Tab labels */
static const char *TabLabel[] =
{
"Game",
"Save/Load",
"Controls",
"Options",
"System",
"About"
};
 
static const char
PresentSlotText[] = "\026\244\020 Save\t\026\001\020 Load\t\026\243\020 Delete",
EmptySlotText[] = "\026\244\020 Save",
ControlHelpText[] = "\026\250\020 Change mapping\t\026\001\020 Save to \271";
 
#define TAB_QUICKLOAD 0
#define TAB_STATE 1
#define TAB_CONTROLS 2
#define TAB_OPTIONS 3
#define TAB_SYSTEM 4
#define TAB_MAX TAB_SYSTEM
#define TAB_ABOUT (TAB_MAX+1)
 
#define OPTION_DISPLAY_MODE 0x01
#define OPTION_FRAME_SKIP 0x02
#define OPTION_CLOCK_FREQ 0x03
#define OPTION_SHOW_FPS 0x04
#define OPTION_CONTROL_MODE 0x06
#define OPTION_ANIMATE 0x07
#define OPTION_AUTOFIRE 0x08
 
#define SYSTEM_RESET 0x10
#define SYSTEM_SCRNSHOT 0x11
 
#define SET_AS_CURRENT_GAME(filename) \
strncpy(CurrentGame, filename, sizeof(CurrentGame) - 1)
#define CURRENT_GAME (CurrentGame)
#define GAME_LOADED (CurrentGame[0] != '\0')
 
static void psp_init_controls();
static int psp_load_controls();
static int psp_save_controls();
static void psp_load_options();
static int psp_save_options();
 
static void psp_discard_alpha(PspImage *image);
 
static void psp_display_control_tab();
static void psp_display_state_tab();
 
static PspImage* psp_load_state_icon(const char *path);
static int psp_load_state(const char *path);
static PspImage* psp_save_state(const char *path, PspImage *icon);
 
static const char *QuickloadFilter[] = { "ZIP", "NGP", "NGC", "NGPC", '\0' };
 
static int OnGenericCancel(const void *uiobject,
const void *param);
static void OnGenericRender(const void *uiobject,
const void *item_obj);
static int OnGenericButtonPress(const PspUiFileBrowser *browser,
const char *path,
u32 button_mask);
 
static int OnSplashButtonPress(const struct PspUiSplash *splash,
u32 button_mask);
static void OnSplashRender(const void *uiobject,
const void *null);
static const char* OnSplashGetStatusBarText(const struct PspUiSplash *splash);
 
static int OnMenuOk(const void *menu,
const void *item);
static int OnMenuButtonPress(const struct PspUiMenu *uimenu,
pl_menu_item* item,
u32 button_mask);
static int OnMenuItemChanged(const struct PspUiMenu *uimenu,
pl_menu_item* item,
const pl_menu_option* option);
 
static int OnSaveStateOk(const void *gallery, const void *item);
static int OnSaveStateButtonPress(const PspUiGallery *gallery,
pl_menu_item *sel,
u32 button_mask);
 
static int OnQuickloadOk(const void *browser, const void *path);
 
static void OnSystemRender(const void *uiobject,
const void *item_obj);
 
PspUiFileBrowser QuickloadBrowser =
{
OnGenericRender,
OnQuickloadOk,
OnGenericCancel,
OnGenericButtonPress,
QuickloadFilter,
0
};
 
PspUiMenu
OptionUiMenu =
{
OnGenericRender, /* OnRender() */
OnMenuOk, /* OnOk() */
OnGenericCancel, /* OnCancel() */
OnMenuButtonPress, /* OnButtonPress() */
OnMenuItemChanged, /* OnItemChanged() */
},
SystemUiMenu =
{
OnSystemRender, /* OnRender() */
OnMenuOk, /* OnOk() */
OnGenericCancel, /* OnCancel() */
OnMenuButtonPress, /* OnButtonPress() */
OnMenuItemChanged, /* OnItemChanged() */
},
ControlUiMenu =
{
OnGenericRender, /* OnRender() */
OnMenuOk, /* OnOk() */
OnGenericCancel, /* OnCancel() */
OnMenuButtonPress, /* OnButtonPress() */
OnMenuItemChanged, /* OnItemChanged() */
};
 
PspUiGallery SaveStateGallery =
{
OnGenericRender, /* OnRender() */
OnSaveStateOk, /* OnOk() */
OnGenericCancel, /* OnCancel() */
OnSaveStateButtonPress, /* OnButtonPress() */
NULL /* Userdata */
};
 
/* Menu options */
PL_MENU_OPTIONS_BEGIN(MappableButtons)
/* Unmapped */
PL_MENU_OPTION("None", 0)
/* Special */
PL_MENU_OPTION("Special: Open Menu", (SPC|SPC_MENU))
/* Directions */
PL_MENU_OPTION("Up", (JST|0x01))
PL_MENU_OPTION("Down", (JST|0x02))
PL_MENU_OPTION("Left", (JST|0x04))
PL_MENU_OPTION("Right", (JST|0x08))
/* Buttons */
PL_MENU_OPTION("A", (JST|0x10))
PL_MENU_OPTION("B", (JST|0x20))
PL_MENU_OPTION("A (autofire)", (AFI|0x10))
PL_MENU_OPTION("B (autofire)", (AFI|0x20))
PL_MENU_OPTION("Option", (JST|0x40))
PL_MENU_OPTION("Test switch", (JST|0x80))
PL_MENU_OPTIONS_END
PL_MENU_OPTIONS_BEGIN(ToggleOptions)
PL_MENU_OPTION("Disabled", 0)
PL_MENU_OPTION("Enabled", 1)
PL_MENU_OPTIONS_END
PL_MENU_OPTIONS_BEGIN(AutofireOptions)
PL_MENU_OPTION("Once every 3 frames", 2)
PL_MENU_OPTION("Once every 10 frames", 9)
PL_MENU_OPTION("Once every 30 frames", 29)
PL_MENU_OPTION("Once every 60 frames", 59)
PL_MENU_OPTIONS_END
PL_MENU_OPTIONS_BEGIN(ScreenSizeOptions)
PL_MENU_OPTION("Actual size", DISPLAY_MODE_UNSCALED)
PL_MENU_OPTION("4:3 scaled (fit height)", DISPLAY_MODE_FIT_HEIGHT)
PL_MENU_OPTION("16:9 scaled (fit screen)", DISPLAY_MODE_FILL_SCREEN)
PL_MENU_OPTIONS_END
PL_MENU_OPTIONS_BEGIN(FrameskipOptions)
PL_MENU_OPTION("No skipping", 0)
PL_MENU_OPTION("1", 1)
PL_MENU_OPTION("2", 2)
PL_MENU_OPTION("3", 3)
PL_MENU_OPTIONS_END
PL_MENU_OPTIONS_BEGIN(PspClockFreqOptions)
PL_MENU_OPTION("222 MHz", 222)
PL_MENU_OPTION("266 MHz", 266)
PL_MENU_OPTION("300 MHz", 300)
PL_MENU_OPTION("333 MHz", 333)
PL_MENU_OPTIONS_END
PL_MENU_OPTIONS_BEGIN(ControlModeOptions)
PL_MENU_OPTION("\026\242\020 cancels, \026\241\020 confirms (US)", 0)
PL_MENU_OPTION("\026\241\020 cancels, \026\242\020 confirms (Japan)", 1)
PL_MENU_OPTIONS_END
 
/* Menu items */
PL_MENU_ITEMS_BEGIN(ControlMenuDef)
PL_MENU_ITEM(PSP_CHAR_ANALUP,0,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_ANALDOWN,1,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_ANALLEFT,2,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_ANALRIGHT,3,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_UP,4,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_DOWN,5,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_LEFT,6,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_RIGHT,7,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_SQUARE,8,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_CROSS,9,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_CIRCLE,10,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_TRIANGLE,11,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_LTRIGGER,12,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_RTRIGGER,13,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_SELECT,14,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_START,15,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_LTRIGGER"+"PSP_CHAR_RTRIGGER,16,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_START"+"PSP_CHAR_SELECT,17,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_SELECT"+"PSP_CHAR_LTRIGGER,18,MappableButtons,ControlHelpText)
PL_MENU_ITEM(PSP_CHAR_SELECT"+"PSP_CHAR_RTRIGGER,19,MappableButtons,ControlHelpText)
PL_MENU_ITEMS_END
PL_MENU_ITEMS_BEGIN(OptionMenuDef)
PL_MENU_HEADER("Video")
PL_MENU_ITEM("Screen size",OPTION_DISPLAY_MODE,ScreenSizeOptions,"\026\250\020 Change screen size")
PL_MENU_HEADER("Input")
PL_MENU_ITEM("Rate of autofire", OPTION_AUTOFIRE,AutofireOptions,"\026\250\020 Adjust rate of autofire")
PL_MENU_HEADER("Performance")
PL_MENU_ITEM("Frame skipping", OPTION_FRAME_SKIP,FrameskipOptions,"\026\250\020 Select number of frames to skip per update")
PL_MENU_ITEM("PSP clock frequency",OPTION_CLOCK_FREQ,PspClockFreqOptions,"\026\250\020 Larger values: faster emulation, faster battery depletion (default: 222MHz)")
PL_MENU_ITEM("Show FPS counter",OPTION_SHOW_FPS,ToggleOptions,"\026\250\020 Show/hide the frames-per-second counter")
PL_MENU_HEADER("Menu")
PL_MENU_ITEM("Button mode",OPTION_CONTROL_MODE,ControlModeOptions,"\026\250\020 Change OK and Cancel button mapping")
PL_MENU_ITEM("Animations",OPTION_ANIMATE,ToggleOptions,"\026\250\020 Enable/disable menu animations")
PL_MENU_ITEMS_END
PL_MENU_ITEMS_BEGIN(SystemMenuDef)
PL_MENU_HEADER("Options")
PL_MENU_ITEM("Reset",SYSTEM_RESET,NULL,"\026\001\020 Reset system")
PL_MENU_ITEM("Save screenshot",SYSTEM_SCRNSHOT,NULL,"\026\001\020 Save screenshot")
PL_MENU_ITEMS_END
 
PspUiSplash SplashScreen =
{
OnSplashRender,
OnGenericCancel,
OnSplashButtonPress,
OnSplashGetStatusBarText
};
 
int InitMenu()
{
if (!InitEmulation())
return 0;
 
/* Initialize paths */
sprintf(SaveStatePath, "%sstates/", pl_psp_get_app_directory());
sprintf(ScreenshotPath, "ms0:/PSP/PHOTO/%s/", PSP_APP_NAME);
sprintf(GamePath, "%s", pl_psp_get_app_directory());
 
/* Load the background image */
Background = pspImageLoadPng("background.png");
 
/* Initialize menus */
pl_menu_create(&SystemUiMenu.Menu, SystemMenuDef);
pl_menu_create(&OptionUiMenu.Menu, OptionMenuDef);
pl_menu_create(&ControlUiMenu.Menu, ControlMenuDef);
 
/* Init NoSaveState icon image */
NoSaveIcon = pspImageCreate(160, 152, PSP_IMAGE_16BPP);
pspImageClear(NoSaveIcon, RGB(0x44,0x00,0x00));
 
/* Initialize state menu */
int i;
pl_menu_item *item;
for (i = 0; i < 10; i++)
{
item = pl_menu_append_item(&SaveStateGallery.Menu, i, NULL);
pl_menu_set_item_help_text(item, EmptySlotText);
}
 
/* Initialize options */
psp_load_controls();
psp_load_options();
 
/* Initialize UI components */
UiMetric.Background = Background;
UiMetric.Font = &PspStockFont;
UiMetric.Left = 8;
UiMetric.Top = 24;
UiMetric.Right = 472;
UiMetric.Bottom = 250;
UiMetric.ScrollbarColor = PSP_COLOR_GRAY;
UiMetric.ScrollbarBgColor = 0x44ffffff;
UiMetric.ScrollbarWidth = 10;
UiMetric.TextColor = PSP_COLOR_GRAY;
UiMetric.SelectedColor = COLOR(0xf7,0xc2,0x50,0xFF);
UiMetric.SelectedBgColor = COLOR(0xd5,0xf1,0x17,0x99);
UiMetric.StatusBarColor = PSP_COLOR_WHITE;
UiMetric.BrowserFileColor = PSP_COLOR_GRAY;
UiMetric.BrowserDirectoryColor = PSP_COLOR_YELLOW;
UiMetric.GalleryIconsPerRow = 5;
UiMetric.GalleryIconMarginWidth = 16;
UiMetric.MenuItemMargin = 20;
UiMetric.MenuSelOptionBg = PSP_COLOR_GRAY;
UiMetric.MenuOptionBoxColor = PSP_COLOR_GRAY;
UiMetric.MenuOptionBoxBg = COLOR(0x44,0x00,0x00,0xbb);
UiMetric.MenuDecorColor = UiMetric.SelectedColor;
UiMetric.DialogFogColor = COLOR(0xd5,0xf1,0x17,0xbb);
UiMetric.TitlePadding = 4;
UiMetric.TitleColor = PSP_COLOR_WHITE;
UiMetric.MenuFps = 30;
UiMetric.TabBgColor = COLOR(0xcc,0x73,0x73,0xff);
UiMetric.BrowserScreenshotPath = ScreenshotPath;
UiMetric.BrowserScreenshotDelay = 30;
 
TabIndex = TAB_ABOUT;
 
return 1;
}
 
void DisplayMenu()
{
pl_menu_item *item;
 
/* Menu loop */
do
{
ResumeEmulation = 0;
 
/* Set normal clock frequency */
pl_psp_set_clock_freq(222);
/* Set buttons to autorepeat */
pspCtrlSetPollingMode(PSP_CTRL_AUTOREPEAT);
 
do
{
/* Display appropriate tab */
switch (TabIndex)
{
case TAB_QUICKLOAD:
pspUiOpenBrowser(&QuickloadBrowser,
(GAME_LOADED) ? CURRENT_GAME : GamePath);
break;
case TAB_CONTROLS:
psp_display_control_tab();
break;
case TAB_OPTIONS:
item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_DISPLAY_MODE);
pl_menu_select_option_by_value(item, (void*)(int)psp_options.display_mode);
item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CLOCK_FREQ);
pl_menu_select_option_by_value(item, (void*)(int)psp_options.clock_freq);
item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_SHOW_FPS);
pl_menu_select_option_by_value(item, (void*)(int)psp_options.show_fps);
item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CONTROL_MODE);
pl_menu_select_option_by_value(item, (void*)(UiMetric.OkButton == PSP_CTRL_CIRCLE));
item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_ANIMATE);
pl_menu_select_option_by_value(item, (void*)(int)UiMetric.Animate);
item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_FRAME_SKIP);
pl_menu_select_option_by_value(item, (void*)(int)psp_options.frame_skip);
item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_AUTOFIRE);
pl_menu_select_option_by_value(item, (void*)(int)psp_options.autofire);
 
pspUiOpenMenu(&OptionUiMenu, NULL);
break;
case TAB_STATE:
psp_display_state_tab();
break;
case TAB_SYSTEM:
pspUiOpenMenu(&SystemUiMenu, NULL);
break;
case TAB_ABOUT:
pspUiSplashScreen(&SplashScreen);
break;
}
} while (!ExitPSP && !ResumeEmulation);
 
if (!ExitPSP)
{
/* Set clock frequency during emulation */
pl_psp_set_clock_freq(psp_options.clock_freq);
/* Set buttons to normal mode */
pspCtrlSetPollingMode(PSP_CTRL_NORMAL);
 
if (ResumeEmulation)
{
/* Resume emulation */
if (UiMetric.Animate) pspUiFadeout();
RunEmulation();
if (UiMetric.Animate) pspUiFadeout();
}
}
} while (!ExitPSP);
}
 
void TrashMenu()
{
TrashEmulation();
 
pl_menu_destroy(&SystemUiMenu.Menu);
pl_menu_destroy(&OptionUiMenu.Menu);
pl_menu_destroy(&ControlUiMenu.Menu);
pl_menu_destroy(&SaveStateGallery.Menu);
 
pspImageDestroy(NoSaveIcon);
pspImageDestroy(Background);
 
psp_save_options();
}
 
/* Handles drawing of generic items */
static void OnGenericRender(const void *uiobject,
const void *item_obj)
{
/* Draw tabs */
int i, x, width, height = pspFontGetLineHeight(UiMetric.Font);
for (i = 0, x = 5; i <= TAB_MAX; i++, x += width + 10)
{
width = -10;
 
if (!GAME_LOADED && (i == TAB_STATE || i == TAB_SYSTEM))
continue;
 
/* Determine width of text */
width = pspFontGetTextWidth(UiMetric.Font, TabLabel[i]);
 
/* Draw background of active tab */
if (i == TabIndex)
pspVideoFillRect(x - 5, 0, x + width + 5, height + 1, UiMetric.TabBgColor);
 
/* Draw name of tab */
pspVideoPrint(UiMetric.Font, x, 0, TabLabel[i], PSP_COLOR_WHITE);
}
}
 
static int OnGenericButtonPress(const PspUiFileBrowser *browser,
const char *path,
u32 button_mask)
{
int tab_index;
 
/* If L or R are pressed, switch tabs */
if (button_mask & PSP_CTRL_LTRIGGER)
{
TabIndex--;
do
{
tab_index = TabIndex;
if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex--;
if (TabIndex < 0) TabIndex = TAB_MAX;
} while (tab_index != TabIndex);
}
else if (button_mask & PSP_CTRL_RTRIGGER)
{
TabIndex++;
do
{
tab_index = TabIndex;
if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex++;
if (TabIndex > TAB_MAX) TabIndex = 0;
} while (tab_index != TabIndex);
}
else if ((button_mask & (PSP_CTRL_START | PSP_CTRL_SELECT))
== (PSP_CTRL_START | PSP_CTRL_SELECT))
{
if (pl_util_save_vram_seq(ScreenshotPath, "ui"))
pspUiAlert("Saved successfully");
else
pspUiAlert("ERROR: Not saved");
return 0;
}
else return 0;
 
return 1;
}
 
static int OnGenericCancel(const void *uiobject,
const void* param)
{
if (!GAME_LOADED)
return 0;
 
ResumeEmulation = 1;
return 1;
}
 
static int OnQuickloadOk(const void *browser,
const void *path)
{
/* Write flash data for current game */
if (GAME_LOADED)
writeSaveGameFile();
 
pspUiFlashMessage("Loading, please wait...");
 
if (!handleInputFile((char*)path))
{
pspUiAlert("Error loading cartridge");
return 0;
}
 
/* Reset selected state */
SaveStateGallery.Menu.selected = NULL;
 
SET_AS_CURRENT_GAME((char*)path);
pl_file_get_parent_directory((const char*)path,
GamePath,
sizeof(GamePath));
ResumeEmulation = 1;
 
system_sound_chipreset(); /* Reset sound */
 
return 1;
}
 
static int OnSaveStateOk(const void *gallery, const void *item)
{
char *path;
const char *config_name = pl_file_get_filename(CURRENT_GAME);
 
path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8);
sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name,
((const pl_menu_item*)item)->id);
 
if (pl_file_exists(path) && pspUiConfirm("Load state?"))
{
if (psp_load_state(path))
{
ResumeEmulation = 1;
pl_menu_find_item_by_id(&((PspUiGallery*)gallery)->Menu,
((pl_menu_item*)item)->id);
free(path);
 
return 1;
}
 
pspUiAlert("ERROR: State not loaded");
}
 
free(path);
return 0;
}
 
static int OnSaveStateButtonPress(const PspUiGallery *gallery,
pl_menu_item *sel,
u32 button_mask)
{
if (button_mask & PSP_CTRL_SQUARE
|| button_mask & PSP_CTRL_TRIANGLE)
{
char *path;
char caption[32];
const char *config_name = pl_file_get_filename(CURRENT_GAME);
pl_menu_item *item = pl_menu_find_item_by_id(&gallery->Menu, sel->id);
 
path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8);
sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name, item->id);
 
do /* not a real loop; flow control construct */
{
if (button_mask & PSP_CTRL_SQUARE)
{
if (pl_file_exists(path) && !pspUiConfirm("Overwrite existing state?"))
break;
 
pspUiFlashMessage("Saving, please wait ...");
 
PspImage *icon;
if (!(icon = psp_save_state(path, Screen)))
{
pspUiAlert("ERROR: State not saved");
break;
}
 
SceIoStat stat;
 
/* Trash the old icon (if any) */
if (item->param && item->param != NoSaveIcon)
pspImageDestroy((PspImage*)item->param);
 
/* Update icon, help text */
item->param = icon;
pl_menu_set_item_help_text(item, PresentSlotText);
 
/* Get file modification time/date */
if (sceIoGetstat(path, &stat) < 0)
sprintf(caption, "ERROR");
else
sprintf(caption, "%02i/%02i/%02i %02i:%02i",
stat.st_mtime.month,
stat.st_mtime.day,
stat.st_mtime.year - (stat.st_mtime.year / 100) * 100,
stat.st_mtime.hour,
stat.st_mtime.minute);
 
pl_menu_set_item_caption(item, caption);
}
else if (button_mask & PSP_CTRL_TRIANGLE)
{
if (!pl_file_exists(path) || !pspUiConfirm("Delete state?"))
break;
 
if (!pl_file_rm(path))
{
pspUiAlert("ERROR: State not deleted");
break;
}
 
/* Trash the old icon (if any) */
if (item->param && item->param != NoSaveIcon)
pspImageDestroy((PspImage*)item->param);
 
/* Update icon, caption */
item->param = NoSaveIcon;
pl_menu_set_item_help_text(item, EmptySlotText);
pl_menu_set_item_caption(item, "Empty");
}
} while (0);
 
if (path) free(path);
return 0;
}
 
return OnGenericButtonPress(NULL, NULL, button_mask);
}
 
static void OnSplashRender(const void *splash,
const void *null)
{
int fh, i, x, y, height;
const char *lines[] =
{
PSP_APP_NAME" version "PSP_APP_VER" ("__DATE__")",
"\026http://psp.akop.org/race",
" ",
"2008 Akop Karapetyan (port)",
"2008 Flavor (original PSP port, optimization)",
"2006 Judge_ (emulation)",
NULL
};
 
fh = pspFontGetLineHeight(UiMetric.Font);
 
for (i = 0; lines[i]; i++);
height = fh * (i - 1);
 
/* Render lines */
for (i = 0, y = SCR_HEIGHT / 2 - height / 2; lines[i]; i++, y += fh)
{
x = SCR_WIDTH / 2 - pspFontGetTextWidth(UiMetric.Font, lines[i]) / 2;
pspVideoPrint(UiMetric.Font, x, y, lines[i], PSP_COLOR_GRAY);
}
 
/* Render PSP status */
OnGenericRender(splash, null);
}
 
static int OnSplashButtonPress(const struct PspUiSplash *splash,
u32 button_mask)
{
return OnGenericButtonPress(NULL, NULL, button_mask);
}
 
static const char* OnSplashGetStatusBarText(const struct PspUiSplash *splash)
{
return "\026\255\020/\026\256\020 Switch tabs";
}
 
static int OnMenuOk(const void *uimenu, const void* sel_item)
{
if (uimenu == &ControlUiMenu)
{
/* Save to MS */
if (psp_save_controls())
pspUiAlert("Changes saved");
else
pspUiAlert("ERROR: Changes not saved");
}
else
{
switch (((const pl_menu_item*)sel_item)->id)
{
case SYSTEM_RESET:
if (pspUiConfirm("Reset the system?"))
{
/* Write flash data for current game */
if (GAME_LOADED)
writeSaveGameFile();
 
mainemuinit();
ResumeEmulation = 1;
return 1;
}
break;
case SYSTEM_SCRNSHOT:
/* Save screenshot */
if (!pl_util_save_image_seq(ScreenshotPath,
pl_file_get_filename(CURRENT_GAME),
Screen))
pspUiAlert("ERROR: Screenshot not saved");
else
pspUiAlert("Screenshot saved successfully");
break;
}
}
return 0;
}
 
static int OnMenuButtonPress(const struct PspUiMenu *uimenu,
pl_menu_item* sel_item,
u32 button_mask)
{
if (uimenu == &ControlUiMenu)
{
if (button_mask & PSP_CTRL_TRIANGLE)
{
pl_menu_item *item;
int i;
 
/* Load default mapping */
memcpy(&current_map, &default_map, sizeof(psp_ctrl_map_t));
 
/* Modify the menu */
for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++)
pl_menu_select_option_by_value(item, (void*)default_map.button_map[i]);
 
return 0;
}
}
 
return OnGenericButtonPress(NULL, NULL, button_mask);
}
 
static int OnMenuItemChanged(const struct PspUiMenu *uimenu,
pl_menu_item* item,
const pl_menu_option* option)
{
if (uimenu == &ControlUiMenu)
{
current_map.button_map[item->id] = (unsigned int)option->value;
}
else
{
switch((int)item->id)
{
case OPTION_DISPLAY_MODE:
psp_options.display_mode = (int)option->value;
break;
case OPTION_FRAME_SKIP:
psp_options.frame_skip = (int)option->value;
break;
case OPTION_CLOCK_FREQ:
psp_options.clock_freq = (int)option->value;
break;
case OPTION_SHOW_FPS:
psp_options.show_fps = (int)option->value;
break;
case OPTION_CONTROL_MODE:
UiMetric.OkButton = (!(int)option->value)
? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE;
UiMetric.CancelButton = (!(int)option->value)
? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS;
break;
case OPTION_ANIMATE:
UiMetric.Animate = (int)option->value;
break;
case OPTION_AUTOFIRE:
psp_options.autofire = (int)option->value;
break;
}
}
return 1;
}
 
static void OnSystemRender(const void *uiobject,
const void *item_obj)
{
int w, h, x, y;
w = Screen->Viewport.Width;
h = Screen->Viewport.Height;
x = UiMetric.Right - w - UiMetric.ScrollbarWidth;
y = SCR_HEIGHT - h - 56;
 
/* Draw a small representation of the screen */
pspVideoShadowRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_BLACK, 3);
sceGuDisable(GU_BLEND);
pspVideoPutImage(Screen, x, y, w, h);
sceGuEnable(GU_BLEND);
pspVideoDrawRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_GRAY);
 
OnGenericRender(uiobject, item_obj);
}
 
static void psp_init_controls()
{
/* Initialize to default configuration */
memcpy(&current_map, &default_map, sizeof(psp_ctrl_map_t));
}
 
static int psp_load_controls()
{
psp_ctrl_map_t *config = &current_map;
pl_file_path path;
snprintf(path, sizeof(path) - 1, "%sbuttons.cnf",
pl_psp_get_app_directory());
 
/* If no configuration, load defaults */
if (!pl_file_exists(path))
{
psp_init_controls();
return 1;
}
 
/* Open file for reading */
FILE *file = fopen(path, "r");
if (!file) return 0;
 
/* Read contents of struct */
int nread = fread(config, sizeof(psp_ctrl_map_t), 1, file);
fclose(file);
 
if (nread != 1)
{
psp_init_controls();
return 0;
}
 
return 1;
}
 
static int psp_save_controls()
{
psp_ctrl_map_t *config = &current_map;
pl_file_path path;
snprintf(path, sizeof(path) - 1, "%sbuttons.cnf",
pl_psp_get_app_directory());
 
/* Open file for writing */
FILE *file = fopen(path, "w");
if (!file) return 0;
 
/* Write contents of struct */
int nwritten = fwrite(config, sizeof(psp_ctrl_map_t), 1, file);
fclose(file);
 
return (nwritten == 1);
}
 
static void psp_display_control_tab()
{
pl_menu_item *item;
int i;
 
/* Load current button mappings */
for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++)
pl_menu_select_option_by_value(item, (void*)current_map.button_map[i]);
 
pspUiOpenMenu(&ControlUiMenu, NULL);
}
 
static void psp_display_state_tab()
{
pl_menu_item *item, *sel = NULL;
SceIoStat stat;
ScePspDateTime latest;
char caption[32];
const char *config_name = pl_file_get_filename(CURRENT_GAME);
char *path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8);
char *game_name = strdup(config_name);
char *dot = strrchr(game_name, '.');
if (dot) *dot='\0';
 
memset(&latest,0,sizeof(latest));
 
/* Initialize icons */
for (item = SaveStateGallery.Menu.items; item; item = item->next)
{
sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name, item->id);
 
if (pl_file_exists(path))
{
if (sceIoGetstat(path, &stat) < 0)
sprintf(caption, "ERROR");
else
{
/* Determine the latest save state */
if (pl_util_date_compare(&latest, &stat.st_mtime) < 0)
{
sel = item;
latest = stat.st_mtime;
}
 
sprintf(caption, "%02i/%02i/%02i %02i:%02i",
stat.st_mtime.month,
stat.st_mtime.day,
stat.st_mtime.year - (stat.st_mtime.year / 100) * 100,
stat.st_mtime.hour,
stat.st_mtime.minute);
}
 
pl_menu_set_item_caption(item, caption);
item->param = psp_load_state_icon(path);
pl_menu_set_item_help_text(item, PresentSlotText);
}
else
{
pl_menu_set_item_caption(item, "Empty");
item->param = NoSaveIcon;
pl_menu_set_item_help_text(item, EmptySlotText);
}
}
 
free(path);
 
/* Highlight the latest save state if none are selected */
if (SaveStateGallery.Menu.selected == NULL)
SaveStateGallery.Menu.selected = sel;
 
pspUiOpenGallery(&SaveStateGallery, game_name);
free(game_name);
 
/* Destroy any icons */
for (item = SaveStateGallery.Menu.items; item; item = item->next)
if (item->param != NULL && item->param != NoSaveIcon)
pspImageDestroy((PspImage*)item->param);
}
 
/* Load state icon */
static PspImage* psp_load_state_icon(const char *path)
{
FILE *f = fopen(path, "r");
if (!f) return NULL;
 
/* Load image */
PspImage *image = pspImageLoadPngFd(f);
fclose(f);
 
return image;
}
 
/* Load state */
static int psp_load_state(const char *path)
{
/* Open file for reading */
FILE *f = fopen(path, "r");
if (!f) return 0;
 
/* Load image into temporary object */
PspImage *image = pspImageLoadPngFd(f);
pspImageDestroy(image);
 
/* Load the state data */
int status = state_restore(f);
fclose(f);
 
return status;
}
 
static void psp_discard_alpha(PspImage *image)
{
int i, j;
for (i = image->Viewport.Y; i < image->Viewport.Height; i++)
for (j = image->Viewport.X; j < image->Viewport.Width; j++)
((u16*)image->Pixels)[(i * image->Width) + j] |= 0x8000;
}
 
/* Save state */
static PspImage* psp_save_state(const char *path, PspImage *icon)
{
/* Open file for writing */
FILE *f;
if (!(f = fopen(path, "w")))
return NULL;
 
/* Create thumbnail */
PspImage *thumb;
thumb = pspImageCreateCopy(icon);
 
if (!thumb) { fclose(f); return NULL; }
 
psp_discard_alpha(thumb);
 
/* Write the thumbnail */
if (!pspImageSavePngFd(f, thumb))
{
pspImageDestroy(thumb);
fclose(f);
pl_file_rm(path);
return NULL;
}
 
/* Write the state */
if (!state_store(f))
{
pspImageDestroy(thumb);
thumb = NULL;
}
 
fclose(f);
return thumb;
}
 
static void psp_load_options()
{
pl_file_path path;
snprintf(path, sizeof(path) - 1, "%s%s",
pl_psp_get_app_directory(), "options.ini");
 
/* Load INI */
pl_ini_file file;
pl_ini_load(&file, path);
 
psp_options.display_mode = pl_ini_get_int(&file, "Video", "Display Mode",
DISPLAY_MODE_UNSCALED);
psp_options.frame_skip = pl_ini_get_int(&file, "Video", "Frame Skipping", 0);
psp_options.clock_freq = pl_ini_get_int(&file, "Video", "PSP Clock Frequency", 333);
psp_options.show_fps = pl_ini_get_int(&file, "Video", "Show FPS", 0);
pl_ini_get_string(&file, "File", "Game Path", NULL,
GamePath, sizeof(GamePath));
 
UiMetric.Animate = pl_ini_get_int(&file, "Menu", "Animate", 1);
psp_options.autofire = pl_ini_get_int(&file, "Input", "Autofire", 2);
if (psp_options.autofire < 2)
psp_options.autofire = 2;
 
int control_mode = pl_ini_get_int(&file, "Menu", "Control Mode", 0);
UiMetric.OkButton = (!control_mode)
? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE;
UiMetric.CancelButton = (!control_mode)
? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS;
 
/* Clean up */
pl_ini_destroy(&file);
}
 
static int psp_save_options()
{
pl_file_path path;
snprintf(path, sizeof(path)-1, "%s%s",
pl_psp_get_app_directory(), "options.ini");
 
/* Initialize INI structure */
pl_ini_file file;
pl_ini_create(&file);
pl_ini_set_int(&file, "Video", "Display Mode",
psp_options.display_mode);
pl_ini_set_int(&file, "Video", "Frame Skipping",
psp_options.frame_skip);
pl_ini_set_int(&file, "Video", "PSP Clock Frequency",
psp_options.clock_freq);
pl_ini_set_int(&file, "Video", "Show FPS",
psp_options.show_fps);
pl_ini_set_int(&file, "Menu", "Control Mode",
(UiMetric.OkButton == PSP_CTRL_CIRCLE));
pl_ini_set_int(&file, "Menu", "Animate",
UiMetric.Animate);
pl_ini_set_int(&file, "Input", "Autofire",
psp_options.autofire);
pl_ini_set_string(&file, "File", "Game Path",
GamePath);
 
int status = pl_ini_save(&file, path);
pl_ini_destroy(&file);
 
return status;
}
/race/2.15/psp/psplib/pl_util.c
0,0 → 1,193
/* psplib/pl_util.c
Various utility functions
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include "pl_util.h"
 
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <pspkernel.h>
#include <psprtc.h>
 
#include "pl_file.h"
#include "video.h"
 
#define CRC_BUFFER_SIZE 8192
 
static uint32_t compute_buffer_crc(uint32_t inCrc32,
const void *buf,
size_t bufLen);
 
int pl_util_save_image_seq(const char *path,
const char *filename,
const PspImage *image)
{
/* If screenshot path does not exist, create it */
if (!pl_file_exists(path))
if (!pl_file_mkdir_recursive(path))
return 0;
 
/* Loop until first free screenshot slot is found */
int i = 0;
pl_file_path full_path;
do
{
snprintf(full_path,
sizeof(full_path) - 1,
"%s%s-%02i.png",
path, filename, i);
} while (pl_file_exists(full_path) && ++i < 100);
 
/* Save the screenshot */
return pspImageSavePng(full_path, image);
}
 
int pl_util_save_vram_seq(const char *path,
const char *filename)
{
PspImage* vram = pspVideoGetVramBufferCopy();
if (!vram) return 0;
 
int exit_code = pl_util_save_image_seq(path,
filename,
vram);
pspImageDestroy(vram);
 
return exit_code;
}
 
int pl_util_date_compare(const ScePspDateTime *date1,
const ScePspDateTime *date2)
{
if (date1->year != date2->year)
return date1->year - date2->year;
if (date1->month != date2->month)
return date1->month - date2->month;
if (date1->day != date2->day)
return date1->day - date2->day;
if (date1->hour != date2->hour)
return date1->hour - date2->hour;
if (date1->minute != date2->minute)
return date1->minute - date2->minute;
if (date1->second != date2->second)
return date1->second - date2->second;
return 0;
}
 
int pl_util_compute_crc32_buffer(const void *buf,
size_t buf_len,
uint32_t *crc_32)
{
*crc_32 = compute_buffer_crc(0,
buf,
buf_len);
return 1;
}
 
 
int pl_util_compute_crc32_file(const char *path,
uint32_t *outCrc32)
{
FILE *file;
if (!(file = fopen(path, "r")))
return 0;
 
int status = pl_util_compute_crc32_fd(file, outCrc32);
fclose(file);
 
return status;
}
 
int pl_util_compute_crc32_fd(FILE *file,
uint32_t *outCrc32)
{
unsigned char buf[CRC_BUFFER_SIZE];
size_t bufLen;
 
/** accumulate crc32 from file **/
*outCrc32 = 0;
while (1)
{
if ((bufLen = fread( buf, 1, CRC_BUFFER_SIZE, file )) == 0)
{
if (ferror(file))
return -1;
break;
}
*outCrc32 = compute_buffer_crc(*outCrc32, buf, bufLen);
}
 
return 0;
}
 
static uint32_t compute_buffer_crc(uint32_t inCrc32,
const void *buf,
size_t bufLen)
{
static const unsigned long crcTable[256] = {
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,
0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,
0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,
0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,
0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4,
0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,
0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,0x26D930AC,
0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,
0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,
0xB6662D3D,0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,
0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,
0x086D3D2D,0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,
0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,
0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,0x4DB26158,0x3AB551CE,
0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,
0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,
0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,
0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,
0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,
0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,0xF00F9344,0x8708A3D2,0x1E01F268,
0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,
0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8,
0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,
0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,
0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,
0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,
0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,
0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242,
0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,
0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,
0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,
0x47B2CF7F,0x30B5FFE9,0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,
0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,
0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D };
unsigned long crc32;
unsigned char *byteBuf;
size_t i;
 
/** accumulate crc32 for buffer **/
crc32 = inCrc32 ^ 0xFFFFFFFF;
byteBuf = (unsigned char*) buf;
for (i=0; i < bufLen; i++)
crc32 = (crc32 >> 8) ^ crcTable[ (crc32 ^ byteBuf[i]) & 0xFF ];
return( crc32 ^ 0xFFFFFFFF );
}
/race/2.15/psp/psplib/ui.c
0,0 → 1,2820
/* psplib/ui.c
Simple user interface implementation
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include <malloc.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <pspkernel.h>
#include <psprtc.h>
#include <psppower.h>
#include <pspgu.h>
#include <pspnet_adhocmatching.h>
 
#include "pl_psp.h"
#include "pl_file.h"
#include "ctrl.h"
#include "ui.h"
#include "font.h"
 
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
 
#define UI_ANIM_FRAMES 8
#define UI_ANIM_FOG_STEP 0x0f
 
#define ADHOC_INITIALIZING "Initializing Ad-hoc networking. Please wait..."
#define ADHOC_AWAITING_JOIN "Waiting for someone to join..."
 
#define CONTROL_BUTTON_MASK \
(PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_CROSS | PSP_CTRL_SQUARE | \
PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER | PSP_CTRL_SELECT | PSP_CTRL_START)
 
static const char
*AlertDialogButtonTemplate = "\026\001\020/\026\002\020 Close",
*ConfirmDialogButtonTemplate = "\026\001\020 Confirm\t\026\002\020 Cancel",
*YesNoCancelDialogButtonTemplate =
"\026\001\020 Yes\t\026"PSP_CHAR_SQUARE"\020 No\t\026\002\020 Cancel",
 
*SelectorTemplate = "\026\001\020 Confirm\t\026\002\020 Cancel",
 
*BrowserTemplates[] = {
"\026\002\020 Cancel\t\026\001\020 Open",
"\026\002\020 Cancel\t\026\001\020 Enter directory",
"\026\002\020 Cancel\t\026\001\020 Open\t\026"PSP_CHAR_TRIANGLE"\020 Parent directory",
"\026\002\020 Cancel\t\026\001\020 Enter directory\t\026"PSP_CHAR_TRIANGLE"\020 Parent directory"
},
 
*SplashStatusBarTemplate = "\026\255\020/\026\256\020 Switch tabs",
 
*OptionModeTemplate =
"\026\245\020/\026\246\020 Select\t\026\247\020/\026\002\020 Cancel\t\026\250\020/\026\001\020 Confirm";
 
enum
{
BrowserTemplateOpenTop = 0,
BrowserTemplateEnterTop = 1,
BrowserTemplateOpen = 2,
BrowserTemplateEnter = 3,
};
 
void enter_directory(pl_file_path current_dir,
const char *subdir);
 
#define BROWSER_TEMPLATE_COUNT 4
 
struct UiPos
{
int Index;
int Offset;
const pl_menu_item *Top;
};
 
struct AdhocMatchEvent
{
int NewEvent;
int EventID;
PspMAC EventMAC;
PspMAC CurrentMAC;
char OptData[512];
};
 
static struct AdhocMatchEvent _adhoc_match_event;
 
static void adhocMatchingCallback(int unk1,
int event,
unsigned char *mac2,
int opt_len,
void *opt_data);
 
#define ADHOC_PENDING 0
#define ADHOC_WAIT_CLI 1
#define ADHOC_WAIT_HOST 2
#define ADHOC_WAIT_EST 3
#define ADHOC_ESTABLISHED 4
#define ADHOC_EST_AS_CLI 5
 
#ifndef MATCHING_JOINED
#define MATCHING_JOINED PSP_ADHOC_MATCHING_EVENT_JOIN
#define MATCHING_DISCONNECT PSP_ADHOC_MATCHING_EVENT_LEFT
#define MATCHING_CANCELED PSP_ADHOC_MATCHING_EVENT_CANCEL
#define MATCHING_SELECTED PSP_ADHOC_MATCHING_EVENT_ACCEPT
#define MATCHING_REJECTED PSP_ADHOC_MATCHING_EVENT_REJECT
#define MATCHING_ESTABLISHED PSP_ADHOC_MATCHING_EVENT_COMPLETE
#endif
 
/* TODO: dynamically allocate ?? */
static unsigned int __attribute__((aligned(16))) call_list[524288];//262144];
 
/* Gets status string - containing current time and battery information */
static void GetStatusString(char *status, int length)
{
static char main_str[128], batt_str[32];
pspTime time;
 
/* Get current time */
sceRtcGetCurrentClockLocalTime(&time);
 
/* Get the battery/power-related information */
if (!scePowerIsBatteryExist()) sprintf(batt_str, PSP_CHAR_POWER);
else
{
/* If the battery's online, display charging stats */
int batt_time = scePowerGetBatteryLifeTime();
int batt_percent = scePowerGetBatteryLifePercent();
int i, charging = scePowerIsBatteryCharging();
 
static int percentiles[] = { 60, 30, 12, 0 };
for (i = 0; i < 4; i++)
if (batt_percent >= percentiles[i])
break;
 
/* Fix for when battery switches state from AC to batt */
batt_time = (batt_time >= 0) ? batt_time : 0;
 
sprintf(batt_str, "%c%3i%% (%02i:%02i)",
(charging) ? *PSP_CHAR_POWER : *PSP_CHAR_FULL_BATT + i,
batt_percent, batt_time / 60, batt_time % 60);
}
 
/* Write the rest of the string */
sprintf(main_str, "\270%2i/%2i %02i%c%02i %s ",
time.month, time.day, time.hour, (time.microseconds > 500000) ? ':' : ' ',
time.minutes, batt_str);
 
strncpy(status, main_str, length);
status[length - 1] = '\0';
}
 
static inline void RenderStatus()
{
static char status[128];
GetStatusString(status, sizeof(status));
 
int width = pspFontGetTextWidth(UiMetric.Font, status);
pspVideoPrint(UiMetric.Font, SCR_WIDTH - width, 0, status, PSP_COLOR_WHITE);
}
 
static void ReplaceIcons(char *string)
{
char *ch;
 
for (ch = string; *ch; ch++)
{
switch(*ch)
{
case '\001': *ch = pspUiGetButtonIcon(UiMetric.OkButton); break;
case '\002': *ch = pspUiGetButtonIcon(UiMetric.CancelButton); break;
}
}
}
 
char pspUiGetButtonIcon(u32 button_mask)
{
switch (button_mask)
{
case PSP_CTRL_CROSS: return *PSP_CHAR_CROSS;
case PSP_CTRL_CIRCLE: return *PSP_CHAR_CIRCLE;
case PSP_CTRL_TRIANGLE: return *PSP_CHAR_TRIANGLE;
case PSP_CTRL_SQUARE: return *PSP_CHAR_SQUARE;
default: return '?';
}
}
 
void pspUiAlert(const char *message)
{
PspImage *screen = NULL;
int sx, sy, dx, dy, th, fh, mw, cw, w, h;
int i, n = UI_ANIM_FRAMES;
char *instr = strdup(AlertDialogButtonTemplate);
ReplaceIcons(instr);
 
mw = pspFontGetTextWidth(UiMetric.Font, message);
cw = pspFontGetTextWidth(UiMetric.Font, instr);
fh = pspFontGetLineHeight(UiMetric.Font);
th = pspFontGetTextHeight(UiMetric.Font, message);
 
w = ((mw > cw) ? mw : cw) + 50;
h = th + fh * 3;
sx = SCR_WIDTH / 2 - w / 2;
sy = SCR_HEIGHT / 2 - h / 2;
dx = sx + w;
dy = sy + h;
 
/* Intro animation */
if (UiMetric.Animate)
{
/* Get copy of screen */
screen = pspVideoGetVramBufferCopy();
 
for (i = 0; i < n; i++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
COLOR(RED_32(UiMetric.MenuOptionBoxBg),
GREEN_32(UiMetric.MenuOptionBoxBg),
BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
pspVideoBegin();
 
if (UiMetric.Animate)
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message,
UiMetric.TextColor);
pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr,
UiMetric.TextColor);
pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
SceCtrlData pad;
 
/* Loop until X or O is pressed */
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton)
break;
}
if (!ExitPSP && UiMetric.Animate)
{
/* Exit animation */
for (i = n - 1; i >= 0; i--)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
COLOR(RED_32(UiMetric.MenuOptionBoxBg),
GREEN_32(UiMetric.MenuOptionBoxBg),
BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
if (screen) pspImageDestroy(screen);
free(instr);
}
 
int pspUiYesNoCancel(const char *message)
{
PspImage *screen = NULL;
int sx, sy, dx, dy, th, fh, mw, cw, w, h;
int i, n = UI_ANIM_FRAMES;
char *instr = strdup(YesNoCancelDialogButtonTemplate);
ReplaceIcons(instr);
 
mw = pspFontGetTextWidth(UiMetric.Font, message);
cw = pspFontGetTextWidth(UiMetric.Font, instr);
fh = pspFontGetLineHeight(UiMetric.Font);
th = pspFontGetTextHeight(UiMetric.Font, message);
 
w = ((mw > cw) ? mw : cw) + 50;
h = th + fh * 3;
sx = SCR_WIDTH / 2 - w / 2;
sy = SCR_HEIGHT / 2 - h / 2;
dx = sx + w;
dy = sy + h;
 
/* Intro animation */
if (UiMetric.Animate)
{
/* Get copy of screen */
screen = pspVideoGetVramBufferCopy();
 
for (i = 0; i < n; i++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
COLOR(RED_32(UiMetric.MenuOptionBoxBg),
GREEN_32(UiMetric.MenuOptionBoxBg),
BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
pspVideoBegin();
 
if (UiMetric.Animate)
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message,
UiMetric.TextColor);
pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr,
UiMetric.TextColor);
pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
SceCtrlData pad;
 
/* Loop until X or O is pressed */
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton
|| pad.Buttons & PSP_CTRL_SQUARE) break;
}
 
if (!ExitPSP && UiMetric.Animate)
{
/* Exit animation */
for (i = n - 1; i >= 0; i--)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
COLOR(RED_32(UiMetric.MenuOptionBoxBg),
GREEN_32(UiMetric.MenuOptionBoxBg),
BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
if (screen) pspImageDestroy(screen);
free(instr);
 
if (pad.Buttons & UiMetric.CancelButton) return PSP_UI_CANCEL;
else if (pad.Buttons & PSP_CTRL_SQUARE) return PSP_UI_NO;
else return PSP_UI_YES;
}
 
int pspUiConfirm(const char *message)
{
PspImage *screen = NULL;
int sx, sy, dx, dy, th, fh, mw, cw, w, h;
int i, n = UI_ANIM_FRAMES;
char *instr = strdup(ConfirmDialogButtonTemplate);
ReplaceIcons(instr);
 
mw = pspFontGetTextWidth(UiMetric.Font, message);
cw = pspFontGetTextWidth(UiMetric.Font, instr);
fh = pspFontGetLineHeight(UiMetric.Font);
th = pspFontGetTextHeight(UiMetric.Font, message);
 
w = ((mw > cw) ? mw : cw) + 50;
h = th + fh * 3;
sx = SCR_WIDTH / 2 - w / 2;
sy = SCR_HEIGHT / 2 - h / 2;
dx = sx + w;
dy = sy + h;
 
if (UiMetric.Animate)
{
/* Get copy of screen */
screen = pspVideoGetVramBufferCopy();
 
/* Intro animation */
for (i = 0; i < n; i++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
COLOR(RED_32(UiMetric.MenuOptionBoxBg),
GREEN_32(UiMetric.MenuOptionBoxBg),
BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
pspVideoBegin();
 
if (UiMetric.Animate)
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message,
UiMetric.TextColor);
pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr,
UiMetric.TextColor);
pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
SceCtrlData pad;
 
/* Loop until X or O is pressed */
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton)
break;
}
 
if (!ExitPSP && UiMetric.Animate)
{
/* Exit animation */
for (i = n - 1; i >= 0; i--)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
COLOR(RED_32(UiMetric.MenuOptionBoxBg),
GREEN_32(UiMetric.MenuOptionBoxBg),
BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
if (screen) pspImageDestroy(screen);
free(instr);
 
return pad.Buttons & UiMetric.OkButton;
}
 
void pspUiFlashMessage(const char *message)
{
PspImage *screen = NULL;
int sx, sy, dx, dy, fh, mw, mh, w, h;
int i, n = UI_ANIM_FRAMES;
 
mw = pspFontGetTextWidth(UiMetric.Font, message);
fh = pspFontGetLineHeight(UiMetric.Font);
mh = pspFontGetTextHeight(UiMetric.Font, message);
 
w = mw + 50;
h = mh + fh * 2;
sx = SCR_WIDTH / 2 - w / 2;
sy = SCR_HEIGHT / 2 - h / 2;
dx = sx + w;
dy = sy + h;
 
if (UiMetric.Animate)
{
/* Get copy of screen */
screen = pspVideoGetVramBufferCopy();
 
/* Intro animation */
for (i = 0; i < n; i++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*i));
pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2,
SCR_HEIGHT/2-(((dy-sy)/n)*i)/2,
SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2,
COLOR(RED_32(UiMetric.MenuOptionBoxBg),
GREEN_32(UiMetric.MenuOptionBoxBg),
BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
pspVideoBegin();
 
if (UiMetric.Animate)
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0,0,0,UI_ANIM_FOG_STEP*n));
pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg);
pspVideoPrintCenter(UiMetric.Font,
sx, sy + fh, dx, message, UiMetric.TextColor);
pspVideoGlowRect(sx, sy, dx - 1, dy - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
if (screen) pspImageDestroy(screen);
}
 
void pspUiOpenBrowser(PspUiFileBrowser *browser, const char *start_path)
{
pl_file *file;
pl_file_list list;
const pl_menu_item *sel, *last_sel;
pl_menu_item *item;
SceCtrlData pad;
char *instructions[BROWSER_TEMPLATE_COUNT];
int delay;
PspImage *screenshot = NULL;
int screenshot_width = 0;
int screenshot_height = 0;
 
/* Initialize instruction strings */
int i;
for (i = 0; i < BROWSER_TEMPLATE_COUNT; i++)
{
instructions[i] = strdup(BrowserTemplates[i]);
ReplaceIcons(instructions[i]);
}
 
if (!start_path)
start_path = pl_psp_get_app_directory();
 
pl_file_path cur_path;
if (!pl_file_is_directory(start_path))
pl_file_get_parent_directory(start_path, cur_path, sizeof(cur_path));
else
{
int copy_len = MIN(strlen(start_path), sizeof(cur_path) - 1);
strncpy(cur_path, start_path, copy_len);
cur_path[copy_len] = '\0';
}
 
const char *cur_file = pl_file_get_filename(start_path);
struct UiPos pos;
int lnmax, lnhalf;
int sby, sbh, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
int sx, sy, dx, dy;
int hasparent, is_dir;
 
sx = UiMetric.Left;
sy = UiMetric.Top + fh + UiMetric.TitlePadding;
dx = UiMetric.Right;
dy = UiMetric.Bottom;
w = dx - sx - UiMetric.ScrollbarWidth;
h = dy - sy;
 
pl_menu menu;
pl_menu_create(&menu, NULL);
 
memset(call_list, 0, sizeof(call_list));
 
int sel_top = 0, last_sel_top = 0, fast_scroll;
 
/* Begin browsing (outer) loop */
while (!ExitPSP)
{
delay = UiMetric.BrowserScreenshotDelay;
sel = last_sel = NULL;
pos.Top = NULL;
pl_menu_clear_items(&menu);
 
/* Load list of files for the selected path */
if (pl_file_get_file_list(&list, cur_path, browser->Filter) >= 0)
{
/* Check for a parent path, prepend .. if necessary */
if ((hasparent =! pl_file_is_root_directory(cur_path)))
{
item = pl_menu_append_item(&menu, 0, "..");
item->param = (void*)PL_FILE_DIRECTORY;
}
 
/* Add a menu item for each file */
for (file = list.files; file; file = file->next)
{
/* Skip files that begin with '.' */
if (file->name && file->name[0] == '.')
continue;
 
item = pl_menu_append_item(&menu, 0, file->name);
item->param = (void*)(int)file->attrs;
 
if (cur_file && strcmp(file->name, cur_file) == 0)
sel = item;
}
 
cur_file = NULL;
 
/* Destroy the file list */
pl_file_destroy_file_list(&list);
}
else
{
/* Check for a parent path, prepend .. if necessary */
if ((hasparent = !pl_file_is_root_directory(cur_path)))
{
item = pl_menu_append_item(&menu, 0, "..");
item->param = (void*)PL_FILE_DIRECTORY;
}
}
 
/* Initialize variables */
lnmax = (dy - sy) / fh;
lnhalf = lnmax >> 1;
int item_count = pl_menu_get_item_count(&menu);
sbh = (item_count > lnmax)
? (int)((float)h * ((float)lnmax / (float)item_count)) : 0;
 
pos.Index = pos.Offset = 0;
 
if (!sel)
{
/* Select the first file/dir in the directory */
if (menu.items && menu.items->next)
sel=menu.items->next;
else if (menu.items)
sel=menu.items;
}
 
/* Compute index and offset of selected file */
if (sel)
{
pos.Top = menu.items;
for (item = menu.items; item != sel; item = item->next)
{
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->next; }
else pos.Index++;
}
}
 
pspVideoWaitVSync();
 
/* Begin navigation (inner) loop */
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
fast_scroll = 0;
if (delay >= 0) delay--;
if ((delay == 0)
&& sel
&& !screenshot
&& !((unsigned int)sel->param & PL_FILE_DIRECTORY)
&& UiMetric.BrowserScreenshotPath)
{
pl_file_path screenshot_path;
sprintf(screenshot_path, "%s%s-00.png",
UiMetric.BrowserScreenshotPath, sel->caption);
screenshot = pspImageLoadPng(screenshot_path);
}
 
/* Check the directional buttons */
if (sel)
{
if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN) && sel->next)
{
if (pos.Index+1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->next; }
else pos.Index++;
sel=sel->next;
fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
}
else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP) && sel->prev)
{
if (pos.Index - 1 < 0) { pos.Offset--; pos.Top=pos.Top->prev; }
else pos.Index--;
sel = sel->prev;
fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
}
else if (pad.Buttons & PSP_CTRL_LEFT)
{
for (i=0; sel->prev && i < lnhalf; i++)
{
if (pos.Index-1 < 0) { pos.Offset--; pos.Top=pos.Top->prev; }
else pos.Index--;
sel=sel->prev;
}
}
else if (pad.Buttons & PSP_CTRL_RIGHT)
{
for (i=0; sel->next && i < lnhalf; i++)
{
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->next; }
else pos.Index++;
sel=sel->next;
}
}
 
/* File/dir selection */
if (pad.Buttons & UiMetric.OkButton)
{
if (((unsigned int)sel->param & PL_FILE_DIRECTORY))
{
enter_directory(cur_path, sel->caption);
break;
}
else
{
int exit = 1;
 
/* Selected a file */
if (browser->OnOk)
{
char *file = malloc((strlen(cur_path) + strlen(sel->caption) + 1) * sizeof(char));
sprintf(file, "%s%s", cur_path, sel->caption);
exit = browser->OnOk(browser, file);
free(file);
}
 
if (exit) goto exit_browser;
else continue;
}
}
}
 
if (pad.Buttons & PSP_CTRL_TRIANGLE)
{
if (!pl_file_is_root_directory(cur_path))
{
enter_directory(cur_path, "..");
break;
}
}
else if (pad.Buttons & UiMetric.CancelButton)
{
if (browser->OnCancel)
browser->OnCancel(browser, cur_path);
goto exit_browser;
}
else if ((pad.Buttons & CONTROL_BUTTON_MASK) && browser->OnButtonPress)
{
char *file = NULL;
int exit;
 
if (sel)
{
file = malloc((strlen(cur_path) + strlen(sel->caption) + 1) * sizeof(char));
sprintf(file, "%s%s", cur_path, sel->caption);
}
 
exit = browser->OnButtonPress(browser,
file, pad.Buttons & CONTROL_BUTTON_MASK);
 
if (file) free(file);
if (exit) goto exit_browser;
}
 
is_dir = (unsigned int)sel->param & PL_FILE_DIRECTORY;
 
sceGuStart(GU_CALL, call_list);
 
/* Draw current path */
pspVideoPrint(UiMetric.Font, sx, UiMetric.Top, cur_path,
UiMetric.TitleColor);
pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w,
UiMetric.Top + fh - 1, UiMetric.TitleColor);
 
const char *instruction;
if (hasparent)
instruction = instructions[(is_dir)
? BrowserTemplateEnter : BrowserTemplateOpen];
else
instruction = instructions[(is_dir)
? BrowserTemplateEnterTop : BrowserTemplateOpenTop];
 
pspVideoPrintCenter(UiMetric.Font,
sx, SCR_HEIGHT - fh, dx, instruction, UiMetric.StatusBarColor);
 
/* Draw scrollbar */
if (sbh > 0)
{
sby = sy + (int)((float)(h - sbh)
* ((float)(pos.Offset + pos.Index) / (float)item_count));
pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sy, dx, dy,
UiMetric.ScrollbarBgColor);
pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sby, dx, sby + sbh,
UiMetric.ScrollbarColor);
}
 
/* Render the files */
for (item = (pl_menu_item*)pos.Top, i = 0, j = sy;
item && i < lnmax; item = item->next, j += fh, i++)
{
if (item == sel) sel_top = j;
 
pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->caption, w - 10,
"...", (item == sel) ? UiMetric.SelectedColor
: ((unsigned int)item->param & PL_FILE_DIRECTORY)
? UiMetric.BrowserDirectoryColor : UiMetric.BrowserFileColor);
}
 
/* Render status information */
RenderStatus();
 
/* Perform any custom drawing */
if (browser->OnRender)
browser->OnRender(browser, "not implemented");
 
sceGuFinish();
 
if (screenshot)
{
screenshot_width = screenshot->Viewport.Width;
screenshot_height = screenshot->Viewport.Height;
}
 
if (sel != last_sel && !fast_scroll && sel && last_sel
&& UiMetric.Animate)
{
/* Move animation */
int f, n = 4;
for (f = 1; f <= n; f++)
{
pspVideoBegin();
 
/* Clear screen */
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
 
/* Render screenshot */
if (screenshot)
pspVideoPutImage(screenshot,
UiMetric.Right - screenshot_width,
((UiMetric.Bottom - UiMetric.Top) / 2 -
screenshot_height / 2) + UiMetric.Top,
screenshot_width,
screenshot_height);
 
/* Selection box */
int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
pspVideoFillRect(sx, box_top, sx+w, box_top+fh,
UiMetric.SelectedBgColor);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
pspVideoBegin();
 
/* Clear screen */
if (UiMetric.Background)
pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
else pspVideoClearScreen();
 
/* Render screenshot */
if (screenshot)
pspVideoPutImage(screenshot,
UiMetric.Right - screenshot_width,
((UiMetric.Bottom - UiMetric.Top) / 2 -
screenshot_height / 2) + UiMetric.Top,
screenshot_width,
screenshot_height);
 
/* Render selection box */
if (sel) pspVideoFillRect(sx, sel_top, sx+w, sel_top+fh,
UiMetric.SelectedBgColor);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
if (last_sel != sel)
{
if (screenshot != NULL)
{
pspImageDestroy(screenshot);
screenshot = NULL;
}
 
delay = UiMetric.BrowserScreenshotDelay;
}
 
last_sel = sel;
last_sel_top = sel_top;
}
}
 
exit_browser:
 
if (screenshot != NULL)
pspImageDestroy(screenshot);
 
/* Free instruction strings */
for (i = 0; i < BROWSER_TEMPLATE_COUNT; i++)
free(instructions[i]);
 
pl_menu_destroy(&menu);
}
 
void pspUiOpenGallery(PspUiGallery *gallery, const char *title)
{
pl_menu *menu = &(gallery->Menu);
const pl_menu_item *top, *item;
SceCtrlData pad;
pl_menu_item *sel = menu->selected;
 
int sx, sy, dx, dy,
orig_w = 272, orig_h = 228, // defaults
fh, c, i, j,
sbh, sby,
w, h,
icon_w, icon_h,
grid_w, grid_h,
icon_idx, icon_off,
rows, vis_v, vis_s,
icons;
const pl_menu_item *last_sel = NULL;
 
/* Find first icon and save its width/height */
for (item = menu->items; item; item = item->next)
{
if (item->param)
{
orig_w = ((PspImage*)item->param)->Viewport.Width;
orig_h = ((PspImage*)item->param)->Height;
break;
}
}
 
fh = pspFontGetLineHeight(UiMetric.Font);
sx = UiMetric.Left;
sy = UiMetric.Top + ((title) ? fh + UiMetric.TitlePadding : 0);
dx = UiMetric.Right;
dy = UiMetric.Bottom;
w = (dx - sx) - UiMetric.ScrollbarWidth; // visible width
h = dy - sy; // visible height
icon_w = (w - UiMetric.GalleryIconMarginWidth
* (UiMetric.GalleryIconsPerRow - 1)) / UiMetric.GalleryIconsPerRow; // icon width
icon_h = (int)((float)icon_w
/ ((float)orig_w / (float)orig_h)); // icon height
grid_w = icon_w + UiMetric.GalleryIconMarginWidth; // width of the grid
grid_h = icon_h + (fh * 2); // half-space for margin + 1 line of text
icons = pl_menu_get_item_count(menu); // number of icons total
rows = ceil((float)icons / (float)UiMetric.GalleryIconsPerRow); // number of rows total
vis_v = h / grid_h; // number of rows visible at any time
vis_s = UiMetric.GalleryIconsPerRow * vis_v; // max. number of icons visible on screen at any time
int max_w = ((float)icon_w * 1.5); /* Maximized width */
int max_h = ((float)icon_h * 1.5); /* Maximized height */
 
icon_idx = 0;
icon_off = 0;
top = menu->items;
 
if (!sel)
{
/* Select the first icon */
sel = menu->items;
}
else
{
/* Find the selected icon */
for (item = menu->items; item; item = item->next)
{
if (item == sel)
break;
 
if (++icon_idx >= vis_s)
{
icon_idx=0;
icon_off += vis_s;
top = item;
}
}
if (item != sel)
{
/* Icon not found; reset to first icon */
sel = menu->items;
top = menu->items;
icon_idx = 0;
icon_off = 0;
}
}
 
/* Compute height of scrollbar */
sbh = ((float)vis_v / (float)(rows + (rows % vis_v))) * (float)h;
 
/* Compute update frequency */
u32 ticks_per_sec, ticks_per_upd;
u64 current_tick, last_tick;
 
ticks_per_sec = sceRtcGetTickResolution();
sceRtcGetCurrentTick(&last_tick);
ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
 
memset(call_list, 0, sizeof(call_list));
int sel_left = 0 /*, max_left = 0 */;
int sel_top = 0 /*, max_top = 0 */;
 
pspVideoWaitVSync();
 
/* Begin navigation loop */
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
/* Check the directional buttons */
if (sel)
{
if (pad.Buttons & PSP_CTRL_RIGHT && sel->next)
{
sel = sel->next;
if (++icon_idx >= vis_s)
{
icon_idx = 0;
icon_off += vis_s;
top = sel;
}
}
else if (pad.Buttons & PSP_CTRL_LEFT && sel->prev)
{
sel = sel->prev;
if (--icon_idx < 0)
{
icon_idx = vis_s-1;
icon_off -= vis_s;
for (i = 0; i < vis_s && top; i++) top = top->prev;
}
}
else if (pad.Buttons & PSP_CTRL_DOWN)
{
for (i = 0; sel->next && i < UiMetric.GalleryIconsPerRow; i++)
{
sel = sel->next;
if (++icon_idx >= vis_s)
{
icon_idx = 0;
icon_off += vis_s;
top = sel;
}
}
}
else if (pad.Buttons & PSP_CTRL_UP)
{
for (i = 0; sel->prev && i < UiMetric.GalleryIconsPerRow; i++)
{
sel = sel->prev;
if (--icon_idx < 0)
{
icon_idx = vis_s-1;
icon_off -= vis_s;
for (j = 0; j < vis_s && top; j++) top = top->prev;
}
}
}
 
if (pad.Buttons & UiMetric.OkButton)
{
pad.Buttons &= ~UiMetric.OkButton;
if (!gallery->OnOk || gallery->OnOk(gallery, sel))
break;
}
}
 
if (pad.Buttons & UiMetric.CancelButton)
{
pad.Buttons &= ~UiMetric.CancelButton;
if (gallery->OnCancel)
gallery->OnCancel(gallery, sel);
break;
}
 
if ((pad.Buttons & CONTROL_BUTTON_MASK) && gallery->OnButtonPress)
if (gallery->OnButtonPress(gallery, sel, pad.Buttons & CONTROL_BUTTON_MASK))
break;
 
if (last_sel != sel && last_sel && sel && sel->param && UiMetric.Animate)
{
/* "Implode" animation */
int f = 1, n = 2;
// for (f = n - 1; f > 0; f--)
// {
pspVideoBegin();
 
/* Clear screen */
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
/* Render the menu items */
for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next)
if (item->param && item != last_sel)
{
pspVideoBegin();
pspVideoPutImage((PspImage*)item->param, j, i, icon_w, icon_h);
pspVideoEnd();
}
 
pspVideoBegin();
 
pspVideoPutImage((PspImage*)last_sel->param,
sel_left-(icon_w+((max_w-icon_w)/n)*f)/2,
sel_top-(icon_h+((max_h-icon_h)/n)*f)/2,
icon_w+((max_w-icon_w)/n)*f,
icon_h+((max_h-icon_h)/n)*f);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
// }
}
 
sceGuStart(GU_CALL, call_list);
 
/* Draw title */
if (title)
{
pspVideoPrint(UiMetric.Font, UiMetric.Left, UiMetric.Top,
title, UiMetric.TitleColor);
pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w,
UiMetric.Top + fh - 1, UiMetric.TitleColor);
}
 
/* Draw scrollbar */
if (sbh < h)
{
sby = sy + (((float)icon_off / (float)UiMetric.GalleryIconsPerRow)
/ (float)(rows + (rows % vis_v))) * (float)h;
pspVideoFillRect(dx - UiMetric.ScrollbarWidth,
sy, dx, dy, UiMetric.ScrollbarBgColor);
pspVideoFillRect(dx - UiMetric.ScrollbarWidth,
sby, dx, sby+sbh, UiMetric.ScrollbarColor);
}
 
/* Draw instructions */
if (sel && sel->help_text)
{
static char help_copy[PL_FILE_MAX_PATH_LEN];
strncpy(help_copy, sel->help_text, PL_FILE_MAX_PATH_LEN - 1);
help_copy[PL_FILE_MAX_PATH_LEN - 1] = '\0';
ReplaceIcons(help_copy);
 
pspVideoPrintCenter(UiMetric.Font,
0, SCR_HEIGHT - fh, SCR_WIDTH, help_copy, UiMetric.StatusBarColor);
}
 
/* Render non-image components of each item */
for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
{
for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next)
{
if (item != sel)
{
pspVideoShadowRect(j - 1, i - 1, j + icon_w, i + icon_h, PSP_COLOR_BLACK, 3);
pspVideoDrawRect(j - 1, i - 1, j + icon_w, i + icon_h, UiMetric.TextColor);
 
if (item->caption)
{
int cap_pos = j + icon_w / 2
- pspFontGetTextWidth(UiMetric.Font, item->caption) / 2;
pspVideoPrint(UiMetric.Font, cap_pos,
i + icon_h + (fh / 2), item->caption, UiMetric.TextColor);
}
}
else
{
sel_left = j + icon_w / 2;
sel_top = i + icon_h / 2;
 
sel_left = (sel_left-max_w/2 < sx) ? sx+max_w/2 : sel_left;
sel_top = (sel_top-max_h/2 < UiMetric.Top)
? UiMetric.Top+max_h/2 : sel_top;
sel_left = (sel_left+max_w/2 > dx) ? dx-max_w/2 : sel_left;
sel_top = (sel_top+max_h/2 > dy) ? dy-max_h/2 : sel_top;
}
}
}
 
/* Render status information */
RenderStatus();
 
/* Perform any custom drawing */
if (gallery->OnRender)
gallery->OnRender(gallery, sel);
 
sceGuFinish();
 
if (last_sel != sel && last_sel && sel && sel->param && UiMetric.Animate)
{
/* Popup animation */
int f = 1, n = 2;
// for (f = 1; f < n; f++)
// {
pspVideoBegin();
 
/* Clear screen */
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
/* Render the menu items */
for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next)
if (item->param && item != sel)
{
pspVideoBegin();
pspVideoPutImage((PspImage*)item->param, j, i, icon_w, icon_h);
pspVideoEnd();
}
 
pspVideoBegin();
 
pspVideoPutImage((PspImage*)sel->param,
sel_left-(icon_w+((max_w-icon_w)/n)*f)/2,
sel_top-(icon_h+((max_h-icon_h)/n)*f)/2,
icon_w+((max_w-icon_w)/n)*f,
icon_h+((max_h-icon_h)/n)*f);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
// }
}
 
pspVideoBegin();
 
/* Clear screen */
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
/* Render the menu items */
for (i = sy, item = top; item && i + grid_h < dy; i += grid_h)
for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next)
if (item->param && item != sel)
{
pspVideoBegin();
pspVideoPutImage((PspImage*)item->param, j, i, icon_w, icon_h);
pspVideoEnd();
}
 
pspVideoBegin();
 
if (sel && sel->param)
{
pspVideoPutImage((PspImage*)sel->param, sel_left-max_w/2, sel_top-max_h/2,
max_w, max_h);
pspVideoGlowRect(sel_left-max_w/2, sel_top-max_h/2,
sel_left+max_w/2 - 1, sel_top+max_h/2 - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
}
 
if (sel && sel->caption)
{
int cap_left = sel_left
- pspFontGetTextWidth(UiMetric.Font, sel->caption) / 2;
pspVideoPrint(UiMetric.Font, cap_left,
sel_top + max_h/2 - (fh + (fh - UiMetric.Font->Ascent)), sel->caption,
UiMetric.TextColor);
}
 
pspVideoEnd();
 
last_sel = sel;
 
/* Wait if needed */
do { sceRtcGetCurrentTick(&current_tick); }
while (current_tick - last_tick < ticks_per_upd);
last_tick = current_tick;
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
 
menu->selected = sel;
}
 
void pspUiOpenMenu(PspUiMenu *uimenu, const char *title)
{
struct UiPos pos;
pl_menu *menu = &(uimenu->Menu);
const pl_menu_item *item;
SceCtrlData pad;
const pl_menu_option *temp_option;
int lnmax;
int sby, sbh, i, j, k, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
int sx, sy, dx, dy, sel_top = 0, last_sel_top = 0;
int max_item_w = 0, item_w;
int option_mode, max_option_w = 0;
int arrow_w = pspFontGetTextWidth(UiMetric.Font, "\272");
int anim_frame = 0, anim_incr = 1;
pl_menu_item *sel = menu->selected, *last_sel = NULL;
 
sx = UiMetric.Left;
sy = UiMetric.Top + ((title) ? (fh + UiMetric.TitlePadding) : 0);
dx = UiMetric.Right;
dy = UiMetric.Bottom;
w = dx - sx - UiMetric.ScrollbarWidth;
h = dy - sy;
 
memset(call_list, 0, sizeof(call_list));
 
/* Determine width of the longest caption */
for (item = menu->items; item; item = item->next)
{
if (item->caption)
{
item_w = pspFontGetTextWidth(UiMetric.Font, item->caption);
if (item_w > max_item_w)
max_item_w = item_w;
}
}
 
/* Initialize variables */
lnmax = (dy - sy) / fh;
int item_count = pl_menu_get_item_count(menu);
sbh = (item_count > lnmax)
? (int)((float)h * ((float)lnmax / (float)item_count)) : 0;
 
pos.Index = 0;
pos.Offset = 0;
pos.Top = NULL;
option_mode = 0;
temp_option = NULL;
 
int cur_x=0, min_x=0, max_x=0;
int cur_y=0, min_y=0, max_y=0;
 
/* Find first selectable item */
if (!sel)
{
for (sel = menu->items; sel; sel = sel->next)
if (sel->caption && sel->caption[0] != '\t')
break;
}
 
/* Compute index and offset of selected file */
pos.Top = menu->items;
for (item = menu->items; item != sel; item = item->next)
{
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; }
else pos.Index++;
}
 
pspVideoWaitVSync();
pl_menu_item *last;
struct UiPos last_valid;
 
/* Compute update frequency */
u32 ticks_per_sec, ticks_per_upd;
u64 current_tick, last_tick;
 
ticks_per_sec = sceRtcGetTickResolution();
sceRtcGetCurrentTick(&last_tick);
ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
 
int fast_scroll;
 
/* Begin navigation loop */
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
fast_scroll = 0;
anim_frame += (UiMetric.Animate) ? anim_incr : 0;
if (anim_frame > 2 || anim_frame < 0)
anim_incr *= -1;
 
/* Check the directional buttons */
if (sel)
{
if (pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN)
{
fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
 
if (option_mode)
{
if (temp_option->next)
temp_option = temp_option->next;
}
else
{
if (sel->next)
{
last = sel;
last_valid = pos;
 
for (;;)
{
if (pos.Index + 1 >= lnmax)
{
pos.Offset++;
pos.Top = pos.Top->next;
}
else pos.Index++;
 
sel = sel->next;
 
if (!sel)
{
sel = last;
pos = last_valid;
break;
}
 
if (sel->caption && sel->caption[0] != '\t')
break;
}
}
}
}
else if (pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP)
{
fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
 
if (option_mode)
{
if (temp_option->prev)
temp_option = temp_option->prev;
}
else
{
if (sel->prev)
{
last = sel;
last_valid = pos;
 
for (;;)
{
if (pos.Index - 1 < 0)
{
pos.Offset--;
pos.Top = pos.Top->prev;
}
else pos.Index--;
 
sel = sel->prev;
 
if (!sel)
{
sel = last;
 
pos.Index = 0;
pos.Offset = 0;
pos.Top = menu->items;
 
for (item = menu->items; item != sel; item = item->next)
{
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; }
else pos.Index++;
}
 
break;
}
 
if (sel->caption && sel->caption[0] != '\t')
break;
}
}
}
}
 
/* Recompute box bounds if scrolling in option mode */
if (option_mode && (pad.Buttons &
(PSP_CTRL_UP|PSP_CTRL_ANALUP|PSP_CTRL_DOWN|PSP_CTRL_ANALDOWN)))
{
cur_x = sx + max_item_w + UiMetric.MenuItemMargin + 10;
min_y = sy + pos.Index * fh;
cur_y = min_y + fh / 2;
max_y = sy + (pos.Index + 1) * fh;
min_x = cur_x - UiMetric.MenuItemMargin;
max_x = cur_x + max_option_w + UiMetric.MenuItemMargin;
cur_x += pspFontGetTextWidth(UiMetric.Font, " >");
if (sel->selected && sel->selected->text)
cur_x += pspFontGetTextWidth(UiMetric.Font, sel->selected->text);
 
const pl_menu_option *option;
for (option = temp_option; option && min_y >= sy; option = option->prev, min_y -= fh);
for (option = temp_option->next; option && max_y < dy; option = option->next, max_y += fh);
max_y += fh;
}
 
if (option_mode)
{
if (pad.Buttons & PSP_CTRL_RIGHT || pad.Buttons & UiMetric.OkButton)
{
option_mode = 0;
 
/* If the callback function refuses the change, restore selection */
if (!uimenu->OnItemChanged || uimenu->OnItemChanged(uimenu, sel, temp_option))
sel->selected = (pl_menu_option*)temp_option;
}
else if (pad.Buttons & PSP_CTRL_LEFT || pad.Buttons & UiMetric.CancelButton)
{
option_mode = 0;
 
if (pad.Buttons & UiMetric.CancelButton)
pad.Buttons &= ~UiMetric.CancelButton;
}
 
if (!option_mode)
{
if (UiMetric.Animate)
{
/* Deflation animation */
for (i = UI_ANIM_FRAMES - 1; i >= 0; i--)
{
pspVideoBegin();
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
pspVideoCallList(call_list);
 
/* Perform any custom drawing */
if (uimenu->OnRender)
uimenu->OnRender(uimenu, sel);
 
/* Clear screen */
pspVideoFillRect(cur_x - ((cur_x - min_x) / UI_ANIM_FRAMES) * i,
cur_y - ((cur_y - min_y) / UI_ANIM_FRAMES) * i,
cur_x + ((max_x - cur_x) / UI_ANIM_FRAMES) * i,
cur_y + ((max_y - cur_y) / UI_ANIM_FRAMES) * i,
UiMetric.MenuOptionBoxBg);
 
/* Selected option for the item */
if (sel->selected && sel->selected->text)
pspVideoPrint(UiMetric.Font,
sx + max_item_w + UiMetric.MenuItemMargin + 10,
sy + pos.Index * fh, sel->selected->text, UiMetric.SelectedColor);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
}
}
else
{
if ((pad.Buttons & PSP_CTRL_RIGHT)
&& sel->options && sel->options->next)
{
option_mode = 1;
max_option_w = 0;
int width;
const pl_menu_option *option;
 
/* Find the longest option caption */
for (option = sel->options; option; option = option->next)
if (option->text && (width = pspFontGetTextWidth(UiMetric.Font, option->text)) > max_option_w)
max_option_w = width;
 
temp_option = (sel->selected) ? sel->selected : sel->options;
 
/* Determine bounds */
cur_x = sx + max_item_w + UiMetric.MenuItemMargin + 10;
min_y = sy + pos.Index * fh;
cur_y = min_y + fh / 2;
max_y = sy + (pos.Index + 1) * fh;
min_x = cur_x - UiMetric.MenuItemMargin;
max_x = cur_x + max_option_w + UiMetric.MenuItemMargin;
cur_x += pspFontGetTextWidth(UiMetric.Font, " >");
if (sel->selected && sel->selected->text)
cur_x += pspFontGetTextWidth(UiMetric.Font, sel->selected->text);
 
for (option = temp_option; option && min_y >= sy; option = option->prev, min_y -= fh);
for (option = temp_option->next; option && max_y < dy; option = option->next, max_y += fh);
max_y += fh;
 
if (UiMetric.Animate)
{
/* Expansion animation */
for (i = 0; i <= UI_ANIM_FRAMES; i++)
{
pspVideoBegin();
 
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width,
UiMetric.Background->Height);
 
pspVideoCallList(call_list);
 
/* Perform any custom drawing */
if (uimenu->OnRender)
uimenu->OnRender(uimenu, sel);
 
pspVideoFillRect(cur_x - ((cur_x - min_x) / UI_ANIM_FRAMES) * i,
cur_y - ((cur_y - min_y) / UI_ANIM_FRAMES) * i,
cur_x + ((max_x - cur_x) / UI_ANIM_FRAMES) * i,
cur_y + ((max_y - cur_y) / UI_ANIM_FRAMES) * i,
UiMetric.MenuOptionBoxBg);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
}
else if (pad.Buttons & UiMetric.OkButton)
{
if (!uimenu->OnOk || uimenu->OnOk(uimenu, sel))
break;
}
}
}
 
if (!option_mode)
{
if (pad.Buttons & UiMetric.CancelButton)
{
if (uimenu->OnCancel)
uimenu->OnCancel(uimenu, sel);
break;
}
 
if ((pad.Buttons & CONTROL_BUTTON_MASK) && uimenu->OnButtonPress)
{
if (uimenu->OnButtonPress(uimenu, sel, pad.Buttons & CONTROL_BUTTON_MASK))
break;
}
}
 
/* Render to a call list */
sceGuStart(GU_CALL, call_list);
 
/* Draw instructions */
if (sel)
{
const char *dirs = NULL;
 
if (!option_mode && sel->help_text)
{
static char help_copy[PL_FILE_MAX_PATH_LEN];
strncpy(help_copy, sel->help_text, PL_FILE_MAX_PATH_LEN - 1);
help_copy[PL_FILE_MAX_PATH_LEN - 1] = '\0';
ReplaceIcons(help_copy);
 
dirs = help_copy;
}
else if (option_mode)
{
static char help_copy[PL_FILE_MAX_PATH_LEN];
strncpy(help_copy, OptionModeTemplate, PL_FILE_MAX_PATH_LEN - 1);
help_copy[PL_FILE_MAX_PATH_LEN - 1] = '\0';
ReplaceIcons(help_copy);
 
dirs = help_copy;
}
 
if (dirs)
pspVideoPrintCenter(UiMetric.Font,
0, SCR_HEIGHT - fh, SCR_WIDTH, dirs, UiMetric.StatusBarColor);
}
 
/* Draw title */
if (title)
{
pspVideoPrint(UiMetric.Font, UiMetric.Left, UiMetric.Top,
title, UiMetric.TitleColor);
pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w,
UiMetric.Top + fh - 1, UiMetric.TitleColor);
}
 
/* Render the menu items */
for (item = pos.Top, i = 0, j = sy; item && i < lnmax; item = item->next, j += fh, i++)
{
if (item->caption)
{
/* Section header */
if (item->caption[0] == '\t')
{
// if (i != 0) j += fh / 2;
pspVideoPrint(UiMetric.Font, sx, j, item->caption + 1, UiMetric.TitleColor);
pspVideoDrawLine(sx, j + fh - 1, sx + w, j + fh - 1, UiMetric.TitleColor);
continue;
}
 
if (item == sel) sel_top = j;
 
/* Item caption */
pspVideoPrint(UiMetric.Font, sx + 10, j, item->caption,
(item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
 
if (!option_mode || item != sel)
{
/* Selected option for the item */
if (item->selected)
{
k = sx + max_item_w + UiMetric.MenuItemMargin + 10;
k += pspVideoPrint(UiMetric.Font, k, j, item->selected->text,
(item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
 
if (!option_mode && item == sel)
if (sel->options && sel->options->next)
pspVideoPrint(UiMetric.Font, k + anim_frame, j, " >", UiMetric.MenuDecorColor);
}
}
}
}
 
/* Render status information */
RenderStatus();
 
/* Draw scrollbar */
if (sbh > 0)
{
sby = sy + (int)((float)(h - sbh) * ((float)(pos.Offset + pos.Index) / (float)item_count));
pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sy, dx, dy, UiMetric.ScrollbarBgColor);
pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sby, dx, sby + sbh, UiMetric.ScrollbarColor);
}
 
/* End writing to call list */
sceGuFinish();
 
if (!option_mode && !fast_scroll && sel && last_sel
&& UiMetric.Animate && last_sel != sel)
{
/* Move animation */
int f, n = 4;
for (f = 1; f <= n; f++)
{
pspVideoBegin();
 
/* Clear screen */
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
 
int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
pspVideoFillRect(sx, box_top, sx+w, box_top+fh,
UiMetric.SelectedBgColor);
 
sceGuCallList(call_list);
 
/* Perform any custom drawing */
if (uimenu->OnRender)
uimenu->OnRender(uimenu, sel);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
/* Begin direct rendering */
pspVideoBegin();
 
/* Clear screen */
if (!UiMetric.Background) pspVideoClearScreen();
else pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
 
/* Draw the highlight for selected item */
if (!option_mode)
pspVideoFillRect(sx, sel_top, sx+w, sel_top+fh,
UiMetric.SelectedBgColor);
 
pspVideoCallList(call_list);
 
/* Perform any custom drawing */
if (uimenu->OnRender)
uimenu->OnRender(uimenu, sel);
 
/* Render menu options */
if (option_mode)
{
k = sx + max_item_w + UiMetric.MenuItemMargin + 10;
int arrow_x = min_x + (UiMetric.MenuItemMargin / 2 - arrow_w / 2);
const pl_menu_option *option;
 
/* Background */
pspVideoFillRect(min_x, min_y, max_x, max_y, UiMetric.MenuOptionBoxBg);
pspVideoFillRect(min_x, sy + pos.Index * fh, max_x,
sy + (pos.Index + 1) * fh, UiMetric.MenuSelOptionBg);
pspVideoGlowRect(min_x, min_y, max_x - 1, max_y - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
 
/* Render selected item + previous items */
i = sy + pos.Index * fh;
for (option = temp_option; option && i >= sy; option = option->prev, i -= fh)
pspVideoPrint(UiMetric.Font, k, i, option->text, (option == temp_option)
? UiMetric.SelectedColor : UiMetric.MenuOptionBoxColor);
 
/* Up arrow */
if (option) pspVideoPrint(UiMetric.Font, arrow_x,
i + fh + anim_frame, PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor);
 
/* Render following items */
i = sy + (pos.Index + 1) * fh;
for (option = temp_option->next; option && i < dy; option = option->next, i += fh)
pspVideoPrint(UiMetric.Font, k, i, option->text,
UiMetric.MenuOptionBoxColor);
 
/* Down arrow */
if (option) pspVideoPrint(UiMetric.Font, arrow_x, i - fh - anim_frame,
PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor);
}
 
pspVideoEnd();
 
/* Wait if needed */
do { sceRtcGetCurrentTick(&current_tick); }
while (current_tick - last_tick < ticks_per_upd);
last_tick = current_tick;
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
last_sel = sel;
last_sel_top = sel_top;
}
 
menu->selected = sel;
}
 
void pspUiSplashScreen(PspUiSplash *splash)
{
SceCtrlData pad;
int fh = pspFontGetLineHeight(UiMetric.Font);
 
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
if (pad.Buttons & UiMetric.CancelButton)
{
if (splash->OnCancel) splash->OnCancel(splash, NULL);
break;
}
 
if ((pad.Buttons & CONTROL_BUTTON_MASK) && splash->OnButtonPress)
{
if (splash->OnButtonPress(splash, pad.Buttons & CONTROL_BUTTON_MASK))
break;
}
 
pspVideoBegin();
 
/* Clear screen */
if (UiMetric.Background)
pspVideoPutImage(UiMetric.Background, 0, 0,
UiMetric.Background->Viewport.Width, UiMetric.Background->Height);
else
pspVideoClearScreen();
 
/* Draw instructions */
const char *dirs = (splash->OnGetStatusBarText)
? splash->OnGetStatusBarText(splash)
: SplashStatusBarTemplate;
pspVideoPrintCenter(UiMetric.Font, UiMetric.Left,
SCR_HEIGHT - fh, UiMetric.Right, dirs, UiMetric.StatusBarColor);
 
/* Render status information */
RenderStatus();
 
/* Perform any custom drawing */
if (splash->OnRender)
splash->OnRender(splash, NULL);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
const pl_menu_item* pspUiSelect(const char *title, const pl_menu *menu)
{
const pl_menu_item *sel, *item, *last_sel = NULL;
struct UiPos pos;
int lnmax, lnhalf;
int i, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
int sx, sy, dx, dy;
int anim_frame = 0, anim_incr = 1;
int arrow_w = pspFontGetTextWidth(UiMetric.Font, PSP_CHAR_DOWN_ARROW);
int widest = 100;
int sel_top = 0, last_sel_top = 0;
SceCtrlData pad;
 
char *help_text = strdup(SelectorTemplate);
ReplaceIcons(help_text);
 
memset(call_list, 0, sizeof(call_list));
 
/* Determine width of the longest caption */
for (item = menu->items; item; item = item->next)
{
if (item->caption)
{
int item_w = pspFontGetTextWidth(UiMetric.Font, item->caption);
if (item_w > widest)
widest = item_w;
}
}
 
widest += UiMetric.MenuItemMargin * 2;
 
sx = SCR_WIDTH - widest;
sy = UiMetric.Top;
dx = SCR_WIDTH;
dy = UiMetric.Bottom;
w = dx - sx;
h = dy - sy;
 
u32 ticks_per_sec, ticks_per_upd;
u64 current_tick, last_tick;
 
/* Initialize variables */
lnmax = (dy - sy) / fh;
lnhalf = lnmax >> 1;
 
sel = menu->items;
pos.Top = menu->items;
pos.Index = pos.Offset = 0;
 
pspVideoWaitVSync();
 
/* Compute update frequency */
ticks_per_sec = sceRtcGetTickResolution();
sceRtcGetCurrentTick(&last_tick);
ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
 
/* Get copy of screen */
PspImage *screen = pspVideoGetVramBufferCopy();
 
if (UiMetric.Animate)
{
/* Intro animation */
for (i = 0; i < UI_ANIM_FRAMES; i++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw right frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
int fast_scroll;
 
/* Begin navigation loop */
while (!ExitPSP)
{
if (!pspCtrlPollControls(&pad))
continue;
 
fast_scroll = 0;
 
/* Incr/decr animation frame */
anim_frame += (UiMetric.Animate) ? anim_incr : 0;
if (anim_frame > 2 || anim_frame < 0)
anim_incr *= -1;
 
/* Check the directional buttons */
if (sel)
{
if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN)
&& sel->next)
{
fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; }
else pos.Index++;
sel = sel->next;
}
else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP)
&& sel->prev)
{
fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; }
else pos.Index--;
sel = sel->prev;
}
else if (pad.Buttons & PSP_CTRL_LEFT)
{
for (i = 0; sel->prev && i < lnhalf; i++)
{
if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; }
else pos.Index--;
sel = sel->prev;
}
}
else if (pad.Buttons & PSP_CTRL_RIGHT)
{
for (i = 0; sel->next && i < lnhalf; i++)
{
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; }
else pos.Index++;
sel=sel->next;
}
}
 
if (pad.Buttons & UiMetric.OkButton) break;
}
 
if (pad.Buttons & UiMetric.CancelButton) { sel = NULL; break; }
 
/* Render to a call list */
sceGuStart(GU_CALL, call_list);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0, 0, 0, UI_ANIM_FOG_STEP * UI_ANIM_FRAMES));
pspVideoGlowRect(sx, 0, dx - 1, SCR_HEIGHT - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
 
/* Title */
if (title)
pspVideoPrintCenter(UiMetric.Font, sx, 0, dx,
title, UiMetric.TitleColor);
 
/* Render the items */
for (item = (pl_menu_item*)pos.Top, i = 0, j = sy;
item && i < lnmax; item = item->next, j += fh, i++)
{
if (item == sel) sel_top = j;
pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->caption, w - 10,
"...", (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
}
 
/* Up arrow */
if (pos.Top && pos.Top->prev) pspVideoPrint(UiMetric.Font,
SCR_WIDTH - arrow_w * 2, sy + anim_frame,
PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor);
 
/* Down arrow */
if (item) pspVideoPrint(UiMetric.Font, SCR_WIDTH - arrow_w * 2,
dy - fh - anim_frame, PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor);
 
/* Shortcuts */
pspVideoPrintCenter(UiMetric.Font, sx, SCR_HEIGHT - fh, dx,
help_text, UiMetric.StatusBarColor);
 
sceGuFinish();
 
if (sel != last_sel && !fast_scroll && sel && last_sel
&& UiMetric.Animate)
{
/* Move animation */
int f, n = 4;
for (f = 1; f <= n; f++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
/* Selection box */
int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
pspVideoFillRect(sx, box_top, sx + w, box_top + fh,
UiMetric.SelectedBgColor);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
if (sel) pspVideoFillRect(sx, sel_top, sx + w, sel_top + fh,
UiMetric.SelectedBgColor);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
/* Wait if needed */
do { sceRtcGetCurrentTick(&current_tick); }
while (current_tick - last_tick < ticks_per_upd);
last_tick = current_tick;
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
last_sel = sel;
last_sel_top = sel_top;
}
 
if (UiMetric.Animate)
{
/* Exit animation */
for (i = UI_ANIM_FRAMES - 1; i >= 0; i--)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw right frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
free(help_text);
pspImageDestroy(screen);
 
return sel;
}
 
static void adhocMatchingCallback(int unk1,
int event,
unsigned char *mac2,
int opt_len,
void *opt_data)
{
_adhoc_match_event.NewEvent = 1;
_adhoc_match_event.EventID = event;
memcpy(_adhoc_match_event.EventMAC, mac2,
sizeof(unsigned char) * 6);
strncpy(_adhoc_match_event.OptData, opt_data, sizeof(char) * opt_len);
_adhoc_match_event.OptData[opt_len] = '\0';
}
 
int pspUiAdhocHost(const char *name, PspMAC mac)
{
/* Check the wlan switch */
if (!pspAdhocIsWLANEnabled())
{
pspUiAlert("Error: WLAN switch is turned off");
return 0;
}
 
pspUiFlashMessage(ADHOC_INITIALIZING);
_adhoc_match_event.NewEvent = 0;
 
/* Initialize ad-hoc networking */
if (!pspAdhocInit("ULUS99999", adhocMatchingCallback))
{
pspUiAlert("Ad-hoc networking initialization failed");
return 0;
}
 
/* Wait for someone to join */
pspUiFlashMessage(ADHOC_AWAITING_JOIN);
 
int state = ADHOC_WAIT_CLI;
PspMAC selected;
 
/* Loop until someone joins or host cancels */
while (!ExitPSP)
{
SceCtrlData pad;
 
if (!pspCtrlPollControls(&pad))
continue;
 
if (pad.Buttons & UiMetric.CancelButton)
break;
 
if (_adhoc_match_event.NewEvent)
{
_adhoc_match_event.NewEvent = 0;
 
switch(_adhoc_match_event.EventID)
{
case MATCHING_JOINED:
break;
case MATCHING_DISCONNECT:
case MATCHING_CANCELED:
if (pspAdhocIsMACEqual(selected, _adhoc_match_event.EventMAC))
state = ADHOC_WAIT_CLI;
break;
case MATCHING_SELECTED:
if (state == ADHOC_WAIT_CLI)
{
memcpy(selected, _adhoc_match_event.EventMAC,
sizeof(unsigned char) * 6);
sceKernelDelayThread(1000000/60);
pspAdhocSelectTarget(selected);
state = ADHOC_WAIT_EST;
}
break;
case MATCHING_ESTABLISHED:
if (state == ADHOC_WAIT_EST)
{
if (pspAdhocIsMACEqual(selected, _adhoc_match_event.EventMAC))
{
state = ADHOC_ESTABLISHED;
goto established;
}
}
break;
}
}
 
/* Wait if needed */
sceKernelDelayThread(1000000/60);
}
 
established:
 
if (state == ADHOC_ESTABLISHED)
{
sceKernelDelayThread(1000000);
 
PspMAC my_mac;
pspAdhocGetOwnMAC(my_mac);
memcpy(mac, selected, sizeof(unsigned char) * 6);
 
if (!pspAdhocConnect(my_mac))
return 0;
 
return 1;
}
 
/* Shutdown ad-hoc networking */
pspAdhocShutdown();
return 0;
}
 
int pspUiAdhocJoin(PspMAC mac)
{
/* Check the wlan switch */
if (!pspAdhocIsWLANEnabled())
{
pspUiAlert("Error: WLAN switch is turned off");
return 0;
}
 
char *title = "Select host";
 
/* Get copy of screen */
PspImage *screen = pspVideoGetVramBufferCopy();
 
pspUiFlashMessage(ADHOC_INITIALIZING);
_adhoc_match_event.NewEvent = 0;
 
/* Initialize ad-hoc networking */
if (!pspAdhocInit("ULUS99999", adhocMatchingCallback))
{
pspUiAlert("Ad-hoc networking initialization failed");
pspImageDestroy(screen);
return 0;
}
 
/* Initialize menu */
pl_menu menu;
pl_menu_create(&menu, NULL);
 
int state = ADHOC_PENDING;
const pl_menu_item *sel, *item, *last_sel = NULL;
struct UiPos pos;
int lnmax, lnhalf;
int i, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font);
int sx, sy, dx, dy;
int anim_frame = 0, anim_incr = 1;
int arrow_w = pspFontGetTextWidth(UiMetric.Font, PSP_CHAR_DOWN_ARROW);
int widest = 100;
int sel_top = 0, last_sel_top = 0;
SceCtrlData pad;
PspMAC selected;
 
char *help_text = strdup(SelectorTemplate);
ReplaceIcons(help_text);
 
memset(call_list, 0, sizeof(call_list));
 
/* Determine width of the longest caption */
for (item = menu.items; item; item = item->next)
{
if (item->caption)
{
int item_w = pspFontGetTextWidth(UiMetric.Font, item->caption);
if (item_w > widest)
widest = item_w;
}
}
 
widest += UiMetric.MenuItemMargin * 2;
 
sx = SCR_WIDTH - widest;
sy = UiMetric.Top;
dx = SCR_WIDTH;
dy = UiMetric.Bottom;
w = dx - sx;
h = dy - sy;
 
u32 ticks_per_sec, ticks_per_upd;
u64 current_tick, last_tick;
 
/* Initialize variables */
lnmax = (dy - sy) / fh;
lnhalf = lnmax >> 1;
 
sel = menu.items;
pos.Top = menu.items;
pos.Index = pos.Offset = 0;
 
pspVideoWaitVSync();
 
/* Compute update frequency */
ticks_per_sec = sceRtcGetTickResolution();
sceRtcGetCurrentTick(&last_tick);
ticks_per_upd = ticks_per_sec / UiMetric.MenuFps;
 
if (UiMetric.Animate)
{
/* Intro animation */
for (i = 0; i < UI_ANIM_FRAMES; i++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw right frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
int fast_scroll, found_psp;
 
/* Begin navigation loop */
while (!ExitPSP)
{
if (_adhoc_match_event.NewEvent)
{
found_psp = 0;
pl_menu_item *adhoc_item;
_adhoc_match_event.NewEvent = 0;
 
if (_adhoc_match_event.EventID == MATCHING_JOINED)
{
/* Make sure the machine isn't already on the list */
for (adhoc_item = menu.items; adhoc_item; adhoc_item = adhoc_item->next)
if (adhoc_item->param && pspAdhocIsMACEqual((unsigned char*)adhoc_item->param,
_adhoc_match_event.EventMAC))
{
found_psp = 1;
break;
}
 
if (!found_psp)
{
/* Create item */
adhoc_item = pl_menu_append_item(&menu, 0, _adhoc_match_event.OptData);
 
/* Add MAC */
unsigned char *opp_mac = (unsigned char*)malloc(6 * sizeof(unsigned char));
memcpy(opp_mac, _adhoc_match_event.EventMAC, sizeof(unsigned char) * 6);
adhoc_item->param = opp_mac;
 
if (!pos.Top)
sel = pos.Top = menu.items;
}
}
else if (_adhoc_match_event.EventID == MATCHING_DISCONNECT)
{
/* Make sure the machine IS on the list */
for (adhoc_item = menu.items; adhoc_item; adhoc_item = adhoc_item->next)
if (adhoc_item->param && pspAdhocIsMACEqual((unsigned char*)adhoc_item->param,
_adhoc_match_event.EventMAC))
{
found_psp = 1;
break;
}
 
if (found_psp)
{
/* Free MAC & destroy item */
free((void*)adhoc_item->param);
pl_menu_remove_item(&menu, adhoc_item);
 
/* Reset items */
sel = pos.Top = menu.items;
pos.Index = pos.Offset = 0;
}
}
else if (_adhoc_match_event.EventID == MATCHING_REJECTED)
{
/* Host rejected connection */
if (state == ADHOC_WAIT_HOST)
{
state = ADHOC_PENDING;
}
}
else if (_adhoc_match_event.EventID == MATCHING_ESTABLISHED)
{
if (state == ADHOC_WAIT_HOST)
{
state = ADHOC_EST_AS_CLI;
break;
}
}
}
 
/* Delay */
sceKernelDelayThread(1000000/60);
 
if (!pspCtrlPollControls(&pad))
continue;
 
fast_scroll = 0;
 
/* Incr/decr animation frame */
anim_frame += (UiMetric.Animate) ? anim_incr : 0;
if (anim_frame > 2 || anim_frame < 0)
anim_incr *= -1;
 
/* Check the directional buttons */
if (sel)
{
if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN)
&& sel->next)
{
fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN;
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; }
else pos.Index++;
sel = sel->next;
}
else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP)
&& sel->prev)
{
fast_scroll = pad.Buttons & PSP_CTRL_ANALUP;
if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; }
else pos.Index--;
sel = sel->prev;
}
else if (pad.Buttons & PSP_CTRL_LEFT)
{
for (i = 0; sel->prev && i < lnhalf; i++)
{
if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; }
else pos.Index--;
sel = sel->prev;
}
}
else if (pad.Buttons & PSP_CTRL_RIGHT)
{
for (i = 0; sel->next && i < lnhalf; i++)
{
if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; }
else pos.Index++;
sel=sel->next;
}
}
 
if (pad.Buttons & UiMetric.OkButton)
{
if (state == ADHOC_PENDING)
{
state = ADHOC_WAIT_HOST;
memcpy(selected, sel->param, sizeof(unsigned char) * 6);
pspAdhocSelectTarget(selected);
}
}
}
 
if (pad.Buttons & UiMetric.CancelButton) { sel = NULL; break; }
 
/* Render to a call list */
sceGuStart(GU_CALL, call_list);
 
/* Apply fog and draw frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0, 0, 0, UI_ANIM_FOG_STEP * UI_ANIM_FRAMES));
pspVideoGlowRect(sx, 0, dx - 1, SCR_HEIGHT - 1,
COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2);
 
/* Title */
if (title)
pspVideoPrintCenter(UiMetric.Font, sx, 0, dx,
title, UiMetric.TitleColor);
 
/* Render the items */
for (item = (pl_menu_item*)pos.Top, i = 0, j = sy;
item && i < lnmax; item = item->next, j += fh, i++)
{
if (item == sel) sel_top = j;
pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->caption, w - 10,
"...", (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor);
}
 
/* Up arrow */
if (pos.Top && pos.Top->prev) pspVideoPrint(UiMetric.Font,
SCR_WIDTH - arrow_w * 2, sy + anim_frame,
PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor);
 
/* Down arrow */
if (item) pspVideoPrint(UiMetric.Font, SCR_WIDTH - arrow_w * 2,
dy - fh - anim_frame, PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor);
 
/* Shortcuts */
pspVideoPrintCenter(UiMetric.Font, sx, SCR_HEIGHT - fh, dx,
help_text, UiMetric.StatusBarColor);
 
sceGuFinish();
 
if (sel != last_sel && !fast_scroll && sel && last_sel
&& UiMetric.Animate)
{
/* Move animation */
int f, n = 4;
for (f = 1; f <= n; f++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
/* Selection box */
int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f;
pspVideoFillRect(sx, box_top, sx + w, box_top + fh,
UiMetric.SelectedBgColor);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
if (sel) pspVideoFillRect(sx, sel_top, sx + w, sel_top + fh,
UiMetric.SelectedBgColor);
 
sceGuCallList(call_list);
 
pspVideoEnd();
 
/* Wait if needed */
do { sceRtcGetCurrentTick(&current_tick); }
while (current_tick - last_tick < ticks_per_upd);
last_tick = current_tick;
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
 
last_sel = sel;
last_sel_top = sel_top;
}
 
if (UiMetric.Animate)
{
/* Exit animation */
for (i = UI_ANIM_FRAMES - 1; i >= 0; i--)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog and draw right frame */
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT,
COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i));
pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)),
0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg);
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
}
 
free(help_text);
pspImageDestroy(screen);
 
/* Free memory used for MACs; menu resources */
for (item = menu.items; item; item=item->next)
if (item->param) free((void*)item->param);
pl_menu_destroy(&menu);
 
if (state == ADHOC_EST_AS_CLI)
{
memcpy(mac, selected, sizeof(unsigned char) * 6);
 
if (!pspAdhocConnect(selected))
return 0;
 
return 1;
}
 
/* Shut down ad-hoc networking */
pspAdhocShutdown();
return 0;
}
 
void pspUiFadeout()
{
/* Get copy of screen */
PspImage *screen = pspVideoGetVramBufferCopy();
 
/* Exit animation */
int i, alpha;
for (i = 0; i < UI_ANIM_FRAMES; i++)
{
pspVideoBegin();
 
/* Clear screen */
pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height);
 
/* Apply fog */
alpha = (0x100/UI_ANIM_FRAMES)*i-1;
if (alpha > 0)
pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, COLOR(0,0,0,alpha));
 
pspVideoEnd();
 
/* Swap buffers */
pspVideoWaitVSync();
pspVideoSwapBuffers();
}
 
pspImageDestroy(screen);
}
 
void enter_directory(pl_file_path current_dir,
const char *subdir)
{
pl_file_path new_path;
pl_file_open_directory(current_dir,
subdir,
new_path,
sizeof(new_path));
strcpy(current_dir, new_path);
}
/race/2.15/psp/psplib/image.c
0,0 → 1,587
/* psplib/image.h
Image manipulation/saving/loading
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include <malloc.h>
#include <string.h>
#include <png.h>
#include <pspgu.h>
 
#include "video.h"
#include "image.h"
 
typedef unsigned char byte;
 
int FindPowerOfTwoLargerThan(int n);
int FindPowerOfTwoLargerThan2(int n);
 
/* Creates an image in memory */
PspImage* pspImageCreate(int width, int height, int bpp)
{
if (bpp != PSP_IMAGE_INDEXED && bpp != PSP_IMAGE_16BPP) return NULL;
 
int size = width * height * (bpp / 8);
void *pixels = memalign(16, size);
 
if (!pixels) return NULL;
 
PspImage *image = (PspImage*)malloc(sizeof(PspImage));
 
if (!image)
{
free(pixels);
return NULL;
}
 
memset(pixels, 0, size);
 
image->Width = width;
image->Height = height;
image->Pixels = pixels;
 
image->Viewport.X = 0;
image->Viewport.Y = 0;
image->Viewport.Width = width;
image->Viewport.Height = height;
 
int i;
for (i = 1; i < width; i *= 2);
image->PowerOfTwo = (i == width);
image->BytesPerPixel = bpp / 8;
image->FreeBuffer = 1;
image->Depth = bpp;
memset(image->Palette, 0, sizeof(image->Palette));
image->PalSize = (unsigned short)256;
 
switch (image->Depth)
{
case PSP_IMAGE_INDEXED:
image->TextureFormat = GU_PSM_T8;
break;
case PSP_IMAGE_16BPP:
image->TextureFormat = GU_PSM_5551;
break;
}
 
return image;
}
 
/* Creates an image using portion of VRAM */
PspImage* pspImageCreateVram(int width, int height, int bpp)
{
if (bpp != PSP_IMAGE_INDEXED && bpp != PSP_IMAGE_16BPP) return NULL;
 
int i, size = width * height * (bpp / 8);
void *pixels = pspVideoAllocateVramChunk(size);
 
if (!pixels) return NULL;
 
PspImage *image = (PspImage*)malloc(sizeof(PspImage));
if (!image) return NULL;
 
memset(pixels, 0, size);
 
image->Width = width;
image->Height = height;
image->Pixels = pixels;
 
image->Viewport.X = 0;
image->Viewport.Y = 0;
image->Viewport.Width = width;
image->Viewport.Height = height;
 
for (i = 1; i < width; i *= 2);
image->PowerOfTwo = (i == width);
image->BytesPerPixel = bpp >> 3;
image->FreeBuffer = 0;
image->Depth = bpp;
memset(image->Palette, 0, sizeof(image->Palette));
image->PalSize = (unsigned short)256;
 
switch (image->Depth)
{
case PSP_IMAGE_INDEXED: image->TextureFormat = GU_PSM_T8; break;
case PSP_IMAGE_16BPP: image->TextureFormat = GU_PSM_5551; break;
}
 
return image;
}
 
PspImage* pspImageCreateOptimized(int width, int height, int bpp)
{
PspImage *image = pspImageCreate(FindPowerOfTwoLargerThan(width), height, bpp);
if (image) image->Viewport.Width = width;
 
return image;
}
 
/* Destroys image */
void pspImageDestroy(PspImage *image)
{
if (image->FreeBuffer) free(image->Pixels);
free(image);
}
 
PspImage* pspImageRotate(const PspImage *orig, int angle_cw)
{
PspImage *final;
 
/* Create image of appropriate size */
switch(angle_cw)
{
case 0:
return pspImageCreateCopy(orig);
case 90:
final = pspImageCreate(orig->Viewport.Height,
orig->Viewport.Width, orig->Depth);
break;
case 180:
final = pspImageCreate(orig->Viewport.Width,
orig->Viewport.Height, orig->Depth);
break;
case 270:
final = pspImageCreate(orig->Viewport.Height,
orig->Viewport.Width, orig->Depth);
break;
default:
return NULL;
}
 
int i, j, k, di = 0;
int width = final->Width;
int height = final->Height;
int l_shift = orig->BytesPerPixel >> 1;
const unsigned char *source = (unsigned char*)orig->Pixels;
unsigned char *dest = (unsigned char*)final->Pixels;
 
/* Skip to Y viewport starting point */
source += (orig->Viewport.Y * orig->Width) << l_shift;
 
/* Copy image contents */
for (i = 0, k = 0; i < orig->Viewport.Height; i++)
{
/* Skip to the start of the X viewport */
source += orig->Viewport.X << l_shift;
 
for (j = 0; j < orig->Viewport.Width; j++, source += 1 << l_shift, k++)
{
switch(angle_cw)
{
case 90:
di = (width - (k / height) - 1) + (k % height) * width;
break;
case 180:
di = (height - i - 1) * width + (width - j - 1);
break;
case 270:
di = (k / height) + (height - (k % height) - 1) * width;
break;
}
 
/* Write to destination */
if (orig->Depth == PSP_IMAGE_INDEXED) dest[di] = *source;
else ((unsigned short*)dest)[di] = *(unsigned short*)source; /* 16 bpp */
}
 
/* Skip to the end of the line */
source += (orig->Width - (orig->Viewport.X + orig->Viewport.Width)) << l_shift;
}
 
if (orig->Depth == PSP_IMAGE_INDEXED)
{
memcpy(final->Palette, orig->Palette, sizeof(orig->Palette));
final->PalSize = orig->PalSize;
}
 
return final;
}
 
/* Creates a half-sized thumbnail of an image */
PspImage* pspImageCreateThumbnail(const PspImage *image)
{
PspImage *thumb;
int i, j, p;
 
if (!(thumb = pspImageCreate(image->Viewport.Width >> 1,
image->Viewport.Height >> 1, image->Depth)))
return NULL;
 
int dy = image->Viewport.Y + image->Viewport.Height;
int dx = image->Viewport.X + image->Viewport.Width;
 
for (i = image->Viewport.Y, p = 0; i < dy; i += 2)
for (j = image->Viewport.X; j < dx; j += 2)
if (image->Depth == PSP_IMAGE_INDEXED)
((unsigned char*)thumb->Pixels)[p++]
= ((unsigned char*)image->Pixels)[(image->Width * i) + j];
else
((unsigned short*)thumb->Pixels)[p++]
= ((unsigned short*)image->Pixels)[(image->Width * i) + j];
 
if (image->Depth == PSP_IMAGE_INDEXED)
{
memcpy(thumb->Palette, image->Palette, sizeof(image->Palette));
thumb->PalSize = image->PalSize;
}
 
return thumb;
}
 
int pspImageDiscardColors(const PspImage *original)
{
if (original->Depth != PSP_IMAGE_16BPP) return 0;
 
int y, x, gray;
unsigned short *p;
 
for (y = 0, p = (unsigned short*)original->Pixels; y < original->Height; y++)
for (x = 0; x < original->Width; x++, p++)
{
gray = (RED(*p) * 3 + GREEN(*p) * 4 + BLUE(*p) * 2) / 9;
*p = RGB(gray, gray, gray);
}
 
return 1;
}
 
int pspImageBlur(const PspImage *original, PspImage *blurred)
{
if (original->Width != blurred->Width
|| original->Height != blurred->Height
|| original->Depth != blurred->Depth
|| original->Depth != PSP_IMAGE_16BPP) return 0;
 
int r, g, b, n, i, y, x, dy, dx;
unsigned short p;
 
for (y = 0, i = 0; y < original->Height; y++)
{
for (x = 0; x < original->Width; x++, i++)
{
r = g = b = n = 0;
for (dy = y - 1; dy <= y + 1; dy++)
{
if (dy < 0 || dy >= original->Height) continue;
 
for (dx = x - 1; dx <= x + 1; dx++)
{
if (dx < 0 || dx >= original->Width) continue;
 
p = ((unsigned short*)original->Pixels)[dx + dy * original->Width];
r += RED(p);
g += GREEN(p);
b += BLUE(p);
n++;
}
 
r /= n;
g /= n;
b /= n;
((unsigned short*)blurred->Pixels)[i] = RGB(r, g, b);
}
}
}
 
return 1;
}
 
/* Creates an exact copy of the image */
PspImage* pspImageCreateCopy(const PspImage *image)
{
PspImage *copy;
 
/* Create image */
if (!(copy = pspImageCreate(image->Width, image->Height, image->Depth)))
return NULL;
 
/* Copy pixels */
int size = image->Width * image->Height * image->BytesPerPixel;
memcpy(copy->Pixels, image->Pixels, size);
memcpy(&copy->Viewport, &image->Viewport, sizeof(PspViewport));
memcpy(copy->Palette, image->Palette, sizeof(image->Palette));
copy->PalSize = image->PalSize;
 
return copy;
}
 
/* Clears an image */
void pspImageClear(PspImage *image, unsigned int color)
{
if (image->Depth == PSP_IMAGE_INDEXED)
{
memset(image->Pixels, color & 0xff, image->Width * image->Height);
}
else if (image->Depth == PSP_IMAGE_16BPP)
{
int i;
unsigned short *pixel = image->Pixels;
for (i = image->Width * image->Height - 1; i >= 0; i--, pixel++)
*pixel = color & 0xffff;
}
}
 
/* Loads an image from a file */
PspImage* pspImageLoadPng(const char *path)
{
FILE *fp = fopen(path,"rb");
if(!fp) return NULL;
 
PspImage *image = pspImageLoadPngFd(fp);
fclose(fp);
 
return image;
}
 
/* Saves an image to a file */
int pspImageSavePng(const char *path, const PspImage* image)
{
FILE *fp = fopen( path, "wb" );
if (!fp) return 0;
 
int stat = pspImageSavePngFd(fp, image);
fclose(fp);
 
return stat;
}
 
#define IRGB(r,g,b,a) (((((b)>>3)&0x1F)<<10)|((((g)>>3)&0x1F)<<5)|\
(((r)>>3)&0x1F)|(a?0x8000:0))
 
/* Loads an image from an open file descriptor (16-bit PNG)*/
PspImage* pspImageLoadPngFd(FILE *fp)
{
const size_t nSigSize = 8;
byte signature[nSigSize];
if (fread(signature, sizeof(byte), nSigSize, fp) != nSigSize)
return 0;
 
if (!png_check_sig(signature, nSigSize))
return 0;
 
png_struct *pPngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!pPngStruct)
return 0;
 
png_info *pPngInfo = png_create_info_struct(pPngStruct);
if(!pPngInfo)
{
png_destroy_read_struct(&pPngStruct, NULL, NULL);
return 0;
}
 
if (setjmp(pPngStruct->jmpbuf))
{
png_destroy_read_struct(&pPngStruct, NULL, NULL);
return 0;
}
 
png_init_io(pPngStruct, fp);
png_set_sig_bytes(pPngStruct, nSigSize);
png_read_png(pPngStruct, pPngInfo,
PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING |
PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_BGR , NULL);
 
png_uint_32 width = pPngInfo->width;
png_uint_32 height = pPngInfo->height;
int color_type = pPngInfo->color_type;
 
PspImage *image;
 
int mod_width = FindPowerOfTwoLargerThan2(width);
if (!(image = pspImageCreate(mod_width, height, PSP_IMAGE_16BPP)))
{
png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL);
return 0;
}
 
image->Viewport.Width = width;
 
png_byte **pRowTable = pPngInfo->row_pointers;
unsigned int x, y;
byte r, g, b, a;
unsigned short *out = image->Pixels;
 
for (y=0; y<height; y++)
{
png_byte *pRow = pRowTable[y];
 
for (x=0; x<width; x++)
{
switch(color_type)
{
case PNG_COLOR_TYPE_GRAY:
r = g = b = *pRow++;
a = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
r = g = b = pRow[0];
a = pRow[1];
pRow += 2;
break;
case PNG_COLOR_TYPE_RGB:
b = pRow[0];
g = pRow[1];
r = pRow[2];
a = 1;
pRow += 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
b = pRow[0];
g = pRow[1];
r = pRow[2];
a = pRow[3];
pRow += 4;
break;
default:
r = g = b = a = 0;
break;
}
 
// *out++ = IRGB(r,g,b,a);
*out++ = IRGB(r,g,b,a);
}
 
out += (mod_width - width);
}
 
png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL);
 
return image;
}
 
/* Saves an image to an open file descriptor (16-bit PNG)*/
int pspImageSavePngFd(FILE *fp, const PspImage* image)
{
unsigned char *bitmap;
int i, j, width, height;
 
width = image->Viewport.Width;
height = image->Viewport.Height;
 
if (!(bitmap = (u8*)malloc(sizeof(u8) * width * height * 3)))
return 0;
 
if (image->Depth == PSP_IMAGE_INDEXED)
{
const unsigned char *pixel;
pixel = (unsigned char*)image->Pixels + (image->Viewport.Y * image->Width);
 
for (i = 0; i < height; i++)
{
/* Skip to the start of the viewport */
pixel += image->Viewport.X;
for (j = 0; j < width; j++, pixel++)
{
bitmap[i * width * 3 + j * 3 + 0] = RED(image->Palette[*pixel]);
bitmap[i * width * 3 + j * 3 + 1] = GREEN(image->Palette[*pixel]);
bitmap[i * width * 3 + j * 3 + 2] = BLUE(image->Palette[*pixel]);
}
/* Skip to the end of the line */
pixel += image->Width - (image->Viewport.X + width);
}
}
else
{
const unsigned short *pixel;
pixel = (unsigned short*)image->Pixels + (image->Viewport.Y * image->Width);
 
for (i = 0; i < height; i++)
{
/* Skip to the start of the viewport */
pixel += image->Viewport.X;
for (j = 0; j < width; j++, pixel++)
{
bitmap[i * width * 3 + j * 3 + 0] = RED(*pixel);
bitmap[i * width * 3 + j * 3 + 1] = GREEN(*pixel);
bitmap[i * width * 3 + j * 3 + 2] = BLUE(*pixel);
}
/* Skip to the end of the line */
pixel += image->Width - (image->Viewport.X + width);
}
}
 
png_struct *pPngStruct = png_create_write_struct( PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL );
 
if (!pPngStruct)
{
free(bitmap);
return 0;
}
 
png_info *pPngInfo = png_create_info_struct( pPngStruct );
if (!pPngInfo)
{
png_destroy_write_struct( &pPngStruct, NULL );
free(bitmap);
return 0;
}
 
png_byte **buf = (png_byte**)malloc(height * sizeof(png_byte*));
if (!buf)
{
png_destroy_write_struct( &pPngStruct, &pPngInfo );
free(bitmap);
return 0;
}
 
unsigned int y;
for (y = 0; y < height; y++)
buf[y] = (byte*)&bitmap[y * width * 3];
 
if (setjmp( pPngStruct->jmpbuf ))
{
free(buf);
free(bitmap);
png_destroy_write_struct( &pPngStruct, &pPngInfo );
return 0;
}
 
png_init_io( pPngStruct, fp );
png_set_IHDR( pPngStruct, pPngInfo, width, height, 8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info( pPngStruct, pPngInfo );
png_write_image( pPngStruct, buf );
png_write_end( pPngStruct, pPngInfo );
 
png_destroy_write_struct( &pPngStruct, &pPngInfo );
free(buf);
free(bitmap);
 
return 1;
}
 
int FindPowerOfTwoLargerThan(int n)
{
int i;
for (i = n; i < n; i *= 2);
return i;
}
 
int FindPowerOfTwoLargerThan2(int n)
{
int i;
for (i = 1; i < n; i *= 2);
return i;
}
/race/2.15/psp/psplib/pl_file.c
0,0 → 1,332
/* psplib/pl_file.c
File and directory query routines
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include <pspkernel.h>
#include <psptypes.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
 
#include "pl_file.h"
 
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
 
static void
sort_file_list(pl_file_list *list,
int count);
static int
compare_files_by_name(const void *s1,
const void *s2);
static int
mkdir_recursive(const char *path);
 
void pl_file_get_parent_directory(const char *path,
char *parent,
int length)
{
int pos = strlen(path) - 1,
len;
 
for (; pos >= 0 && path[pos] == '/'; pos--);
for (; pos >= 0 && path[pos] != '/'; pos--);
 
if (pos < 0)
{
len = MIN(strlen(path), length - 1);
strncpy(parent, path, len);
parent[len] = '\0';
return;
}
 
len = MIN(pos + 1, length - 1);
strncpy(parent, path, len);
parent[len] = '\0';
}
 
const char* pl_file_get_filename(const char *path)
{
const char *filename;
if (!(filename = strrchr(path, '/')))
return path;
return filename + 1;
}
 
const char* pl_file_get_extension(const char *path)
{
const char *filename = pl_file_get_filename(path);
const char *ext;
if (!(ext = strrchr(filename, '.')))
return filename + strlen(filename);
return ext + 1;
}
 
int pl_file_rm(const char *path)
{
return sceIoRemove(path) >= 0;
}
 
/* Returns size of file in bytes or <0 if error */
int pl_file_get_file_size(const char *path)
{
SceIoStat stat;
memset(&stat, 0, sizeof(stat));
if (sceIoGetstat(path, &stat) < 0)
return -1;
 
return (int)stat.st_size;
}
 
int pl_file_is_root_directory(const char *path)
{
const char *pos = strchr(path, '/');
return !pos || !(*(pos + 1));
}
 
int pl_file_exists(const char *path)
{
SceIoStat stat;
return sceIoGetstat(path, &stat) == 0;
}
 
int pl_file_is_of_type(const char *path,
const char *extension)
{
int fn_len, ext_len;
const char *file_ext;
 
fn_len = strlen(path);
ext_len = strlen(extension);
 
/* Filename must be at least 2 chars longer (period + a char) */
if (fn_len < ext_len + 2)
return 0;
 
file_ext = path + (fn_len - ext_len);
if (*(file_ext - 1) == '.' && strcasecmp(file_ext, extension) == 0)
return 1;
 
return 0;
}
 
void pl_file_destroy_file_list(pl_file_list *list)
{
pl_file *file, *next;
 
for (file = list->files; file; file = next)
{
next = file->next;
free(file->name);
free(file);
}
}
 
static int mkdir_recursive(const char *path)
{
int exit_status = 1;
SceIoStat stat;
 
if (sceIoGetstat(path, &stat) == 0)
/* If not a directory, cannot continue; otherwise success */
return (stat.st_attr & FIO_SO_IFDIR);
 
/* First, try creating its parent directory */
char *slash_pos = strrchr(path, '/');
if (!slash_pos); /* Top level */
else if (slash_pos != path && slash_pos[-1] == ':'); /* Top level */
else
{
char *parent = strdup(path);
parent[slash_pos - path] = '\0';
exit_status = mkdir_recursive(parent);
 
free(parent);
}
 
if (exit_status && slash_pos[1] != '\0')
{
if (sceIoMkdir(path, 0777) != 0)
exit_status = 0;
}
 
return exit_status;
}
 
int pl_file_mkdir_recursive(const char *path)
{
return mkdir_recursive(path);
}
 
int pl_file_get_file_list_count(const pl_file_list *list)
{
int count = 0;
pl_file *file;
 
for (file = list->files; file; file = file->next)
count++;
return count;
}
 
/* Returns number of files successfully read; negative number if error */
int pl_file_get_file_list(pl_file_list *list,
const char *path,
const char **filter)
{
SceUID fd = sceIoDopen(path);
if (fd < 0) return -1;
 
SceIoDirent dir;
memset(&dir, 0, sizeof(dir));
 
pl_file *file, *last = NULL;
list->files = NULL;
 
const char **pext;
int loop;
int count = 0;
 
while (sceIoDread(fd, &dir) > 0)
{
if (filter && !(dir.d_stat.st_attr & FIO_SO_IFDIR))
{
/* Loop through the list of allowed extensions and compare */
for (pext = filter, loop = 1; *pext; pext++)
{
if (pl_file_is_of_type(dir.d_name, *pext))
{
loop = 0;
break;
}
}
 
if (loop) continue;
}
 
/* Create a new file entry */
if (!(file = (pl_file*)malloc(sizeof(pl_file))))
{
pl_file_destroy_file_list(list);
return -1;
}
 
file->name = strdup(dir.d_name);
file->next = NULL;
file->attrs = (dir.d_stat.st_attr & FIO_SO_IFDIR)
? PL_FILE_DIRECTORY : 0;
 
/* Update preceding element */
if (last) last->next = file;
else list->files = file;
 
last = file;
count++;
}
 
sceIoDclose(fd);
 
/* Sort the files by name */
sort_file_list(list, count);
return count;
}
 
static void sort_file_list(pl_file_list *list,
int count)
{
pl_file **files, *file, **fp;
int i;
 
if (count < 1)
return;
 
/* Copy the file entries to an array */
files = (pl_file**)malloc(sizeof(pl_file*) * count);
for (file = list->files, fp = files; file; file = file->next, i++, fp++)
*fp = file;
 
/* Sort the array */
qsort((void*)files, count, sizeof(pl_file*), compare_files_by_name);
 
/* Rearrange the file entries in the list */
list->files = files[0];
list->files->next = NULL;
 
for (i = 1; i < count; i++)
files[i - 1]->next = files[i];
 
pl_file *last = files[count - 1];
last->next = NULL;
free(files);
}
 
static int compare_files_by_name(const void *s1, const void *s2)
{
pl_file *f1 = *(pl_file**)s1, *f2 = *(pl_file**)s2;
if ((f1->attrs & PL_FILE_DIRECTORY) == (f2->attrs & PL_FILE_DIRECTORY))
return strcasecmp(f1->name, f2->name);
else if (f1->attrs & PL_FILE_DIRECTORY)
return -1;
else return 1;
}
 
int pl_file_open_directory(const char *path,
const char *subdir,
char *result,
int result_len)
{
/* This routine should be made more robust */
/* to accept subdirs like ../../ etc... */
int path_len = strlen(path);
int copy_len;
 
/* Ascend one level */
if (strcmp(subdir, "..") == 0)
{
pl_file_get_parent_directory(path,
result,
result_len);
return 1;
}
else
{
copy_len = MIN(result_len - 1, strlen(subdir) + path_len + 2);
snprintf(result, copy_len, "%s%s/", path, subdir);
result[copy_len] = '\0';
return 1;
}
 
/* If we're here, then we couldn't figure out final path */
/* Just copy the original path */
copy_len = MIN(result_len - 1, path_len);
strncpy(result, path, copy_len);
result[copy_len] = '\0';
 
return (strcmp(subdir, ".") == 0);
}
 
int pl_file_is_directory(const char *path)
{
int len;
if ((len = strlen(path)) < 1)
return 0;
return (path[len - 1] == '/');
}
/race/2.15/psp/psplib/pl_file.h
0,0 → 1,76
/* psplib/file.h
File and directory query routines
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#ifndef _PL_FILE_H
#define _PL_FILE_H
 
#ifdef __cplusplus
extern "C" {
#endif
 
#define PL_FILE_DIRECTORY 0x01
#define PL_FILE_MAX_PATH_LEN 1024
 
typedef char pl_file_path[PL_FILE_MAX_PATH_LEN];
 
typedef struct pl_file_t
{
char *name;
unsigned char attrs;
struct pl_file_t *next;
} pl_file;
 
typedef struct pl_file_list_t
{
struct pl_file_t *files;
} pl_file_list;
 
void pl_file_get_parent_directory(const char *path,
char *parent,
int length);
const char*
pl_file_get_filename(const char *path);
const char*
pl_file_get_extension(const char *path);
int pl_file_get_file_size(const char *path);
int pl_file_exists(const char *path);
int pl_file_rm(const char *path);
int pl_file_open_directory(const char *path,
const char *subdir,
char *result,
int result_len);
int pl_file_is_directory(const char *path);
int pl_file_is_root_directory(const char *path);
int pl_file_is_of_type(const char *path,
const char *extension);
int pl_file_mkdir_recursive(const char *path);
/* Returns number of files successfully read; <0 if error */
int pl_file_get_file_list(pl_file_list *list,
const char *path,
const char **filter);
void pl_file_destroy_file_list(pl_file_list *list);
int pl_file_get_file_list_count(const pl_file_list *list);
 
#ifdef __cplusplus
}
#endif
 
#endif // _PL_FILE_H
/race/2.15/psp/psplib/ui.h
0,0 → 1,146
/* psplib/ui.h
Simple user interface implementation
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#ifndef _PSP_UI_H
#define _PSP_UI_H
 
#include "video.h"
#include "pl_menu.h"
#include "adhoc.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 
typedef struct PspUiMetric
{
const PspImage *Background;
const PspFont *Font;
u64 CancelButton;
u64 OkButton;
int Left;
int Top;
int Right;
int Bottom;
u32 ScrollbarColor;
u32 ScrollbarBgColor;
int ScrollbarWidth;
u32 TextColor;
u32 SelectedColor;
u32 SelectedBgColor;
u32 StatusBarColor;
int MenuFps;
 
u32 DialogFogColor;
 
u32 BrowserFileColor;
u32 BrowserDirectoryColor;
u32 BrowserScreenshotDelay;
const char *BrowserScreenshotPath;
 
int GalleryIconsPerRow;
int GalleryIconMarginWidth;
 
int MenuItemMargin;
u32 MenuSelOptionBg;
u32 MenuOptionBoxColor;
u32 MenuOptionBoxBg;
u32 MenuDecorColor;
 
int TitlePadding;
u32 TitleColor;
u32 TabBgColor;
int Animate;
} PspUiMetric;
 
typedef struct PspUiFileBrowser
{
void (*OnRender)(const void *browser, const void *path);
int (*OnOk)(const void *browser, const void *file);
int (*OnCancel)(const void *gallery, const void *parent_dir);
int (*OnButtonPress)(const struct PspUiFileBrowser* browser,
const char *selected, u32 button_mask);
const char **Filter;
void *Userdata;
} PspUiFileBrowser;
 
typedef struct PspUiMenu
{
void (*OnRender)(const void *uimenu, const void *item);
int (*OnOk)(const void *menu, const void *item);
int (*OnCancel)(const void *menu, const void *item);
int (*OnButtonPress)(const struct PspUiMenu *menu, pl_menu_item *item,
u32 button_mask);
int (*OnItemChanged)(const struct PspUiMenu *menu, pl_menu_item *item,
const pl_menu_option *option);
pl_menu Menu;
} PspUiMenu;
 
typedef struct PspUiGallery
{
void (*OnRender)(const void *gallery, const void *item);
int (*OnOk)(const void *gallery, const void *item);
int (*OnCancel)(const void *gallery, const void *item);
int (*OnButtonPress)(const struct PspUiGallery *gallery, pl_menu_item* item,
u32 button_mask);
void *Userdata;
pl_menu Menu;
} PspUiGallery;
 
typedef struct PspUiSplash
{
void (*OnRender)(const void *splash, const void *null);
int (*OnCancel)(const void *splash, const void *null);
int (*OnButtonPress)(const struct PspUiSplash *splash, u32 button_mask);
const char* (*OnGetStatusBarText)(const struct PspUiSplash *splash);
} PspUiSplash;
 
#define PSP_UI_YES 2
#define PSP_UI_NO 1
#define PSP_UI_CANCEL 0
 
#define PSP_UI_CONFIRM 1
 
char pspUiGetButtonIcon(u32 button_mask);
 
void pspUiOpenBrowser(PspUiFileBrowser *browser, const char *start_path);
void pspUiOpenGallery(PspUiGallery *gallery, const char *title);
void pspUiOpenMenu(PspUiMenu *uimenu, const char *title);
void pspUiSplashScreen(PspUiSplash *splash);
 
int pspUiAdhocHost(const char *name, PspMAC mac);
int pspUiAdhocJoin(PspMAC mac);
 
int pspUiConfirm(const char *message);
int pspUiYesNoCancel(const char *message);
void pspUiAlert(const char *message);
void pspUiFlashMessage(const char *message);
const pl_menu_item* pspUiSelect(const char *title, const pl_menu *menu);
 
void pspUiFadeout();
 
PspUiMetric UiMetric;
 
#ifdef __cplusplus
}
#endif
 
#endif // _PSP_UI_H
/race/2.15/psp/psplib/pl_ini.c
0,0 → 1,373
/* psplib/pl_ini.h
INI file reading/writing
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include "pl_ini.h"
 
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
 
#define PL_MAX_LINE_LENGTH 512
 
typedef struct pl_ini_pair_t
{
char *key;
char *value;
struct pl_ini_pair_t *next;
} pl_ini_pair;
 
typedef struct pl_ini_section_t
{
char *name;
struct pl_ini_pair_t *head;
struct pl_ini_section_t *next;
} pl_ini_section;
 
static pl_ini_section* create_section(const char *name);
static pl_ini_pair* create_pair(char *string);
static pl_ini_section* find_section(const pl_ini_file *file,
const char *section_name);
static pl_ini_pair* find_pair(const pl_ini_section *section,
const char *key_name);
static pl_ini_pair* locate(const pl_ini_file *file,
const char *section_name,
const char *key_name);
static pl_ini_pair* locate_or_create(pl_ini_file *file,
const char *section_name,
const char *key_name);
 
int pl_ini_create(pl_ini_file *file)
{
file->head = NULL;
return 1;
}
 
int pl_ini_load(pl_ini_file *file,
const char *path)
{
file->head = NULL;
 
FILE *stream;
if (!(stream = fopen(path, "r")))
return 0;
 
pl_ini_section *current_section = NULL;
pl_ini_pair *tail;
 
char string[PL_MAX_LINE_LENGTH],
name[PL_MAX_LINE_LENGTH];
char *ptr;
int len;
 
/* Create unnamed section */
current_section = NULL;
tail = NULL;
 
while(!feof(stream) && fgets(string, sizeof(string), stream))
{
/* TODO: Skip whitespace */
/* New section */
if (string[0] == '[')
{
if ((ptr = strrchr(string, ']')))
{
len = ptr - string - 1;
strncpy(name, string + 1, len);
name[len] = '\0';
 
if (!current_section)
current_section = file->head = create_section(name);
else
{
current_section->next = create_section(name);
current_section = current_section->next;
}
 
tail = NULL;
}
}
else if (string[0] =='#'); /* Do nothing - comment */
else
{
/* No section defined - create empty section */
if (!current_section)
{
current_section = create_section(strdup(""));
file->head = current_section;
tail = NULL;
}
 
pl_ini_pair *pair = create_pair(string);
if (pair)
{
if (tail) tail->next = pair;
else current_section->head = pair;
tail = pair;
}
}
}
 
fclose(stream);
return 1;
}
 
int pl_ini_save(const pl_ini_file *file,
const char *path)
{
FILE *stream;
if (!(stream = fopen(path, "w")))
return 0;
 
pl_ini_section *section;
pl_ini_pair *pair;
 
for (section = file->head; section; section = section->next)
{
fprintf(stream, "[%s]\n", section->name);
for (pair = section->head; pair; pair = pair->next)
fprintf(stream, "%s=%s\n", pair->key, pair->value);
}
 
fclose(stream);
return 1;
}
 
int pl_ini_get_int(const pl_ini_file *file,
const char *section,
const char *key,
int default_value)
{
pl_ini_pair *pair = locate(file, section, key);
return (pair) ? atoi(pair->value) : default_value;
}
 
int pl_ini_get_string(const pl_ini_file *file,
const char *section,
const char *key,
const char *default_value,
char *copy_to,
int dest_len)
{
pl_ini_pair *pair = locate(file, section, key);
if (pair)
{
strncpy(copy_to, pair->value, dest_len);
return 1;
}
else if (default_value)
{
strncpy(copy_to, default_value, dest_len);
return 1;
}
 
return 0;
}
 
void pl_ini_set_int(pl_ini_file *file,
const char *section,
const char *key,
int value)
{
pl_ini_pair *pair;
if (!(pair = locate_or_create(file, section, key)))
return;
 
/* Replace the value */
if (pair->value)
free(pair->value);
 
char temp[64];
snprintf(temp, 63, "%i", value);
pair->value = strdup(temp);
}
 
void pl_ini_set_string(pl_ini_file *file,
const char *section,
const char *key,
const char *string)
{
pl_ini_pair *pair;
if (!(pair = locate_or_create(file, section, key)))
return;
 
/* Replace the value */
if (pair->value)
free(pair->value);
pair->value = strdup(string);
}
 
void pl_ini_destroy(pl_ini_file *file)
{
pl_ini_section *section, *next_section;
pl_ini_pair *pair, *next_pair;
 
for (section = file->head; section; section = next_section)
{
next_section = section->next;
 
if (section->name)
free(section->name);
for (pair = section->head; pair; pair = next_pair)
{
next_pair = pair->next;
if (pair->key)
free(pair->key);
if (pair->value)
free(pair->value);
free(pair);
}
 
free(section);
}
}
 
static pl_ini_section* find_section(const pl_ini_file *file,
const char *section_name)
{
pl_ini_section *section;
for (section = file->head; section; section = section->next)
if (strcmp(section_name, section->name) == 0)
return section;
 
return NULL;
}
 
static pl_ini_pair* find_pair(const pl_ini_section *section,
const char *key_name)
{
pl_ini_pair *pair;
for (pair = section->head; pair; pair = pair->next)
if (strcmp(pair->key, key_name) == 0)
return pair;
 
return NULL;
}
 
static pl_ini_pair* locate(const pl_ini_file *file,
const char *section_name,
const char *key_name)
{
pl_ini_section *section;
if (!(section = find_section(file, section_name)))
return NULL;
 
return find_pair(section, key_name);
}
 
static pl_ini_pair* locate_or_create(pl_ini_file *file,
const char *section_name,
const char *key_name)
{
pl_ini_section *section = find_section(file, section_name);
pl_ini_pair *pair = NULL;
 
if (section)
pair = find_pair(section, key_name);
else
{
/* Create section */
section = create_section(section_name);
 
if (!file->head)
file->head = section;
else
{
pl_ini_section *s;
for (s = file->head; s->next; s = s->next); /* Find the tail */
s->next = section;
}
}
 
if (!pair)
{
/* Create pair */
pair = (pl_ini_pair*)malloc(sizeof(pl_ini_pair));
pair->key = strdup(key_name);
pair->value = NULL;
pair->next = NULL;
 
if (!section->head)
section->head = pair;
else
{
pl_ini_pair *p;
for (p = section->head; p->next; p = p->next); /* Find the tail */
p->next = pair;
}
}
 
return pair;
}
 
static pl_ini_section* create_section(const char *name)
{
pl_ini_section *section
= (pl_ini_section*)malloc(sizeof(pl_ini_section));
section->head = NULL;
section->next = NULL;
section->name = strdup(name);
 
return section;
}
 
static pl_ini_pair* create_pair(char *string)
{
char *ptr;
if (!(ptr = strchr(string, '=')))
return NULL;
 
int len;
char *name, *value;
 
/* Copy NAME */
len = ptr - string;
if (!(name = (char*)malloc(sizeof(char) * (len + 1))))
return NULL;
strncpy(name, string, len);
name[len] = '\0';
 
/* Copy VALUE */
if (!(value = strdup(ptr + 1)))
{
free(name);
return NULL;
}
 
len = strlen(value);
if (value[len - 1] == '\n') value[len - 1] = '\0';
 
/* Create struct */
pl_ini_pair *pair = (pl_ini_pair*)malloc(sizeof(pl_ini_pair));
 
if (!pair)
{
free(name);
free(value);
return NULL;
}
 
pair->key = name;
pair->value = value;
pair->next = NULL;
 
return pair;
}
/race/2.15/psp/psplib/font.c
0,0 → 1,63
/* psplib/font.c
Rudimentary bitmap font implementation
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include "font.h"
#include "stockfont.h"
 
int pspFontGetLineHeight(const PspFont *font)
{
return font->Height;
}
 
int pspFontGetTextWidth(const PspFont *font, const char *string)
{
const unsigned char *ch;
int width, max, w;
 
for (ch = (unsigned char*)string, width = 0, max = 0; *ch; ch++)
{
/* Tab = 4 spaces (TODO) */
if (*ch == '\t') w = font->Chars[(unsigned char)' '].Width * 4;
/* Newline */
else if (*ch == '\n') width = w = 0;
/* Special char */
else if (*ch < 32) w = 0;
/* Normal char */
else w = font->Chars[(unsigned char)(*ch)].Width;
 
width += w;
if (width > max) max = width;
}
 
return max;
}
 
int pspFontGetTextHeight(const PspFont *font, const char *string)
{
const char *ch;
int lines;
 
for (ch = string, lines = 1; *ch; ch++)
if (*ch == '\n') lines++;
 
return lines * font->Height;
}
 
/race/2.15/psp/psplib/font.h
0,0 → 1,90
/* psplib/font.h
Rudimentary bitmap font implementation
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#ifndef _PSP_FONT_H
#define _PSP_FONT_H
 
#ifdef __cplusplus
extern "C" {
#endif
 
#define PSP_CHAR_ANALUP "\251"
#define PSP_CHAR_ANALDOWN "\252"
#define PSP_CHAR_ANALLEFT "\253"
#define PSP_CHAR_ANALRIGHT "\254"
#define PSP_CHAR_UP "\245"
#define PSP_CHAR_DOWN "\246"
#define PSP_CHAR_LEFT "\247"
#define PSP_CHAR_RIGHT "\250"
#define PSP_CHAR_SQUARE "\244"
#define PSP_CHAR_CROSS "\241"
#define PSP_CHAR_CIRCLE "\242"
#define PSP_CHAR_TRIANGLE "\243"
#define PSP_CHAR_LTRIGGER "\255"
#define PSP_CHAR_RTRIGGER "\256"
#define PSP_CHAR_SELECT "\257\260"
#define PSP_CHAR_START "\261\262"
 
#define PSP_CHAR_UP_ARROW "\272"
#define PSP_CHAR_DOWN_ARROW "\273"
 
#define PSP_CHAR_POWER "\267"
#define PSP_CHAR_EMPTY_BATT "\266"
#define PSP_CHAR_FULL_BATT "\263"
#define PSP_CHAR_FLOPPY "\274"
 
#define PSP_CHAR_MS "\271"
 
#define PSP_FONT_RESTORE 020
#define PSP_FONT_BLACK 021
#define PSP_FONT_RED 022
#define PSP_FONT_GREEN 023
#define PSP_FONT_BLUE 024
#define PSP_FONT_GRAY 025
#define PSP_FONT_YELLOW 026
#define PSP_FONT_MAGENTA 027
#define PSP_FONT_WHITE 030
 
struct PspFont
{
unsigned char Height;
unsigned char Ascent;
struct
{
unsigned char Width;
unsigned short *Char;
} Chars[256];
};
 
typedef struct PspFont PspFont;
 
extern const PspFont PspStockFont;
 
int pspFontGetLineHeight(const PspFont *font);
int pspFontGetTextWidth(const PspFont *font, const char *string);
int pspFontGetTextHeight(const PspFont *font, const char *string);
 
 
#ifdef __cplusplus
}
#endif
 
#endif // _PSP_FONT_H
/race/2.15/psp/psplib/pl_util.h
0,0 → 1,52
/* psplib/pl_util.h
Various utility functions
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#ifndef _PL_UTIL_H
#define _PL_UTIL_H
 
#include <psptypes.h>
#include "image.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 
/* Sequential image saves */
int pl_util_save_image_seq(const char *path,
const char *filename,
const PspImage *image);
int pl_util_save_vram_seq(const char *path,
const char *prefix);
int pl_util_date_compare(const ScePspDateTime *date1,
const ScePspDateTime *date2);
int pl_util_compute_crc32_buffer(const void *buf,
size_t buf_len,
uint32_t *crc_32);
int pl_util_compute_crc32_fd(FILE *file,
uint32_t *outCrc32);
int pl_util_compute_crc32_file(const char *path,
uint32_t *outCrc32);
 
#ifdef __cplusplus
}
#endif
 
#endif // _PL_UTIL_H
/race/2.15/psp/psplib/stockfont.fd
0,0 → 1,4099
height 13
ascent 11
 
char 0
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 1
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 2
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 3
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 4
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 5
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 6
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 7
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 8
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 9
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 10
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 11
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 12
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 13
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 14
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 15
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 16
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 17
width 6
000000
000000
000000
111111
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 18
width 6
000000
000000
000000
000000
000000
000000
111111
000000
000000
000000
000000
000000
000000
 
char 19
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
111111
000000
000000
000000
 
char 20
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
111111
 
char 21
width 6
001000
001000
001000
001000
001000
001000
001111
001000
001000
001000
001000
001000
001000
 
char 22
width 6
001000
001000
001000
001000
001000
001000
111000
001000
001000
001000
001000
001000
001000
 
char 23
width 6
001000
001000
001000
001000
001000
001000
111111
000000
000000
000000
000000
000000
000000
 
char 24
width 6
000000
000000
000000
000000
000000
000000
111111
001000
001000
001000
001000
001000
001000
 
char 25
width 6
001000
001000
001000
001000
001000
001000
001000
001000
001000
001000
001000
001000
001000
 
char 26
width 6
000000
000000
000000
000110
011000
100000
011000
000110
000000
111110
000000
000000
000000
 
char 27
width 6
000000
000000
000000
110000
001100
000010
001100
110000
000000
111110
000000
000000
000000
 
char 28
width 6
000000
000000
000000
000000
000000
111110
010100
010100
010100
010100
010100
000000
000000
 
char 29
width 6
000000
000000
000000
000000
000000
000010
111110
001000
111110
100000
000000
000000
000000
 
char 30
width 6
000000
000000
001100
010010
010000
010000
111000
010000
010000
010010
101100
000000
000000
 
char 31
width 6
000000
000000
000000
000000
000000
000000
001100
000000
000000
000000
000000
000000
000000
 
char 32
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 33
width 6
000000
000000
001000
001000
001000
001000
001000
001000
001000
000000
001000
000000
000000
 
char 34
width 6
000000
000000
010100
010100
010100
000000
000000
000000
000000
000000
000000
000000
000000
 
char 35
width 6
000000
000000
000000
010100
010100
111110
010100
111110
010100
010100
000000
000000
000000
 
char 36
width 6
000000
000000
001000
011110
101000
101000
011100
001010
001010
111100
001000
000000
000000
 
char 37
width 6
000000
000000
010010
101010
010100
000100
001000
010000
010100
101010
100100
000000
000000
 
char 38
width 6
000000
000000
000000
010000
101000
101000
010000
101000
100110
100100
011010
000000
000000
 
char 39
width 6
000000
000000
001100
001000
010000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 40
width 6
000000
000100
001000
001000
010000
010000
010000
010000
010000
001000
001000
000100
000000
 
char 41
width 6
000000
010000
001000
001000
000100
000100
000100
000100
000100
001000
001000
010000
000000
 
char 42
width 6
000000
000000
001000
101010
011100
101010
001000
000000
000000
000000
000000
000000
000000
 
char 43
width 6
000000
000000
000000
000000
001000
001000
111110
001000
001000
000000
000000
000000
000000
 
char 44
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
001100
001000
010000
000000
 
char 45
width 6
000000
000000
000000
000000
000000
000000
111110
000000
000000
000000
000000
000000
000000
 
char 46
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
001000
011100
001000
000000
 
char 47
width 6
000000
000000
000010
000010
000100
000100
001000
010000
010000
100000
100000
000000
000000
 
char 48
width 6
000000
000000
000000
011100
110110
100010
100010
100010
100010
110110
011100
000000
000000
 
char 49
width 6
000000
000000
000000
111000
001000
001000
001000
001000
001000
001000
111110
000000
000000
 
char 50
width 6
000000
000000
000000
011100
100010
000010
000010
000100
001000
010000
111110
000000
000000
 
char 51
width 6
000000
000000
000000
011100
100010
000010
011100
000010
000010
100010
011100
000000
000000
 
char 52
width 7
0000000
0000000
0000000
0000100
0001100
0010100
0100100
1000100
1111110
0000100
0000100
0000000
0000000
 
char 53
width 7
000000
000000
000000
111100
100000
100000
111100
000010
000010
000010
111100
000000
000000
 
char 54
width 6
000000
000000
000000
001110
010000
100000
111100
100010
100010
100010
011100
000000
000000
 
char 55
width 6
000000
000000
000000
111110
000010
000100
000100
001000
001000
001000
010000
000000
000000
 
char 56
width 6
000000
000000
000000
011100
100010
100010
011100
100010
100010
100010
011100
000000
000000
 
char 57
width 7
000000
000000
000000
011100
100010
100010
100010
011110
000010
000100
111000
000000
000000
 
char 58
width 6
000000
000000
000000
001000
011100
001000
000000
000000
001000
011100
001000
000000
000000
 
char 59
width 6
000000
000000
000000
000000
001000
011100
001000
000000
000000
001100
001000
010000
000000
 
char 60
width 6
000000
000000
000010
000100
001000
010000
100000
010000
001000
000100
000010
000000
000000
 
char 61
width 6
000000
000000
000000
000000
000000
111110
000000
000000
111110
000000
000000
000000
000000
 
char 62
width 6
000000
000000
100000
010000
001000
000100
000010
000100
001000
010000
100000
000000
000000
 
char 63
width 6
000000
000000
011100
100010
100010
000010
000100
001000
001000
000000
001000
000000
000000
 
char 64
width 6
000000
000000
011100
100010
100010
100110
101010
101010
101100
100000
011110
000000
000000
 
char 65
width 8
00000000
00000000
00000000
00010000
00101000
00101000
00101000
01000100
01111100
01000100
10000010
00000000
00000000
 
char 66
width 7
0000000
0000000
0000000
1111100
1000010
1000010
1111100
1000010
1000010
1000010
1111100
0000000
0000000
 
char 67
width 7
0000000
0000000
0000000
0011100
0100010
1000000
1000000
1000000
1000000
0100010
0011100
0000000
0000000
 
char 68
width 8
0000000
0000000
0000000
1111000
1000100
1000010
1000010
1000010
1000010
1000100
1111000
0000000
0000000
 
char 69
width 6
000000
000000
000000
111110
100000
100000
111110
100000
100000
100000
111110
000000
000000
 
char 70
width 6
000000
000000
000000
111110
100000
100000
111110
100000
100000
100000
100000
000000
000000
 
char 71
width 8
00000000
00000000
00000000
00111100
01000010
10000000
10000000
10001110
10000010
01000010
00111100
00000000
00000000
 
char 72
width 7
0000000
0000000
0000000
1000010
1000010
1000010
1111110
1000010
1000010
1000010
1000010
0000000
0000000
 
char 73
width 2
00
00
00
10
10
10
10
10
10
10
10
00
00
 
char 74
width 4
0000
0000
0000
0010
0010
0010
0010
0010
0010
0010
0010
0010
1100
 
char 75
width 7
0000000
0000000
0000000
1000100
1001000
1010000
1100000
1010000
1001000
1000100
1000010
0000000
0000000
 
char 76
width 6
000000
000000
000000
100000
100000
100000
100000
100000
100000
100000
111110
000000
000000
 
char 77
width 8
00000000
00000000
00000000
10000010
11000110
11000110
10101010
10101010
10010010
10000010
10000010
00000000
00000000
 
char 78
width 7
0000000
0000000
0000000
1100010
1100010
1010010
1010010
1001010
1001010
1000110
1000110
0000000
0000000
 
char 79
width 8
00000000
00000000
00000000
00111000
01000100
10000010
10000010
10000010
10000010
01000100
00111000
00000000
00000000
 
char 80
width 6
000000
000000
000000
111100
100010
100010
100010
111100
100000
100000
100000
000000
000000
 
char 81
width 8
00000000
00000000
00000000
00111000
01000100
10000010
10000010
10000010
10000010
01000100
00111000
00001100
00000000
 
char 82
width 7
0000000
0000000
0000000
1111000
1000100
1000100
1000100
1111000
1001000
1000100
1000010
0000000
0000000
 
char 83
width 7
0000000
0000000
0000000
0111100
1000010
1000000
1111000
0000110
0000010
1000010
0111100
0000000
0000000
 
char 84
width 8
00000000
00000000
00000000
11111110
00010000
00010000
00010000
00010000
00010000
00010000
00010000
00000000
00000000
 
char 85
width 7
0000000
0000000
0000000
1000010
1000010
1000010
1000010
1000010
1000010
1100110
0111100
0000000
0000000
 
char 86
width 9
00000000
00000000
00000000
10000010
10000010
01000100
01000100
00101000
00101000
00010000
00010000
00000000
00000000
 
char 87
width 10
0000000000
0000000000
0000000000
1000100010
1000100010
0100100100
0101010100
0101010100
0101010100
0010001000
0010001000
0000000000
0000000000
 
char 88
width 8
00000000
00000000
00000000
10000010
01000100
00101000
00010000
00010000
00101000
01000100
10000010
00000000
00000000
 
char 89
width 8
00000000
00000000
00000000
10000010
01000100
00101000
00010000
00010000
00010000
00010000
00010000
00000000
00000000
 
char 90
width 8
00000000
00000000
00000000
11111110
00000100
00001000
00010000
00010000
00100000
01000000
11111110
00000000
00000000
 
char 91
width 6
000000
011100
010000
010000
010000
010000
010000
010000
010000
010000
010000
011100
000000
 
char 92
width 6
000000
000000
100000
100000
010000
010000
001000
000100
000100
000010
000010
000000
000000
 
char 93
width 6
000000
011100
000100
000100
000100
000100
000100
000100
000100
000100
000100
011100
000000
 
char 94
width 6
000000
000000
001000
010100
100010
000000
000000
000000
000000
000000
000000
000000
000000
 
char 95
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
111110
000000
 
char 96
width 6
000000
000000
001100
000100
000010
000000
000000
000000
000000
000000
000000
000000
000000
 
char 97
width 6
000000
000000
000000
000000
000000
011100
000010
011110
100010
100010
011110
000000
000000
 
char 98
width 6
000000
000000
100000
100000
100000
111100
100010
100010
100010
100010
111100
000000
000000
 
char 99
width 5
00000
00000
00000
00000
00000
01110
10000
10000
10000
10000
01110
00000
00000
 
char 100
width 6
000000
000000
000010
000010
000010
011110
100010
100010
100010
100010
011110
000000
000000
 
char 101
width 6
000000
000000
000000
000000
000000
011100
100010
111110
100000
110010
011100
000000
000000
 
char 102
width 5
00000
00000
01110
01000
01000
11110
01000
01000
01000
01000
01000
00000
00000
 
char 103
width 6
000000
000000
000000
000000
000000
011110
100010
100010
100010
100010
011110
000010
011100
 
char 104
width 6
000000
000000
100000
100000
100000
100000
111100
100010
100010
100010
100010
000000
000000
 
char 105
width 2
00
00
00
00
10
00
10
10
10
10
10
00
00
 
char 106
width 3
000
000
000
000
010
000
010
010
010
010
010
010
110
 
char 107
width 7
000000
000000
100000
100000
100000
100100
101000
110000
101000
100100
100010
000000
000000
 
char 108
width 2
00
00
10
10
10
10
10
10
10
10
10
00
00
 
char 109
width 10
0000000000
0000000000
0000000000
0000000000
0000000000
1111111100
1000100010
1000100010
1000100010
1000100010
1000100010
0000000000
0000000000
 
char 110
width 6
000000
000000
000000
000000
000000
111100
100010
100010
100010
100010
100010
000000
000000
 
char 111
width 6
000000
000000
000000
000000
000000
011100
100010
100010
100010
100010
011100
000000
000000
 
char 112
width 6
000000
000000
000000
000000
000000
111100
100010
100010
100010
100010
111100
100000
100000
 
char 113
width 6
000000
000000
000000
000000
000000
011110
100010
100010
100010
100010
011110
000010
000010
 
char 114
width 5
00000
00000
00000
00000
00000
10110
11000
10000
10000
10000
10000
00000
00000
 
char 115
width 6
000000
000000
000000
000000
000000
011100
100010
111000
000110
100010
011100
000000
000000
 
char 116
width 5
00000
00000
00000
01000
01000
11110
01000
01000
01000
01000
01110
00000
00000
 
char 117
width 6
000000
000000
000000
000000
000000
100010
100010
100010
100010
100010
011110
000000
000000
 
char 118
width 7
0000000
0000000
0000000
0000000
0000000
1000010
1000010
0100100
0100100
0011000
0011000
0000000
0000000
 
char 119
width 8
00000000
00000000
00000000
00000000
00000000
10010010
10010010
10101010
10101010
01000100
01000100
00000000
00000000
 
char 120
width 7
0000000
0000000
0000000
0000000
0000000
1000010
0100100
0011000
0011000
0100100
1000010
0000000
0000000
 
char 121
width 7
0000000
0000000
0000000
0000000
0000000
1000010
1000010
0100100
0100100
0011000
0011000
0010000
1100000
 
char 122
width 6
000000
000000
000000
000000
000000
111110
000010
000100
001000
010000
111110
000000
000000
 
char 123
width 6
000000
000110
001000
001000
001000
001000
110000
001000
001000
001000
001000
000110
000000
 
char 124
width 6
000000
000000
001000
001000
001000
001000
001000
001000
001000
001000
001000
000000
000000
 
char 125
width 6
000000
110000
001000
001000
001000
001000
000110
001000
001000
001000
001000
110000
000000
 
char 126
width 6
000000
000000
010010
101010
100100
000000
000000
000000
000000
000000
000000
000000
000000
 
char 127
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 128
width 6
000000
000000
001110
010000
010000
111100
010000
111100
010000
010000
001110
000000
000000
 
char 129
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 130
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
001100
000100
001000
000000
 
char 131
width 6
000000
000000
000100
001010
001000
001000
011100
001000
001000
001000
001000
101000
010000
 
char 132
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
110110
010010
100100
000000
 
char 133
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
101010
000000
000000
 
char 134
width 6
000000
000000
001000
001000
111110
001000
001000
001000
001000
001000
001000
000000
000000
 
char 135
width 6
000000
000000
001000
001000
111110
001000
001000
111110
001000
001000
001000
000000
000000
 
char 136
width 6
000000
001100
010010
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 137
width 6
000000
000000
010010
101010
010100
000100
001000
010000
011010
110101
101010
000000
000000
 
char 138
width 6
000000
010010
001100
000000
011100
100010
100000
011100
000010
100010
011100
000000
000000
 
char 139
width 6
000000
000000
000000
000000
000100
001000
010000
010000
001000
000100
000000
000000
000000
 
char 140
width 6
000000
000000
011110
101000
101000
101000
101100
101000
101000
101000
011110
000000
000000
 
char 141
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 142
width 6
000000
010010
001100
000000
111110
000010
000100
001000
010000
100000
111110
000000
000000
 
char 143
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 144
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 145
width 6
000000
000000
000100
001000
001100
000000
000000
000000
000000
000000
000000
000000
000000
 
char 146
width 6
000000
000000
001100
000100
001000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 147
width 6
000000
000000
010010
100100
110110
000000
000000
000000
000000
000000
000000
000000
000000
 
char 148
width 6
000000
000000
110110
010010
100100
000000
000000
000000
000000
000000
000000
000000
000000
 
char 149
width 6
000000
000000
000000
000000
011100
111110
111110
111110
011100
000000
000000
000000
000000
 
char 150
width 6
000000
000000
000000
000000
000000
000000
111110
000000
000000
000000
000000
000000
000000
 
char 151
width 6
000000
000000
000000
000000
000000
000000
111111
000000
000000
000000
000000
000000
000000
 
char 152
width 6
000000
001010
010100
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 153
width 6
000000
000000
111101
010111
010101
010101
000000
000000
000000
000000
000000
000000
000000
 
char 154
width 6
000000
000000
100100
011000
000000
011100
100010
011000
000100
100010
011100
000000
000000
 
char 155
width 6
000000
000000
000000
000000
010000
001000
000100
000100
001000
010000
000000
000000
000000
 
char 156
width 6
000000
000000
000000
000000
000000
010100
101010
101110
101000
101010
010100
000000
000000
 
char 157
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 158
width 6
000000
000000
010010
001100
000000
111110
000100
001000
010000
100000
111110
000000
000000
 
char 159
width 6
000000
010100
010100
000000
100010
010100
010100
001000
001000
001000
001000
000000
000000
 
char 160
width 6
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
000000
 
char 161
width 9
000000000
000000000
000000000
010000010
001000100
000101000
000010000
000101000
001000100
010000010
000000000
000000000
000000000
 
char 162
width 9
000000000
000000000
000000000
000111000
001000100
010000010
010000010
010000010
001000100
000111000
000000000
000000000
000000000
 
char 163
width 10
0000000000
0000000000
0000000000
0000000000
0000100000
0001010000
0010001000
0100000100
1111111110
0000000000
0000000000
0000000000
0000000000
 
char 164
width 9
000000000
000000000
000000000
011111110
010000010
010000010
010000010
010000010
010000010
011111110
000000000
000000000
000000000
 
char 165
width 10
0000000000
0000000000
0111111110
0100000010
0100000010
0100110010
0101111010
0100000010
0010000100
0001001000
0000110000
0000000000
0000000000
 
char 166
width 10
0000000000
0000000000
0000110000
0001001000
0010000100
0100000010
0101111010
0100110010
0100000010
0100000010
0111111110
0000000000
0000000000
 
char 167
width 11
00000000000
00000000000
00000000000
01111110000
01000001000
01001000100
01011000010
01011000010
01001000100
01000001000
01111110000
00000000000
00000000000
 
char 168
width 11
00000000000
00000000000
00000000000
00001111110
00010000010
00100010010
01000011010
01000011010
00100010010
00010000010
00001111110
00000000000
00000000000
 
char 169
width 10
0000000000
0000000000
0011111000
0100000100
1000100010
1001110010
1010101010
1000100010
1000100010
0100000100
0011111000
0000000000
0000000000
 
char 170
width 10
0000000000
0000000000
0011111000
0100000100
1000100010
1000100010
1010101010
1001110010
1000100010
0100000100
0011111000
0000000000
0000000000
 
char 171
width 10
0000000000
0000000000
0011111000
0100000100
1000100010
1001000010
1011111010
1001000010
1000100010
0100000100
0011111000
0000000000
0000000000
 
char 172
width 10
0000000000
0000000000
0011111000
0100000100
1000100010
1000010010
1011111010
1000010010
1000100010
0100000100
0011111000
0000000000
0000000000
 
char 173
width 16
0000000000000000
0000000000000000
1111111111111110
1000000000000010
1000010000000010
1000010000000010
1000010000000010
1000010000000010
1000011111000010
1000000000000010
1111111111111110
0000000000000000
0000000000000000
 
char 174
width 16
0000000000000000
0000000000000000
1111111111111110
1000000000000010
1000011110000010
1000010001000010
1000011110000010
1000010001000010
1000010001000010
1000000000000010
1111111111111110
0000000000000000
0000000000000000
 
char 175
width 16
0000000000000000
0000000000000000
0000000000000000
0110111010001110
1000100010001000
1000100010001000
0100110010001100
0010100010001000
0010100010001000
1100111011101110
0000000000000000
0000000000000000
0000000000000000
 
char 176
width 8
00000000
00000000
00000000
01101110
10000100
10000100
10000100
10000100
10000100
01100100
00000000
00000000
00000000
 
char 177
width 16
0000000000000000
0000000000000000
0000000000000000
0110111001001100
1000010010101010
1000010010101010
0100010011101100
0010010010101010
0010010010101010
1100010010101010
0000000000000000
0000000000000000
0000000000000000
 
char 178
width 4
0000
0000
0000
1110
0100
0100
0100
0100
0100
0100
0000
0000
0000
 
char 179
width 15
000000000000000
000000000000000
001111111111110
001000000000010
001011011011010
111011011011010
111011011011010
111011011011010
001011011011010
001000000000010
001111111111110
000000000000000
000000000000000
 
char 180
width 15
000000000000000
000000000000000
001111111111110
001000000000010
001000011011010
111000011011010
111000011011010
111000011011010
001000011011010
001000000000010
001111111111110
000000000000000
000000000000000
 
char 181
width 15
000000000000000
000000000000000
001111111111110
001000000000010
001000000011010
111000000011010
111000000011010
111000000011010
001000000011010
001000000000010
001111111111110
000000000000000
000000000000000
 
char 182
width 15
000000000000000
000000000000000
001111111111110
001000000000010
001000000000010
111000000000010
111000000000010
111000000000010
001000000000010
001000000000010
001111111111110
000000000000000
000000000000000
 
char 183
width 9
000000000
001000100
001000100
011111110
010000010
010000010
001000100
000111000
000010000
000001000
000000110
000000000
000000000
 
char 184
width 10
0000000000
0000000000
0011111000
0100000100
1000100010
1000100010
1000111010
1000000010
1000000010
0100000100
0011111000
0000000000
0000000000
 
char 185
width 15
000000000000000
000000000000000
111111111111110
100000000000010
100000000000010
100000000000010
100100000000010
101100000000010
100100000000010
010000000000010
001111111111110
000000000000000
000000000000000
 
char 186
width 6
000000
000000
001000
011100
101010
001000
001000
001000
001000
001000
001000
000000
000000
 
char 187
width 6
000000
000000
001000
001000
001000
001000
001000
001000
101010
011100
001000
000000
000000
 
char 188
width 10
0000000000
0000000000
1111111100
1011101010
1011101010
1011111010
1000000010
1011111010
1011111010
1011111010
1111111110
0000000000
0000000000
 
char 189
width 6
000000
000000
000000
000000
001000
001000
111110
011100
110110
100010
000000
000000
000000
 
char 190
width 6
000000
010000
101000
010000
001000
101000
010010
000110
001010
001110
000010
000000
000000
 
char 191
width 6
000000
000000
001000
000000
001000
001000
010000
100000
100010
100010
011100
000000
000000
 
char 192
width 6
000000
010000
001000
000000
001000
010100
100010
100010
111110
100010
100010
000000
000000
 
char 193
width 6
000000
000100
001000
000000
001000
010100
100010
100010
111110
100010
100010
000000
000000
 
char 194
width 6
000000
001100
010010
000000
001000
010100
100010
100010
111110
100010
100010
000000
000000
 
char 195
width 6
000000
001010
010100
000000
001000
010100
100010
100010
111110
100010
100010
000000
000000
 
char 196
width 6
000000
010100
010100
000000
001000
010100
100010
100010
111110
100010
100010
000000
000000
 
char 197
width 6
000000
001000
010100
001000
001000
010100
100010
100010
111110
100010
100010
000000
000000
 
char 198
width 6
000000
000000
010110
101000
101000
101000
101100
111000
101000
101000
101110
000000
000000
 
char 199
width 6
000000
000000
011100
100010
100000
100000
100000
100000
100000
100010
011100
001000
010000
 
char 200
width 6
000000
010000
001000
000000
111110
100000
100000
111100
100000
100000
111110
000000
000000
 
char 201
width 6
000000
000100
001000
000000
111110
100000
100000
111100
100000
100000
111110
000000
000000
 
char 202
width 6
000000
001100
010010
000000
111110
100000
100000
111100
100000
100000
111110
000000
000000
 
char 203
width 6
000000
010100
010100
000000
111110
100000
100000
111100
100000
100000
111110
000000
000000
 
char 204
width 6
000000
010000
001000
000000
011100
001000
001000
001000
001000
001000
011100
000000
000000
 
char 205
width 6
000000
000100
001000
000000
011100
001000
001000
001000
001000
001000
011100
000000
000000
 
char 206
width 6
000000
001100
010010
000000
011100
001000
001000
001000
001000
001000
011100
000000
000000
 
char 207
width 6
000000
010100
010100
000000
011100
001000
001000
001000
001000
001000
011100
000000
000000
 
char 208
width 6
000000
000000
111100
010010
010010
010010
111010
010010
010010
010010
111100
000000
000000
 
char 209
width 6
000000
001010
010100
000000
100010
100010
110010
101010
100110
100010
100010
000000
000000
 
char 210
width 6
000000
010000
001000
000000
011100
100010
100010
100010
100010
100010
011100
000000
000000
 
char 211
width 6
000000
000100
001000
000000
011100
100010
100010
100010
100010
100010
011100
000000
000000
 
char 212
width 6
000000
001100
010010
000000
011100
100010
100010
100010
100010
100010
011100
000000
000000
 
char 213
width 6
000000
001010
010100
000000
011100
100010
100010
100010
100010
100010
011100
000000
000000
 
char 214
width 6
000000
010100
010100
000000
011100
100010
100010
100010
100010
100010
011100
000000
000000
 
char 215
width 6
000000
000000
000000
000000
000000
100010
010100
001000
010100
100010
000000
000000
000000
 
char 216
width 6
000000
000010
011100
100110
100110
101010
101010
101010
110010
110010
011100
100000
000000
 
char 217
width 6
000000
010000
001000
000000
100010
100010
100010
100010
100010
100010
011100
000000
000000
 
char 218
width 6
000000
000100
001000
000000
100010
100010
100010
100010
100010
100010
011100
000000
000000
 
char 219
width 6
000000
001100
010010
000000
100010
100010
100010
100010
100010
100010
011100
000000
000000
 
char 220
width 6
000000
010100
010100
000000
100010
100010
100010
100010
100010
100010
011100
000000
000000
 
char 221
width 6
000000
000100
001000
000000
100010
100010
010100
001000
001000
001000
001000
000000
000000
 
char 222
width 6
000000
000000
100000
111100
100010
100010
100010
111100
100000
100000
100000
000000
000000
 
char 223
width 6
000000
000000
011000
100100
100100
101000
101000
100100
100010
100010
101100
000000
000000
 
char 224
width 6
000000
000000
010000
001000
000000
011100
000010
011110
100010
100110
011010
000000
000000
 
char 225
width 6
000000
000000
000100
001000
000000
011100
000010
011110
100010
100110
011010
000000
000000
 
char 226
width 6
000000
000000
001100
010010
000000
011100
000010
011110
100010
100110
011010
000000
000000
 
char 227
width 6
000000
000000
001010
010100
000000
011100
000010
011110
100010
100110
011010
000000
000000
 
char 228
width 6
000000
000000
010100
010100
000000
011100
000010
011110
100010
100110
011010
000000
000000
 
char 229
width 6
000000
001100
010010
001100
000000
011100
000010
011110
100010
100110
011010
000000
000000
 
char 230
width 6
000000
000000
000000
000000
000000
011100
001010
011100
101000
101010
010100
000000
000000
 
char 231
width 6
000000
000000
000000
000000
000000
011100
100010
100000
100000
100010
011100
001000
010000
 
char 232
width 6
000000
000000
010000
001000
000000
011100
100010
111110
100000
100010
011100
000000
000000
 
char 233
width 6
000000
000000
000100
001000
000000
011100
100010
111110
100000
100010
011100
000000
000000
 
char 234
width 6
000000
000000
001100
010010
000000
011100
100010
111110
100000
100010
011100
000000
000000
 
char 235
width 6
000000
000000
010100
010100
000000
011100
100010
111110
100000
100010
011100
000000
000000
 
char 236
width 6
000000
000000
010000
001000
000000
011000
001000
001000
001000
001000
011100
000000
000000
 
char 237
width 6
000000
000000
000100
001000
000000
011000
001000
001000
001000
001000
011100
000000
000000
 
char 238
width 6
000000
000000
001100
010010
000000
011000
001000
001000
001000
001000
011100
000000
000000
 
char 239
width 6
000000
000000
010100
010100
000000
011000
001000
001000
001000
001000
011100
000000
000000
 
char 240
width 6
000000
010100
001000
011000
000100
011100
100010
100010
100010
100010
011100
000000
000000
 
char 241
width 6
000000
000000
001010
010100
000000
101100
110010
100010
100010
100010
100010
000000
000000
 
char 242
width 6
000000
000000
010000
001000
000000
011100
100010
100010
100010
100010
011100
000000
000000
 
char 243
width 6
000000
000000
000100
001000
000000
011100
100010
100010
100010
100010
011100
000000
000000
 
char 244
width 6
000000
000000
001100
010010
000000
011100
100010
100010
100010
100010
011100
000000
000000
 
char 245
width 6
000000
000000
001010
010100
000000
011100
100010
100010
100010
100010
011100
000000
000000
 
char 246
width 6
000000
000000
010100
010100
000000
011100
100010
100010
100010
100010
011100
000000
000000
 
char 247
width 6
000000
000000
000000
001000
001000
000000
111110
000000
001000
001000
000000
000000
000000
 
char 248
width 6
000000
000000
000000
000000
000010
011100
100110
101010
101010
110010
011100
100000
000000
 
char 249
width 6
000000
000000
010000
001000
000000
100010
100010
100010
100010
100110
011010
000000
000000
 
char 250
width 6
000000
000000
000100
001000
000000
100010
100010
100010
100010
100110
011010
000000
000000
 
char 251
width 6
000000
000000
001100
010010
000000
100010
100010
100010
100010
100110
011010
000000
000000
 
char 252
width 6
000000
000000
010100
010100
000000
100010
100010
100010
100010
100110
011010
000000
000000
 
char 253
width 6
000000
000000
000100
001000
000000
100010
100010
100010
100110
011010
000010
100010
011100
 
char 254
width 6
000000
000000
000000
100000
100000
101100
110010
100010
100010
110010
101100
100000
100000
 
char 255
width 6
000000
000000
010100
010100
000000
100010
100010
100010
100110
011010
000010
100010
011100
 
/race/2.15/psp/psplib/COPYING
0,0 → 1,674
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
 
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
 
Preamble
 
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
 
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
 
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
 
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
 
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
 
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
 
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
 
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
 
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
 
The precise terms and conditions for copying, distribution and
modification follow.
 
TERMS AND CONDITIONS
 
0. Definitions.
 
"This License" refers to version 3 of the GNU General Public License.
 
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
 
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
 
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
 
A "covered work" means either the unmodified Program or a work based
on the Program.
 
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
 
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
 
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
 
1. Source Code.
 
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
 
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
 
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
 
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
 
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
 
The Corresponding Source for a work in source code form is that
same work.
 
2. Basic Permissions.
 
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
 
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
 
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
 
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
 
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
 
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
 
4. Conveying Verbatim Copies.
 
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
 
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
 
5. Conveying Modified Source Versions.
 
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
 
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
 
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
 
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
 
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
 
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
 
6. Conveying Non-Source Forms.
 
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
 
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
 
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
 
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
 
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
 
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
 
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
 
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
 
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
 
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
 
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
 
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
 
7. Additional Terms.
 
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
 
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
 
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
 
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
 
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
 
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
 
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
 
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
 
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
 
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
 
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
 
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
 
8. Termination.
 
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
 
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
 
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
 
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
 
9. Acceptance Not Required for Having Copies.
 
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
 
10. Automatic Licensing of Downstream Recipients.
 
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
 
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
 
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
 
11. Patents.
 
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
 
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
 
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
 
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
 
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
 
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
 
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
 
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
 
12. No Surrender of Others' Freedom.
 
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
 
13. Use with the GNU Affero General Public License.
 
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
 
14. Revised Versions of this License.
 
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
 
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
 
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
 
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
 
15. Disclaimer of Warranty.
 
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 
16. Limitation of Liability.
 
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
 
17. Interpretation of Sections 15 and 16.
 
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
 
END OF TERMS AND CONDITIONS
 
How to Apply These Terms to Your New Programs
 
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
 
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
 
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Also add information on how to contact you by electronic and paper mail.
 
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
 
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
 
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
 
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
 
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
/race/2.15/psp/psplib/image.h
0,0 → 1,81
/* psplib/image.h
Image manipulation/saving/loading
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#ifndef _PSP_IMAGE_H
#define _PSP_IMAGE_H
 
#ifdef __cplusplus
extern "C" {
#endif
 
#include <stdio.h>
 
#define PSP_IMAGE_INDEXED 8
#define PSP_IMAGE_16BPP 16
 
typedef struct
{
int X;
int Y;
int Width;
int Height;
} PspViewport;
 
typedef struct
{
int Width;
int Height;
void *Pixels;
PspViewport Viewport;
char FreeBuffer;
char BytesPerPixel;
char Depth;
char PowerOfTwo;
unsigned int TextureFormat;
/* TODO: don't allocate if not necessary */
unsigned short __attribute__((aligned(16))) Palette[256];
unsigned short PalSize;
} PspImage;
 
/* Create/destroy */
PspImage* pspImageCreate(int width, int height, int bits_per_pixel);
PspImage* pspImageCreateVram(int width, int height, int bits_per_pixel);
PspImage* pspImageCreateOptimized(int width, int height, int bpp);
void pspImageDestroy(PspImage *image);
 
PspImage* pspImageRotate(const PspImage *orig, int angle_cw);
PspImage* pspImageCreateThumbnail(const PspImage *image);
PspImage* pspImageCreateCopy(const PspImage *image);
void pspImageClear(PspImage *image, unsigned int color);
 
PspImage* pspImageLoadPng(const char *path);
int pspImageSavePng(const char *path, const PspImage* image);
PspImage* pspImageLoadPngFd(FILE *fp);
int pspImageSavePngFd(FILE *fp, const PspImage* image);
 
int pspImageBlur(const PspImage *original, PspImage *blurred);
int pspImageDiscardColors(const PspImage *original);
 
#ifdef __cplusplus
}
#endif
 
#endif // _PSP_IMAGE_H
/race/2.15/psp/psplib/Makefile
0,0 → 1,98
## Makefile for psplib library
## Copyright (C) 2008 Akop Karapetyan
 
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
 
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
 
## Author contact information: pspdev@akop.org
 
ifndef PSP_FW_VERSION
PSP_FW_VERSION=200
endif
 
CC=psp-gcc
AR=psp-ar
RANLIB=psp-ranlib
RM=rm -rf
PSPSDK=$(shell psp-config --pspsdk-path)
CFLAGS=-G0 -Wall -I$(PSPSDK)/include
DEFINES=-DPSP -D_PSP_FW_VERSION=$(PSP_FW_VERSION)
 
all: libpsplib.a
 
libpsplib.a: \
adhoc.o font.o image.o ctrl.o video.o ui.o \
pl_ini.o pl_perf.o pl_vk.o pl_util.o pl_image.o \
pl_psp.o pl_menu.o pl_file.o pl_snd.o pl_gfx.o
 
$(AR) cru $@ $?
$(RANLIB) $@
@echo Compiled for firmware $(PSP_FW_VERSION)
 
clean:
$(RM) *.o genfont stockfont.h *.a
 
font.o: font.c font.h stockfont.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
video.o: video.c video.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
ctrl.o: ctrl.c ctrl.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
adhoc.o: adhoc.c adhoc.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
ui.o: ui.c ui.h pl_file.o pl_psp.o \
ctrl.o font.o pl_menu.o video.o \
adhoc.o
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_snd.o: pl_snd.c pl_snd.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_psp.o: pl_psp.c pl_psp.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_ini.o: pl_ini.c pl_ini.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_vk.o: pl_vk.c pl_vk.h video.o font.o \
ctrl.o
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_util.o: pl_util.c pl_util.h image.o \
pl_file.o video.o
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_perf.o: pl_perf.c pl_perf.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_menu.o: pl_menu.c pl_menu.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_file.o: pl_file.c pl_file.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_image.o: pl_image.c pl_image.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
pl_gfx.o: pl_gfx.c pl_gfx.h
$(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $<
 
stockfont.h: stockfont.fd genfont
./genfont < $< > $@
 
genfont: genfont.c
cc $< -o $@
/race/2.15/psp/psplib/pl_psp.c
0,0 → 1,127
/* psplib/pl_psp.c
Platform init/shutdown and various system routines
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include <pspkernel.h>
#include <psppower.h>
#include <malloc.h>
#include <string.h>
 
#include "pl_psp.h"
 
typedef struct pl_psp_callback_t
{
void (*handler)(void *param);
void *param;
} pl_psp_callback;
 
static char _app_directory[1024];
static pl_psp_callback _exit_callback;
int ExitPSP;
 
static int _callback_thread(SceSize args, void* argp);
static int _callback(int arg1, int arg2, void* common);
 
int pl_psp_init(const char *app_path)
{
ExitPSP = 0;
 
char *pos;
if (!(pos = strrchr(app_path, '/')))
_app_directory[0] = '\0';
else
{
strncpy(_app_directory, app_path, pos - app_path + 1);
_app_directory[pos - app_path + 1] = '\0';
}
 
_exit_callback.handler = NULL;
_exit_callback.param = NULL;
 
return 1;
}
 
const char* pl_psp_get_app_directory()
{
return _app_directory;
}
 
void pl_psp_shutdown()
{
sceKernelExitGame();
}
 
void pl_psp_set_clock_freq(int freq)
{
if (freq < 222) freq = 222;
else if (freq > 333) freq = 333;
scePowerSetClockFrequency(freq, freq, freq/2);
}
 
static int _callback(int arg1, int arg2, void* common)
{
pl_psp_callback *callback = (pl_psp_callback*)common;
callback->handler(callback->param);
 
return 0;
}
 
static int _callback_thread(SceSize args, void* argp)
{
int cbid;
 
if (_exit_callback.handler)
{
cbid = sceKernelCreateCallback("Exit Callback", _callback, &_exit_callback);
sceKernelRegisterExitCallback(cbid);
}
 
sceKernelSleepThreadCB();
return 0;
}
 
int pl_psp_register_callback(pl_callback_type type,
void (*func)(void *param),
void *param)
{
switch (type)
{
case PSP_EXIT_CALLBACK:
_exit_callback.handler = func;
_exit_callback.param = param;
break;
default:
return 0;
}
 
return 1;
}
 
int pl_psp_start_callback_thread()
{
int thid;
 
if ((thid = sceKernelCreateThread("update_thread", _callback_thread, 0x11, 0xFA0, 0, 0)) < 0)
return 0;
 
sceKernelStartThread(thid, 0, NULL);
 
return thid;
}
/race/2.15/psp/psplib/pl_menu.c
0,0 → 1,351
/* psplib/pl_menu.c
Simple menu implementation
 
Copyright (C) 2007-2008 Akop Karapetyan
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
 
Author contact information: pspdev@akop.org
*/
 
#include <malloc.h>
#include <string.h>
 
#include "pl_menu.h"
 
static void
destroy_item(pl_menu_item *item);
static pl_menu_item*
find_last_item(const pl_menu *menu);
static pl_menu_option*
find_last_option(const pl_menu_item *item);
 
int pl_menu_create(pl_menu *menu,
const pl_menu_def *def)
{
menu->items = NULL;
menu->selected = NULL;
 
/* No definition; nothing more to do */
if (!def) return 1;
 
pl_menu_item *item;
 
/* Initialize menu */
for (; def->id || def->caption; def++)
{
/* Append the item */
item = pl_menu_append_item(menu,
def->id,
def->caption);
 
if (item)
{
/* Add the options */
if (def->options)
{
const pl_menu_option_def *option_def;
for (option_def = def->options; option_def->text; option_def++)
pl_menu_append_option(item,
option_def->text,
option_def->value, 0);
}
 
/* Set help text */
item->help_text = (def->help_text)
? strdup(def->help_text) : NULL;
}
}
 
return 1;
}
 
void pl_menu_destroy(pl_menu *menu)
{
pl_menu_clear_items(menu);
}
 
void pl_menu_clear_items(pl_menu *menu)
{
pl_menu_item *item, *next;
 
for (item = menu->items; item; item = next)
{
next = item->next;
destroy_item(item);
}
 
menu->items = NULL;
menu->selected = NULL;
}
 
int pl_menu_remove_item(pl_menu *menu,
pl_menu_item *which)
{
pl_menu_item *item;
int found = 0;
 
/* Make sure the item is in the menu */
for (item = menu->items; item; item = item->next)
if (item == which)
{ found = 1; break; }
if (!found) return 0;
 
/* Redirect pointers */
if (item->prev)
item->prev->next = item->next;
else
menu->items = item->next;
 
if (item->next)
item->next->prev = item->prev;
 
if (menu->selected == item)
menu->selected = item->next;
 
/* Destroy the item */
destroy_item(item);
 
return 1;
}
 
static void destroy_item(pl_menu_item *item)
{
if (item->caption)
free(item->caption);
if (item->help_text)
free(item->help_text);
 
pl_menu_clear_options(item);
free(item);
}
 
void pl_menu_clear_options(pl_menu_item *item)
{
pl_menu_option *option, *next;
 
for (option = item->options; option; option = next)
{
next = option->next;
free(option->text);
free(option);
}
 
item->selected = NULL;
item->options = NULL;
}
 
static pl_menu_item* find_last_item(const pl_menu *menu)
{
if (!menu->items)
return NULL;
 
pl_menu_item *item;
for (item = menu->items; item->next; item = item->next);
 
return item;
}
 
static pl_menu_option* find_last_option(const pl_menu_item *item)
{
if (!item->options)
return NULL;
 
pl_menu_option *option;
for (option = item->options; option->next; option = option->next);
 
return option;
}
 
pl_menu_item* pl_menu_append_item(pl_menu *menu,