Remove 'need_fullpath' requirement when using frontends with 'RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE' support

This commit is contained in:
jdgleaver 2021-06-11 11:32:43 +01:00
parent 00a7e82e59
commit 7219ac8aa9
7 changed files with 795 additions and 35 deletions

View File

@ -138,9 +138,20 @@ void retro_deinit(void)
void retro_set_environment(retro_environment_t cb) void retro_set_environment(retro_environment_t cb)
{ {
static const struct retro_system_content_info_override content_overrides[] = {
{
RACE_EXTENSIONS, /* extensions */
false, /* need_fullpath */
false /* persistent_data */
},
{ NULL, false, false }
};
environ_cb = cb; environ_cb = cb;
libretro_set_core_options(environ_cb); libretro_set_core_options(environ_cb);
environ_cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE,
(void*)content_overrides);
} }
void retro_set_audio_sample(retro_audio_sample_t cb) void retro_set_audio_sample(retro_audio_sample_t cb)
@ -202,11 +213,13 @@ static bool race_initialize_sound(void)
return true; return true;
} }
static bool race_initialize_system(const char* gamepath) static bool race_initialize_system(const char *gamepath,
const unsigned char *gamedata, size_t gamesize)
{ {
mainemuinit(); mainemuinit();
if(!handleInputFile((char *)gamepath)){ if (!handleInputFile(gamepath, gamedata, (int)gamesize))
{
handle_error("ERROR handleInputFile"); handle_error("ERROR handleInputFile");
return false; return false;
} }
@ -298,8 +311,10 @@ bool retro_unserialize(const void *data, size_t size)
bool retro_load_game(const struct retro_game_info *info) bool retro_load_game(const struct retro_game_info *info)
{ {
if (!info) const struct retro_game_info_ext *info_ext = NULL;
return false; const unsigned char *content_data = NULL;
size_t content_size = 0;
char content_path[_MAX_PATH];
struct retro_input_descriptor desc[] = { struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
@ -313,6 +328,44 @@ bool retro_load_game(const struct retro_game_info *info)
{ 0 }, { 0 },
}; };
content_path[0] = '\0';
/* Attempt to fetch extended game info */
if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &info_ext))
{
content_data = (const unsigned char *)info_ext->data;
content_size = info_ext->size;
if (info_ext->file_in_archive)
{
/* We don't have a 'physical' file in this
* case, but the core still needs a filename
* in order to build the save file path.
* We therefore fake it, using the content
* directory, canonical content name, and
* content file extension */
snprintf(content_path, sizeof(content_path), "%s%c%s.%s",
info_ext->dir, path_default_slash_c(),
info_ext->name, info_ext->ext);
}
else
{
strncpy(content_path, info_ext->full_path, sizeof(content_path));
content_path[sizeof(content_path) - 1] = '\0';
}
}
else
{
if (!info || !info->path)
return false;
content_data = NULL;
content_size = 0;
strncpy(content_path, info->path, sizeof(content_path));
content_path[sizeof(content_path) - 1] = '\0';
}
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
screen = (struct ngp_screen*)calloc(1, sizeof(*screen)); screen = (struct ngp_screen*)calloc(1, sizeof(*screen));
@ -331,7 +384,8 @@ bool retro_load_game(const struct retro_game_info *info)
return false; return false;
} }
if (!race_initialize_system(info->path)) if (!race_initialize_system(content_path,
content_data, content_size))
return false; return false;
if (!race_initialize_sound()) if (!race_initialize_sound())

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team /* Copyright (C) 2010-2020 The RetroArch team
* *
* --------------------------------------------------------------------------------------- * ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro API header (libretro.h). * The following license statement only applies to this libretro API header (libretro.h).
@ -278,6 +278,11 @@ enum retro_language
RETRO_LANGUAGE_ARABIC = 16, RETRO_LANGUAGE_ARABIC = 16,
RETRO_LANGUAGE_GREEK = 17, RETRO_LANGUAGE_GREEK = 17,
RETRO_LANGUAGE_TURKISH = 18, RETRO_LANGUAGE_TURKISH = 18,
RETRO_LANGUAGE_SLOVAK = 19,
RETRO_LANGUAGE_PERSIAN = 20,
RETRO_LANGUAGE_HEBREW = 21,
RETRO_LANGUAGE_ASTURIAN = 22,
RETRO_LANGUAGE_FINNISH = 23,
RETRO_LANGUAGE_LAST, RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */ /* Ensure sizeof(enum) == sizeof(int) */
@ -708,6 +713,9 @@ enum retro_mod
* state of rumble motors in controllers. * state of rumble motors in controllers.
* A strong and weak motor is supported, and they can be * A strong and weak motor is supported, and they can be
* controlled indepedently. * controlled indepedently.
* Should be called from either retro_init() or retro_load_game().
* Should not be called from retro_set_environment().
* Returns false if rumble functionality is unavailable.
*/ */
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 #define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
/* uint64_t * -- /* uint64_t * --
@ -1087,10 +1095,10 @@ enum retro_mod
#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL) #define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* float * -- /* float * --
* Float value that lets us know what target refresh rate * Float value that lets us know what target refresh rate
* is curently in use by the frontend. * is curently in use by the frontend.
* *
* The core can use the returned value to set an ideal * The core can use the returned value to set an ideal
* refresh rate/framerate. * refresh rate/framerate.
*/ */
@ -1098,7 +1106,7 @@ enum retro_mod
/* bool * -- /* bool * --
* Boolean value that indicates whether or not the frontend supports * Boolean value that indicates whether or not the frontend supports
* input bitmasks being returned by retro_input_state_t. The advantage * input bitmasks being returned by retro_input_state_t. The advantage
* of this is that retro_input_state_t has to be only called once to * of this is that retro_input_state_t has to be only called once to
* grab all button states instead of multiple times. * grab all button states instead of multiple times.
* *
* If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id' * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id'
@ -1117,7 +1125,7 @@ enum retro_mod
* This may be still be done regardless of the core options * This may be still be done regardless of the core options
* interface version. * interface version.
* *
* If version is 1 however, core options may instead be set by * If version is >= 1 however, core options may instead be set by
* passing an array of retro_core_option_definition structs to * passing an array of retro_core_option_definition structs to
* RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
* retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
@ -1132,8 +1140,8 @@ enum retro_mod
* GET_VARIABLE. * GET_VARIABLE.
* This allows the frontend to present these variables to * This allows the frontend to present these variables to
* a user dynamically. * a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of 1. * returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as * This should be called the first time as early as
* possible (ideally in retro_set_environment). * possible (ideally in retro_set_environment).
@ -1169,8 +1177,6 @@ enum retro_mod
* i.e. it should be feasible to cycle through options * i.e. it should be feasible to cycle through options
* without a keyboard. * without a keyboard.
* *
* First entry should be treated as a default.
*
* Example entry: * Example entry:
* { * {
* "foo_option", * "foo_option",
@ -1196,8 +1202,8 @@ enum retro_mod
* GET_VARIABLE. * GET_VARIABLE.
* This allows the frontend to present these variables to * This allows the frontend to present these variables to
* a user dynamically. * a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of 1. * returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as * This should be called the first time as early as
* possible (ideally in retro_set_environment). * possible (ideally in retro_set_environment).
@ -1257,7 +1263,236 @@ enum retro_mod
* *
* 'data' points to an unsigned variable * 'data' points to an unsigned variable
*/ */
#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57
/* unsigned * --
* Unsigned value is the API version number of the disk control
* interface supported by the frontend. If callback return false,
* API version is assumed to be 0.
*
* In legacy code, the disk control interface is defined by passing
* a struct of type retro_disk_control_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
* This may be still be done regardless of the disk control
* interface version.
*
* If version is >= 1 however, the disk control interface may
* instead be defined by passing a struct of type
* retro_disk_control_ext_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* This allows the core to provide additional information about
* disk images to the frontend and/or enables extra
* disk control functionality by the frontend.
*/
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58
/* const struct retro_disk_control_ext_callback * --
* Sets an interface which frontend can use to eject and insert
* disk images, and also obtain information about individual
* disk image files registered by the core.
* This is used for games which consist of multiple images and
* must be manually swapped out by the user (e.g. PSX, floppy disk
* based systems).
*/
#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59
/* unsigned * --
* Unsigned value is the API version number of the message
* interface supported by the frontend. If callback returns
* false, API version is assumed to be 0.
*
* In legacy code, messages may be displayed in an
* implementation-specific manner by passing a struct
* of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE.
* This may be still be done regardless of the message
* interface version.
*
* If version is >= 1 however, messages may instead be
* displayed by passing a struct of type retro_message_ext
* to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the
* core to specify message logging level, priority and
* destination (OSD, logging interface or both).
*/
#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60
/* const struct retro_message_ext * --
* Sets a message to be displayed in an implementation-specific
* manner for a certain amount of 'frames'. Additionally allows
* the core to specify message logging level, priority and
* destination (OSD, logging interface or both).
* Should not be used for trivial messages, which should simply be
* logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
* fallback, stderr).
*/
#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61
/* unsigned * --
* Unsigned value is the number of active input devices
* provided by the frontend. This may change between
* frames, but will remain constant for the duration
* of each frame.
* If callback returns true, a core need not poll any
* input device with an index greater than or equal to
* the number of active devices.
* If callback returns false, the number of active input
* devices is unknown. In this case, all input devices
* should be considered active.
*/
#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62
/* const struct retro_audio_buffer_status_callback * --
* Lets the core know the occupancy level of the frontend
* audio buffer. Can be used by a core to attempt frame
* skipping in order to avoid buffer under-runs.
* A core may pass NULL to disable buffer status reporting
* in the frontend.
*/
#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63
/* const unsigned * --
* Sets minimum frontend audio latency in milliseconds.
* Resultant audio latency may be larger than set value,
* or smaller if a hardware limit is encountered. A frontend
* is expected to honour requests up to 512 ms.
*
* - If value is less than current frontend
* audio latency, callback has no effect
* - If value is zero, default frontend audio
* latency is set
*
* May be used by a core to increase audio latency and
* therefore decrease the probability of buffer under-runs
* (crackling) when performing 'intensive' operations.
* A core utilising RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
* to implement audio-buffer-based frame skipping may achieve
* optimal results by setting the audio latency to a 'high'
* (typically 6x or 8x) integer multiple of the expected
* frame time.
*
* WARNING: This can only be called from within retro_run().
* Calling this can require a full reinitialization of audio
* drivers in the frontend, so it is important to call it very
* sparingly, and usually only with the users explicit consent.
* An eventual driver reinitialize will happen so that audio
* callbacks happening after this call within the same retro_run()
* call will target the newly initialized driver.
*/
#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64
/* const struct retro_fastforwarding_override * --
* Used by a libretro core to override the current
* fastforwarding mode of the frontend.
* If NULL is passed to this function, the frontend
* will return true if fastforwarding override
* functionality is supported (no change in
* fastforwarding state will occur in this case).
*/
#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65
/* const struct retro_system_content_info_override * --
* Allows an implementation to override 'global' content
* info parameters reported by retro_get_system_info().
* Overrides also affect subsystem content info parameters
* set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.
* This function must be called inside retro_set_environment().
* If callback returns false, content info overrides
* are unsupported by the frontend, and will be ignored.
* If callback returns true, extended game info may be
* retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
* in retro_load_game() or retro_load_game_special().
*
* 'data' points to an array of retro_system_content_info_override
* structs terminated by a { NULL, false, false } element.
* If 'data' is NULL, no changes will be made to the frontend;
* a core may therefore pass NULL in order to test whether
* the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
* RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported
* by the frontend.
*
* For struct member descriptions, see the definition of
* struct retro_system_content_info_override.
*
* Example:
*
* - struct retro_system_info:
* {
* "My Core", // library_name
* "v1.0", // library_version
* "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
* true, // need_fullpath
* false // block_extract
* }
*
* - Array of struct retro_system_content_info_override:
* {
* {
* "md|sms|gg", // extensions
* false, // need_fullpath
* true // persistent_data
* },
* {
* "sg", // extensions
* false, // need_fullpath
* false // persistent_data
* },
* { NULL, false, false }
* }
*
* Result:
* - Files of type m3u, cue, iso, chd will not be
* loaded by the frontend. Frontend will pass a
* valid path to the core, and core will handle
* loading internally
* - Files of type md, sms, gg will be loaded by
* the frontend. A valid memory buffer will be
* passed to the core. This memory buffer will
* remain valid until retro_deinit() returns
* - Files of type sg will be loaded by the frontend.
* A valid memory buffer will be passed to the core.
* This memory buffer will remain valid until
* retro_load_game() (or retro_load_game_special())
* returns
*
* NOTE: If an extension is listed multiple times in
* an array of retro_system_content_info_override
* structs, only the first instance will be registered
*/
#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66
/* const struct retro_game_info_ext ** --
* Allows an implementation to fetch extended game
* information, providing additional content path
* and memory buffer status details.
* This function may only be called inside
* retro_load_game() or retro_load_game_special().
* If callback returns false, extended game information
* is unsupported by the frontend. In this case, only
* regular retro_game_info will be available.
* RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed
* to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
* returns true.
*
* 'data' points to an array of retro_game_info_ext structs.
*
* For struct member descriptions, see the definition of
* struct retro_game_info_ext.
*
* - If function is called inside retro_load_game(),
* the retro_game_info_ext array is guaranteed to
* have a size of 1 - i.e. the returned pointer may
* be used to access directly the members of the
* first retro_game_info_ext struct, for example:
*
* struct retro_game_info_ext *game_info_ext;
* if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext))
* printf("Content Directory: %s\n", game_info_ext->dir);
*
* - If the function is called inside retro_load_game_special(),
* the retro_game_info_ext array is guaranteed to have a
* size equal to the num_info argument passed to
* retro_load_game_special()
*/
/* VFS functionality */ /* VFS functionality */
/* File paths: /* File paths:
@ -2147,6 +2382,30 @@ struct retro_frame_time_callback
retro_usec_t reference; retro_usec_t reference;
}; };
/* Notifies a libretro core of the current occupancy
* level of the frontend audio buffer.
*
* - active: 'true' if audio buffer is currently
* in use. Will be 'false' if audio is
* disabled in the frontend
*
* - occupancy: Given as a value in the range [0,100],
* corresponding to the occupancy percentage
* of the audio buffer
*
* - underrun_likely: 'true' if the frontend expects an
* audio buffer underrun during the
* next frame (indicates that a core
* should attempt frame skipping)
*
* It will be called right before retro_run() every frame. */
typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
bool active, unsigned occupancy, bool underrun_likely);
struct retro_audio_buffer_status_callback
{
retro_audio_buffer_status_callback_t callback;
};
/* Pass this to retro_video_refresh_t if rendering to hardware. /* Pass this to retro_video_refresh_t if rendering to hardware.
* Passing NULL to retro_video_refresh_t is still a frame dupe as normal. * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
* */ * */
@ -2307,7 +2566,8 @@ struct retro_keyboard_callback
retro_keyboard_event_t callback; retro_keyboard_event_t callback;
}; };
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. /* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE &
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* Should be set for implementations which can swap out multiple disk * Should be set for implementations which can swap out multiple disk
* images in runtime. * images in runtime.
* *
@ -2365,6 +2625,53 @@ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
* with replace_image_index. */ * with replace_image_index. */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void); typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);
/* Sets initial image to insert in drive when calling
* core_load_game().
* Since we cannot pass the initial index when loading
* content (this would require a major API change), this
* is set by the frontend *before* calling the core's
* retro_load_game()/retro_load_game_special() implementation.
* A core should therefore cache the index/path values and handle
* them inside retro_load_game()/retro_load_game_special().
* - If 'index' is invalid (index >= get_num_images()), the
* core should ignore the set value and instead use 0
* - 'path' is used purely for error checking - i.e. when
* content is loaded, the core should verify that the
* disk specified by 'index' has the specified file path.
* This is to guard against auto selecting the wrong image
* if (for example) the user should modify an existing M3U
* playlist. We have to let the core handle this because
* set_initial_image() must be called before loading content,
* i.e. the frontend cannot access image paths in advance
* and thus cannot perform the error check itself.
* If set path and content path do not match, the core should
* ignore the set 'index' value and instead use 0
* Returns 'false' if index or 'path' are invalid, or core
* does not support this functionality
*/
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);
/* Fetches the path of the specified disk image file.
* Returns 'false' if index is invalid (index >= get_num_images())
* or path is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len);
/* Fetches a core-provided 'label' for the specified disk
* image file. In the simplest case this may be a file name
* (without extension), but for cores with more complex
* content requirements information may be provided to
* facilitate user disk swapping - for example, a core
* running floppy-disk-based content may uniquely label
* save disks, data disks, level disks, etc. with names
* corresponding to in-game disk change prompts (so the
* frontend can provide better user guidance than a 'dumb'
* disk index value).
* Returns 'false' if index is invalid (index >= get_num_images())
* or label is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len);
struct retro_disk_control_callback struct retro_disk_control_callback
{ {
retro_set_eject_state_t set_eject_state; retro_set_eject_state_t set_eject_state;
@ -2378,6 +2685,27 @@ struct retro_disk_control_callback
retro_add_image_index_t add_image_index; retro_add_image_index_t add_image_index;
}; };
struct retro_disk_control_ext_callback
{
retro_set_eject_state_t set_eject_state;
retro_get_eject_state_t get_eject_state;
retro_get_image_index_t get_image_index;
retro_set_image_index_t set_image_index;
retro_get_num_images_t get_num_images;
retro_replace_image_index_t replace_image_index;
retro_add_image_index_t add_image_index;
/* NOTE: Frontend will only attempt to record/restore
* last used disk index if both set_initial_image()
* and get_image_path() are implemented */
retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */
retro_get_image_path_t get_image_path; /* Optional - may be NULL */
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
};
enum retro_pixel_format enum retro_pixel_format
{ {
/* 0RGB1555, native endian. /* 0RGB1555, native endian.
@ -2408,6 +2736,104 @@ struct retro_message
unsigned frames; /* Duration in frames of message. */ unsigned frames; /* Duration in frames of message. */
}; };
enum retro_message_target
{
RETRO_MESSAGE_TARGET_ALL = 0,
RETRO_MESSAGE_TARGET_OSD,
RETRO_MESSAGE_TARGET_LOG
};
enum retro_message_type
{
RETRO_MESSAGE_TYPE_NOTIFICATION = 0,
RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
RETRO_MESSAGE_TYPE_STATUS,
RETRO_MESSAGE_TYPE_PROGRESS
};
struct retro_message_ext
{
/* Message string to be displayed/logged */
const char *msg;
/* Duration (in ms) of message when targeting the OSD */
unsigned duration;
/* Message priority when targeting the OSD
* > When multiple concurrent messages are sent to
* the frontend and the frontend does not have the
* capacity to display them all, messages with the
* *highest* priority value should be shown
* > There is no upper limit to a message priority
* value (within the bounds of the unsigned data type)
* > In the reference frontend (RetroArch), the same
* priority values are used for frontend-generated
* notifications, which are typically assigned values
* between 0 and 3 depending upon importance */
unsigned priority;
/* Message logging level (info, warn, error, etc.) */
enum retro_log_level level;
/* Message destination: OSD, logging interface or both */
enum retro_message_target target;
/* Message 'type' when targeting the OSD
* > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a
* message should be handled in identical fashion to
* a standard frontend-generated notification
* > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that
* message is a notification that requires user attention
* or action, but that it should be displayed in a manner
* that differs from standard frontend-generated notifications.
* This would typically correspond to messages that should be
* displayed immediately (independently from any internal
* frontend message queue), and/or which should be visually
* distinguishable from frontend-generated notifications.
* For example, a core may wish to inform the user of
* information related to a disk-change event. It is
* expected that the frontend itself may provide a
* notification in this case; if the core sends a
* message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an
* uncomfortable 'double-notification' may occur. A message
* of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore
* be presented such that visual conflict with regular
* notifications does not occur
* > RETRO_MESSAGE_TYPE_STATUS: Indicates that message
* is not a standard notification. This typically
* corresponds to 'status' indicators, such as a core's
* internal FPS, which are intended to be displayed
* either permanently while a core is running, or in
* a manner that does not suggest user attention or action
* is required. 'Status' type messages should therefore be
* displayed in a different on-screen location and in a manner
* easily distinguishable from both standard frontend-generated
* notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT
* > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports
* the progress of an internal core task. For example, in cases
* where a core itself handles the loading of content from a file,
* this may correspond to the percentage of the file that has been
* read. Alternatively, an audio/video playback core may use a
* message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current
* playback position as a percentage of the runtime. 'Progress' type
* messages should therefore be displayed as a literal progress bar,
* where:
* - 'retro_message_ext.msg' is the progress bar title/label
* - 'retro_message_ext.progress' determines the length of
* the progress bar
* NOTE: Message type is a *hint*, and may be ignored
* by the frontend. If a frontend lacks support for
* displaying messages via alternate means than standard
* frontend-generated notifications, it will treat *all*
* messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */
enum retro_message_type type;
/* Task progress when targeting the OSD and message is
* of type RETRO_MESSAGE_TYPE_PROGRESS
* > -1: Unmetered/indeterminate
* > 0-100: Current progress percentage
* NOTE: Since message type is a hint, a frontend may ignore
* progress values. Where relevant, a core should therefore
* include progress percentage within the message string,
* such that the message intent remains clear when displayed
* as a standard frontend-generated notification */
int8_t progress;
};
/* Describes how the libretro implementation maps a libretro input bind /* Describes how the libretro implementation maps a libretro input bind
* to its internal input system through a human readable string. * to its internal input system through a human readable string.
* This string can be used to better let a user configure input. */ * This string can be used to better let a user configure input. */
@ -2428,7 +2854,7 @@ struct retro_input_descriptor
struct retro_system_info struct retro_system_info
{ {
/* All pointers are owned by libretro implementation, and pointers must /* All pointers are owned by libretro implementation, and pointers must
* remain valid until retro_deinit() is called. */ * remain valid until it is unloaded. */
const char *library_name; /* Descriptive name of library. Should not const char *library_name; /* Descriptive name of library. Should not
* contain any version numbers, etc. */ * contain any version numbers, etc. */
@ -2470,6 +2896,213 @@ struct retro_system_info
bool block_extract; bool block_extract;
}; };
/* Defines overrides which modify frontend handling of
* specific content file types.
* An array of retro_system_content_info_override is
* passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
* NOTE: In the following descriptions, references to
* retro_load_game() may be replaced with
* retro_load_game_special() */
struct retro_system_content_info_override
{
/* A list of file extensions for which the override
* should apply, delimited by a 'pipe' character
* (e.g. "md|sms|gg")
* Permitted file extensions are limited to those
* included in retro_system_info::valid_extensions
* and/or retro_subsystem_rom_info::valid_extensions */
const char *extensions;
/* Overrides the need_fullpath value set in
* retro_system_info and/or retro_subsystem_rom_info.
* To reiterate:
*
* If need_fullpath is true and retro_load_game() is called:
* - retro_game_info::path is guaranteed to contain a valid
* path to an existent file
* - retro_game_info::data and retro_game_info::size are invalid
*
* If need_fullpath is false and retro_load_game() is called:
* - retro_game_info::path may be NULL
* - retro_game_info::data and retro_game_info::size are guaranteed
* to be valid
*
* In addition:
*
* If need_fullpath is true and retro_load_game() is called:
* - retro_game_info_ext::full_path is guaranteed to contain a valid
* path to an existent file
* - retro_game_info_ext::archive_path may be NULL
* - retro_game_info_ext::archive_file may be NULL
* - retro_game_info_ext::dir is guaranteed to contain a valid path
* to the directory in which the content file exists
* - retro_game_info_ext::name is guaranteed to contain the
* basename of the content file, without extension
* - retro_game_info_ext::ext is guaranteed to contain the
* extension of the content file in lower case format
* - retro_game_info_ext::data and retro_game_info_ext::size
* are invalid
*
* If need_fullpath is false and retro_load_game() is called:
* - If retro_game_info_ext::file_in_archive is false:
* - retro_game_info_ext::full_path is guaranteed to contain
* a valid path to an existent file
* - retro_game_info_ext::archive_path may be NULL
* - retro_game_info_ext::archive_file may be NULL
* - retro_game_info_ext::dir is guaranteed to contain a
* valid path to the directory in which the content file exists
* - retro_game_info_ext::name is guaranteed to contain the
* basename of the content file, without extension
* - retro_game_info_ext::ext is guaranteed to contain the
* extension of the content file in lower case format
* - If retro_game_info_ext::file_in_archive is true:
* - retro_game_info_ext::full_path may be NULL
* - retro_game_info_ext::archive_path is guaranteed to
* contain a valid path to an existent compressed file
* inside which the content file is located
* - retro_game_info_ext::archive_file is guaranteed to
* contain a valid path to an existent content file
* inside the compressed file referred to by
* retro_game_info_ext::archive_path
* e.g. for a compressed file '/path/to/foo.zip'
* containing 'bar.sfc'
* > retro_game_info_ext::archive_path will be '/path/to/foo.zip'
* > retro_game_info_ext::archive_file will be 'bar.sfc'
* - retro_game_info_ext::dir is guaranteed to contain a
* valid path to the directory in which the compressed file
* (containing the content file) exists
* - retro_game_info_ext::name is guaranteed to contain
* EITHER
* 1) the basename of the compressed file (containing
* the content file), without extension
* OR
* 2) the basename of the content file inside the
* compressed file, without extension
* In either case, a core should consider 'name' to
* be the canonical name/ID of the the content file
* - retro_game_info_ext::ext is guaranteed to contain the
* extension of the content file inside the compressed file,
* in lower case format
* - retro_game_info_ext::data and retro_game_info_ext::size are
* guaranteed to be valid */
bool need_fullpath;
/* If need_fullpath is false, specifies whether the content
* data buffer available in retro_load_game() is 'persistent'
*
* If persistent_data is false and retro_load_game() is called:
* - retro_game_info::data and retro_game_info::size
* are valid only until retro_load_game() returns
* - retro_game_info_ext::data and retro_game_info_ext::size
* are valid only until retro_load_game() returns
*
* If persistent_data is true and retro_load_game() is called:
* - retro_game_info::data and retro_game_info::size
* are valid until retro_deinit() returns
* - retro_game_info_ext::data and retro_game_info_ext::size
* are valid until retro_deinit() returns */
bool persistent_data;
};
/* Similar to retro_game_info, but provides extended
* information about the source content file and
* game memory buffer status.
* And array of retro_game_info_ext is returned by
* RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
* NOTE: In the following descriptions, references to
* retro_load_game() may be replaced with
* retro_load_game_special() */
struct retro_game_info_ext
{
/* - If file_in_archive is false, contains a valid
* path to an existent content file (UTF-8 encoded)
* - If file_in_archive is true, may be NULL */
const char *full_path;
/* - If file_in_archive is false, may be NULL
* - If file_in_archive is true, contains a valid path
* to an existent compressed file inside which the
* content file is located (UTF-8 encoded) */
const char *archive_path;
/* - If file_in_archive is false, may be NULL
* - If file_in_archive is true, contain a valid path
* to an existent content file inside the compressed
* file referred to by archive_path (UTF-8 encoded)
* e.g. for a compressed file '/path/to/foo.zip'
* containing 'bar.sfc'
* > archive_path will be '/path/to/foo.zip'
* > archive_file will be 'bar.sfc' */
const char *archive_file;
/* - If file_in_archive is false, contains a valid path
* to the directory in which the content file exists
* (UTF-8 encoded)
* - If file_in_archive is true, contains a valid path
* to the directory in which the compressed file
* (containing the content file) exists (UTF-8 encoded) */
const char *dir;
/* Contains the canonical name/ID of the content file
* (UTF-8 encoded). Intended for use when identifying
* 'complementary' content named after the loaded file -
* i.e. companion data of a different format (a CD image
* required by a ROM), texture packs, internally handled
* save files, etc.
* - If file_in_archive is false, contains the basename
* of the content file, without extension
* - If file_in_archive is true, then string is
* implementation specific. A frontend may choose to
* set a name value of:
* EITHER
* 1) the basename of the compressed file (containing
* the content file), without extension
* OR
* 2) the basename of the content file inside the
* compressed file, without extension
* RetroArch sets the 'name' value according to (1).
* A frontend that supports routine loading of
* content from archives containing multiple unrelated
* content files may set the 'name' value according
* to (2). */
const char *name;
/* - If file_in_archive is false, contains the extension
* of the content file in lower case format
* - If file_in_archive is true, contains the extension
* of the content file inside the compressed file,
* in lower case format */
const char *ext;
/* String of implementation specific meta-data. */
const char *meta;
/* Memory buffer of loaded game content. Will be NULL:
* IF
* - retro_system_info::need_fullpath is true and
* retro_system_content_info_override::need_fullpath
* is unset
* OR
* - retro_system_content_info_override::need_fullpath
* is true */
const void *data;
/* Size of game content memory buffer, in bytes */
size_t size;
/* True if loaded content file is inside a compressed
* archive */
bool file_in_archive;
/* - If data is NULL, value is unset/ignored
* - If data is non-NULL:
* - If persistent_data is false, data and size are
* valid only until retro_load_game() returns
* - If persistent_data is true, data and size are
* are valid until retro_deinit() returns */
bool persistent_data;
};
struct retro_game_geometry struct retro_game_geometry
{ {
unsigned base_width; /* Nominal video width of game. */ unsigned base_width; /* Nominal video width of game. */
@ -2522,8 +3155,20 @@ struct retro_core_option_display
}; };
/* Maximum number of values permitted for a core option /* Maximum number of values permitted for a core option
* NOTE: This may be increased on a core-by-core basis * > Note: We have to set a maximum value due the limitations
* if required (doing so has no effect on the frontend) */ * of the C language - i.e. it is not possible to create an
* array of structs each containing a variable sized array,
* so the retro_core_option_definition values array must
* have a fixed size. The size limit of 128 is a balancing
* act - it needs to be large enough to support all 'sane'
* core options, but setting it too large may impact low memory
* platforms. In practise, if a core option has more than
* 128 values then the implementation is likely flawed.
* To quote the above API reference:
* "The number of possible options should be very limited
* i.e. it should be feasible to cycle through options
* without a keyboard."
*/
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128 #define RETRO_NUM_CORE_OPTION_VALUES_MAX 128
struct retro_core_option_value struct retro_core_option_value
@ -2615,6 +3260,47 @@ struct retro_framebuffer
Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
}; };
/* Used by a libretro core to override the current
* fastforwarding mode of the frontend */
struct retro_fastforwarding_override
{
/* Specifies the runtime speed multiplier that
* will be applied when 'fastforward' is true.
* For example, a value of 5.0 when running 60 FPS
* content will cap the fast-forward rate at 300 FPS.
* Note that the target multiplier may not be achieved
* if the host hardware has insufficient processing
* power.
* Setting a value of 0.0 (or greater than 0.0 but
* less than 1.0) will result in an uncapped
* fast-forward rate (limited only by hardware
* capacity).
* If the value is negative, it will be ignored
* (i.e. the frontend will use a runtime speed
* multiplier of its own choosing) */
float ratio;
/* If true, fastforwarding mode will be enabled.
* If false, fastforwarding mode will be disabled. */
bool fastforward;
/* If true, and if supported by the frontend, an
* on-screen notification will be displayed while
* 'fastforward' is true.
* If false, and if supported by the frontend, any
* on-screen fast-forward notifications will be
* suppressed */
bool notification;
/* If true, the core will have sole control over
* when fastforwarding mode is enabled/disabled;
* the frontend will not be able to change the
* state set by 'fastforward' until either
* 'inhibit_toggle' is set to false, or the core
* is unloaded */
bool inhibit_toggle;
};
/* Callbacks */ /* Callbacks */
/* Environment callback. Gives implementations a way of performing /* Environment callback. Gives implementations a way of performing

36
main.c
View File

@ -261,7 +261,7 @@ static int loadFromZipByName(unsigned char *buffer, char *archive,
*filesize = zinfo.uncompressed_size; *filesize = zinfo.uncompressed_size;
/* Error: file size is zero */ /* Error: file size is zero */
if(*filesize <= 0 || *filesize > (4*1024*1024)) if(*filesize <= 0 || *filesize > MAINROM_SIZE_MAX)
{ {
unzClose(zhandle); unzClose(zhandle);
return (0); return (0);
@ -330,23 +330,35 @@ static int strrchr2(const char *src, int c)
return 0; return 0;
} }
int handleInputFile(char *romName) int handleInputFile(const char *romName,
const unsigned char *romData, int romSize)
{ {
FILE *romFile;
int iDepth = 0;
#ifdef WANT_ZIP #ifdef WANT_ZIP
int size; int iDepth = 0;
#endif #endif
initSysInfo(); //initialize it all initSysInfo(); //initialize it all
#ifdef WANT_ZIP
//if it's a ZIP file, we need to handle that here. //if it's a ZIP file, we need to handle that here.
iDepth = strrchr2(romName, '.'); iDepth = strrchr2(romName, '.');
iDepth++; iDepth++;
#endif
#ifdef WANT_ZIP if (romData)
if( ( strcmp( romName + iDepth, "zip" ) == 0 ) || ( strcmp( romName + iDepth, "ZIP" ) == 0 ))
{ {
int size = romSize > MAINROM_SIZE_MAX ?
MAINROM_SIZE_MAX : romSize;
m_emuInfo.romSize = size;
memcpy(mainrom, romData, size);
strcpy(m_emuInfo.RomFileName, romName);
}
#ifdef WANT_ZIP
else if ( ( strcmp( romName + iDepth, "zip" ) == 0 ) || ( strcmp( romName + iDepth, "ZIP" ) == 0 ))
{
int size;
//get ROM from ZIP //get ROM from ZIP
if(check_zip(romName)) if(check_zip(romName))
{ {
@ -365,9 +377,11 @@ int handleInputFile(char *romName)
return 0; return 0;
} }
} }
else
#endif // WANT_ZIP #endif // WANT_ZIP
else
{ {
FILE *romFile = NULL;
//get ROM from binary ROM file //get ROM from binary ROM file
romFile = fopen(romName, "rb"); romFile = fopen(romName, "rb");
if(!romFile) if(!romFile)
@ -376,11 +390,13 @@ int handleInputFile(char *romName)
return 0; return 0;
} }
m_emuInfo.romSize = fread(mainrom, 1, 4*1024*1024, romFile); m_emuInfo.romSize = fread(mainrom, 1, MAINROM_SIZE_MAX, romFile);
strcpy(m_emuInfo.RomFileName, romName); strcpy(m_emuInfo.RomFileName, romName);
fclose(romFile);
} }
if(!initRom()) if (!initRom())
{ {
fprintf(stderr, "initRom couldn't handle %s file\n", romName); fprintf(stderr, "initRom couldn't handle %s file\n", romName);
return 0; return 0;

3
main.h
View File

@ -57,7 +57,8 @@ extern EMUINFO m_emuInfo;
extern SYSTEMINFO m_sysInfo[NR_OF_SYSTEMS]; extern SYSTEMINFO m_sysInfo[NR_OF_SYSTEMS];
extern int romSize; extern int romSize;
int handleInputFile(char *romName); int handleInputFile(const char *romName,
const unsigned char *romData, int romSize);
void mainemuinit(void); void mainemuinit(void);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -44,7 +44,7 @@ unsigned char cpuram[0x08a0];
* on the gameboy maximum of 128kbyte of RAM is possible, plus some internal ram (64KB) */ * on the gameboy maximum of 128kbyte of RAM is possible, plus some internal ram (64KB) */
unsigned char __attribute__ ((__aligned__(4))) mainram[(64+32+128)*1024]; unsigned char __attribute__ ((__aligned__(4))) mainram[(64+32+128)*1024];
// rom area for roms (4 Megabyte) // rom area for roms (4 Megabyte)
unsigned char __attribute__ ((__aligned__(4))) mainrom[4*1024*1024]; unsigned char __attribute__ ((__aligned__(4))) mainrom[MAINROM_SIZE_MAX];
// cpu internal ROM including vector table starting at 0xff0000 // cpu internal ROM including vector table starting at 0xff0000
unsigned char __attribute__ ((__aligned__(4))) cpurom[256*1024];//prob only needs 0x10000 unsigned char __attribute__ ((__aligned__(4))) cpurom[256*1024];//prob only needs 0x10000
// //

View File

@ -34,6 +34,9 @@
extern "C" { extern "C" {
#endif #endif
/* Maximum ROM size is 4 megabytes */
#define MAINROM_SIZE_MAX (4*1024*1024)
extern unsigned char mainram[]; /* All RAM areas */ extern unsigned char mainram[]; /* All RAM areas */
extern unsigned char mainrom[]; /* ROM image area */ extern unsigned char mainrom[]; /* ROM image area */
extern unsigned char cpurom[]; /* Bios ROM image area */ extern unsigned char cpurom[]; /* Bios ROM image area */
@ -362,7 +365,7 @@ static INLINE unsigned int tlcsMemReadL(unsigned int addr)
i = *(gA++); i = *(gA++);
i |= (*(gA++)) << 8; i |= (*(gA++)) << 8;
i |= (*(gA++)) << 16; i |= (*(gA++)) << 16;
i |= (*gA) << 24; i |= (unsigned int)(*gA) << 24;
#if 0 #if 0
return tlcsMemReadB(addr) | (tlcsMemReadB(addr +1) << 8) | (tlcsMemReadB(addr +2) << 16) | (tlcsMemReadB(addr +3) << 24); return tlcsMemReadB(addr) | (tlcsMemReadB(addr +1) << 8) | (tlcsMemReadB(addr +2) << 16) | (tlcsMemReadB(addr +3) << 24);

View File

@ -792,7 +792,7 @@ static INLINE unsigned int readlong(void)
i = *(my_pc++); i = *(my_pc++);
i |= (*(my_pc++) << 8); i |= (*(my_pc++) << 8);
i |= (*(my_pc++) << 16); i |= (*(my_pc++) << 16);
i |= (*(my_pc++) << 24); i |= ((unsigned int)(*(my_pc++)) << 24);
return i; return i;
} }
else else