mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-04 23:07:46 -04:00
libretro, add Pico pad overlay and storyware pages handling
This commit is contained in:
parent
15cc45c0da
commit
5f9901e098
17 changed files with 3415 additions and 477 deletions
File diff suppressed because it is too large
Load diff
149
platform/libretro/libretro-common/file/file_path_io.c
Normal file
149
platform/libretro/libretro-common/file/file_path_io.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_path_io.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <file/file_path.h>
|
||||
#include <compat/strl.h>
|
||||
#include <compat/posix_string.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <string/stdstring.h>
|
||||
#define VFS_FRONTEND
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
/* TODO/FIXME - globals */
|
||||
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
|
||||
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||
|
||||
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
{
|
||||
const struct retro_vfs_interface*
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
path_stat_cb = retro_vfs_stat_impl;
|
||||
path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||
|
||||
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||
return;
|
||||
|
||||
path_stat_cb = vfs_iface->stat;
|
||||
path_mkdir_cb = vfs_iface->mkdir;
|
||||
}
|
||||
|
||||
int path_stat(const char *path)
|
||||
{
|
||||
return path_stat_cb(path, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* path_is_directory:
|
||||
* @path : path
|
||||
*
|
||||
* Checks if path is a directory.
|
||||
*
|
||||
* @return true if path is a directory, otherwise false.
|
||||
*/
|
||||
bool path_is_directory(const char *path)
|
||||
{
|
||||
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
bool path_is_character_special(const char *path)
|
||||
{
|
||||
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
|
||||
}
|
||||
|
||||
bool path_is_valid(const char *path)
|
||||
{
|
||||
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
|
||||
}
|
||||
|
||||
int32_t path_get_size(const char *path)
|
||||
{
|
||||
int32_t filesize = 0;
|
||||
if (path_stat_cb(path, &filesize) != 0)
|
||||
return filesize;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_mkdir:
|
||||
* @dir : directory
|
||||
*
|
||||
* Create directory on filesystem.
|
||||
*
|
||||
* Recursive function.
|
||||
*
|
||||
* @return true if directory could be created, otherwise false.
|
||||
**/
|
||||
bool path_mkdir(const char *dir)
|
||||
{
|
||||
bool norecurse = false;
|
||||
char *basedir = NULL;
|
||||
|
||||
if (!(dir && *dir))
|
||||
return false;
|
||||
|
||||
/* Use heap. Real chance of stack
|
||||
* overflow if we recurse too hard. */
|
||||
if (!(basedir = strdup(dir)))
|
||||
return false;
|
||||
|
||||
path_parent_dir(basedir, strlen(basedir));
|
||||
|
||||
if (!*basedir || !strcmp(basedir, dir))
|
||||
{
|
||||
free(basedir);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( path_is_directory(basedir)
|
||||
|| path_mkdir(basedir))
|
||||
norecurse = true;
|
||||
|
||||
free(basedir);
|
||||
|
||||
if (norecurse)
|
||||
{
|
||||
int ret = path_mkdir_cb(dir);
|
||||
|
||||
/* Don't treat this as an error. */
|
||||
if (ret == -2 && path_is_directory(dir))
|
||||
return true;
|
||||
else if (ret == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
1251
platform/libretro/libretro-common/formats/png/rpng.c
Normal file
1251
platform/libretro/libretro-common/formats/png/rpng.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,49 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rpng_internal.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _RPNG_COMMON_H
|
||||
#define _RPNG_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <filters.h>
|
||||
#include <formats/rpng.h>
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
static const uint8_t png_magic[8] = {
|
||||
0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a,
|
||||
};
|
||||
|
||||
struct png_ihdr
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t depth;
|
||||
uint8_t color_type;
|
||||
uint8_t compression;
|
||||
uint8_t filter;
|
||||
uint8_t interlace;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -51,6 +51,28 @@ enum
|
|||
RARCH_FILE_UNSUPPORTED
|
||||
};
|
||||
|
||||
struct path_linked_list
|
||||
{
|
||||
char *path;
|
||||
struct path_linked_list *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new linked list with one item in it
|
||||
* The path on this item will be set to NULL
|
||||
**/
|
||||
struct path_linked_list* path_linked_list_new(void);
|
||||
|
||||
/* Free the entire linked list */
|
||||
void path_linked_list_free(struct path_linked_list *in_path_linked_list);
|
||||
|
||||
/**
|
||||
* Add a node to the linked list with this path
|
||||
* If the first node's path if it's not yet set,
|
||||
* set this instead
|
||||
**/
|
||||
void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);
|
||||
|
||||
/**
|
||||
* path_is_compressed_file:
|
||||
* @path : path
|
||||
|
@ -81,12 +103,12 @@ bool path_is_compressed_file(const char *path);
|
|||
* path_get_archive_delim:
|
||||
* @path : path
|
||||
*
|
||||
* Gets delimiter of an archive file. Only the first '#'
|
||||
* Find delimiter of an archive file. Only the first '#'
|
||||
* after a compression extension is considered.
|
||||
*
|
||||
* Returns: pointer to the delimiter in the path if it contains
|
||||
* a compressed file, otherwise NULL.
|
||||
*/
|
||||
* @return pointer to the delimiter in the path if it contains
|
||||
* a path inside a compressed file, otherwise NULL.
|
||||
**/
|
||||
const char *path_get_archive_delim(const char *path);
|
||||
|
||||
/**
|
||||
|
@ -96,10 +118,28 @@ const char *path_get_archive_delim(const char *path);
|
|||
* Gets extension of file. Only '.'s
|
||||
* after the last slash are considered.
|
||||
*
|
||||
* Returns: extension part from the path.
|
||||
*/
|
||||
* Hidden non-leaf function cost:
|
||||
* - calls string_is_empty()
|
||||
* - calls strrchr
|
||||
*
|
||||
* @return extension part from the path.
|
||||
**/
|
||||
const char *path_get_extension(const char *path);
|
||||
|
||||
/**
|
||||
* path_get_extension_mutable:
|
||||
* @path : path
|
||||
*
|
||||
* Specialized version of path_get_extension(). Return
|
||||
* value is mutable.
|
||||
*
|
||||
* Gets extension of file. Only '.'s
|
||||
* after the last slash are considered.
|
||||
*
|
||||
* @return extension part from the path.
|
||||
**/
|
||||
char *path_get_extension_mutable(const char *path);
|
||||
|
||||
/**
|
||||
* path_remove_extension:
|
||||
* @path : path
|
||||
|
@ -108,7 +148,10 @@ const char *path_get_extension(const char *path);
|
|||
* text after and including the last '.'.
|
||||
* Only '.'s after the last slash are considered.
|
||||
*
|
||||
* Returns:
|
||||
* Hidden non-leaf function cost:
|
||||
* - calls strrchr
|
||||
*
|
||||
* @return
|
||||
* 1) If path has an extension, returns path with the
|
||||
* extension removed.
|
||||
* 2) If there is no extension, returns NULL.
|
||||
|
@ -122,9 +165,26 @@ char *path_remove_extension(char *path);
|
|||
*
|
||||
* Get basename from @path.
|
||||
*
|
||||
* Returns: basename from path.
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls path_get_archive_delim()
|
||||
* - can call find_last_slash() once if it returns NULL
|
||||
*
|
||||
* @return basename from path.
|
||||
**/
|
||||
const char *path_basename(const char *path);
|
||||
|
||||
/**
|
||||
* path_basename_nocompression:
|
||||
* @path : path
|
||||
*
|
||||
* Specialized version of path_basename().
|
||||
* Get basename from @path.
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls find_last_slash()
|
||||
*
|
||||
* @return basename from path.
|
||||
**/
|
||||
const char *path_basename_nocompression(const char *path);
|
||||
|
||||
/**
|
||||
|
@ -139,12 +199,13 @@ void path_basedir(char *path);
|
|||
/**
|
||||
* path_parent_dir:
|
||||
* @path : path
|
||||
* @len : length of @path
|
||||
*
|
||||
* Extracts parent directory by mutating path.
|
||||
* Assumes that path is a directory. Keeps trailing '/'.
|
||||
* If the path was already at the root directory, returns empty string
|
||||
**/
|
||||
void path_parent_dir(char *path);
|
||||
void path_parent_dir(char *path, size_t len);
|
||||
|
||||
/**
|
||||
* path_resolve_realpath:
|
||||
|
@ -156,7 +217,7 @@ void path_parent_dir(char *path);
|
|||
*
|
||||
* Relative paths are rebased on the current working dir.
|
||||
*
|
||||
* Returns: @buf if successful, NULL otherwise.
|
||||
* @return @buf if successful, NULL otherwise.
|
||||
* Note: Not implemented on consoles
|
||||
* Note: Symlinks are only resolved on Unix-likes
|
||||
* Note: The current working dir might not be what you expect,
|
||||
|
@ -178,8 +239,11 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
|
|||
* Both @path and @base are assumed to be absolute paths without "." or "..".
|
||||
*
|
||||
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
|
||||
*
|
||||
* @return Length of the string copied into @out
|
||||
**/
|
||||
size_t path_relative_to(char *out, const char *path, const char *base, size_t size);
|
||||
size_t path_relative_to(char *out, const char *path, const char *base,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* path_is_absolute:
|
||||
|
@ -187,7 +251,7 @@ size_t path_relative_to(char *out, const char *path, const char *base, size_t si
|
|||
*
|
||||
* Checks if @path is an absolute path or a relative path.
|
||||
*
|
||||
* Returns: true if path is absolute, false if path is relative.
|
||||
* @return true if path is absolute, false if path is relative.
|
||||
**/
|
||||
bool path_is_absolute(const char *path);
|
||||
|
||||
|
@ -211,8 +275,15 @@ bool path_is_absolute(const char *path);
|
|||
* out_path = "/foo/bar/baz/boo.asm"
|
||||
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
|
||||
* out_path = "/foo/bar/baz/boo"
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - calls strlcpy 2x
|
||||
* - calls strrchr
|
||||
* - calls strlcat
|
||||
*
|
||||
* @return Length of the string copied into @out
|
||||
*/
|
||||
void fill_pathname(char *out_path, const char *in_path,
|
||||
size_t fill_pathname(char *out_path, const char *in_path,
|
||||
const char *replace, size_t size);
|
||||
|
||||
/**
|
||||
|
@ -226,6 +297,12 @@ void fill_pathname(char *out_path, const char *in_path,
|
|||
*
|
||||
* E.g.:
|
||||
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls rtime_localtime()
|
||||
* - Calls strftime
|
||||
* - Calls strlcat
|
||||
*
|
||||
**/
|
||||
size_t fill_dated_filename(char *out_filename,
|
||||
const char *ext, size_t size);
|
||||
|
@ -242,34 +319,33 @@ size_t fill_dated_filename(char *out_filename,
|
|||
*
|
||||
* E.g.:
|
||||
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls time
|
||||
* - Calls rtime_localtime()
|
||||
* - Calls strlcpy 2x
|
||||
* - Calls string_is_empty()
|
||||
* - Calls strftime
|
||||
* - Calls strlcat
|
||||
*
|
||||
* @return Length of the string copied into @out_path
|
||||
**/
|
||||
void fill_str_dated_filename(char *out_filename,
|
||||
size_t fill_str_dated_filename(char *out_filename,
|
||||
const char *in_str, const char *ext, size_t size);
|
||||
|
||||
/**
|
||||
* fill_pathname_noext:
|
||||
* @out_path : output path
|
||||
* @in_path : input path
|
||||
* @replace : what to replace
|
||||
* @size : buffer size of output path
|
||||
*
|
||||
* Appends a filename extension 'replace' to 'in_path', and outputs
|
||||
* result in 'out_path'.
|
||||
*
|
||||
* Assumes in_path has no extension. If an extension is still
|
||||
* present in 'in_path', it will be ignored.
|
||||
*
|
||||
*/
|
||||
size_t fill_pathname_noext(char *out_path, const char *in_path,
|
||||
const char *replace, size_t size);
|
||||
|
||||
/**
|
||||
* find_last_slash:
|
||||
* @str : input path
|
||||
* @str : path
|
||||
* @size : size of path
|
||||
*
|
||||
* Gets a pointer to the last slash in the input path.
|
||||
* Find last slash in path. Tries to find
|
||||
* a backslash on Windows too which takes precedence
|
||||
* over regular slash.
|
||||
|
||||
* Hidden non-leaf function cost:
|
||||
* - calls strrchr
|
||||
*
|
||||
* Returns: a pointer to the last slash in the input path.
|
||||
* @return pointer to last slash/backslash found in @str.
|
||||
**/
|
||||
char *find_last_slash(const char *str);
|
||||
|
||||
|
@ -289,6 +365,11 @@ char *find_last_slash(const char *str);
|
|||
*
|
||||
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
|
||||
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls fill_pathname_slash()
|
||||
* - Calls path_basename()
|
||||
* - Calls strlcpy 2x
|
||||
**/
|
||||
size_t fill_pathname_dir(char *in_dir, const char *in_basename,
|
||||
const char *replace, size_t size);
|
||||
|
@ -300,16 +381,15 @@ size_t fill_pathname_dir(char *in_dir, const char *in_basename,
|
|||
* @size : size of output path
|
||||
*
|
||||
* Copies basename of @in_path into @out_path.
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls path_basename()
|
||||
* - Calls strlcpy
|
||||
*
|
||||
* @return length of the string copied into @out
|
||||
**/
|
||||
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
|
||||
|
||||
void fill_pathname_base_noext(char *out_dir,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
size_t fill_pathname_base_ext(char *out,
|
||||
const char *in_path, const char *ext,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* fill_pathname_basedir:
|
||||
* @out_dir : output directory
|
||||
|
@ -319,12 +399,13 @@ size_t fill_pathname_base_ext(char *out,
|
|||
* Copies base directory of @in_path into @out_path.
|
||||
* If in_path is a path without any slashes (relative current directory),
|
||||
* @out_path will get path "./".
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls strlcpy
|
||||
* - Calls path_basedir()
|
||||
**/
|
||||
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
|
||||
|
||||
void fill_pathname_basedir_noext(char *out_dir,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
/**
|
||||
* fill_pathname_parent_dir_name:
|
||||
* @out_dir : output directory
|
||||
|
@ -333,7 +414,13 @@ void fill_pathname_basedir_noext(char *out_dir,
|
|||
*
|
||||
* Copies only the parent directory name of @in_dir into @out_dir.
|
||||
* The two buffers must not overlap. Removes trailing '/'.
|
||||
* Returns true on success, false if a slash was not found in the path.
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls strdup
|
||||
* - Calls find_last_slash() x times
|
||||
* - Can call strlcpy
|
||||
*
|
||||
* @return true on success, false if a slash was not found in the path.
|
||||
**/
|
||||
bool fill_pathname_parent_dir_name(char *out_dir,
|
||||
const char *in_dir, size_t size);
|
||||
|
@ -347,6 +434,11 @@ bool fill_pathname_parent_dir_name(char *out_dir,
|
|||
* Copies parent directory of @in_dir into @out_dir.
|
||||
* Assumes @in_dir is a directory. Keeps trailing '/'.
|
||||
* If the path was already at the root directory, @out_dir will be an empty string.
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Can call strlcpy if (@out_dir != @in_dir)
|
||||
* - Calls strlen if (@out_dir == @in_dir)
|
||||
* - Calls path_parent_dir()
|
||||
**/
|
||||
void fill_pathname_parent_dir(char *out_dir,
|
||||
const char *in_dir, size_t size);
|
||||
|
@ -374,30 +466,51 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
|
|||
* @size : size of output path
|
||||
*
|
||||
* Joins a directory (@dir) and path (@path) together.
|
||||
* Makes sure not to get two consecutive slashes
|
||||
* Makes sure not to get two consecutive slashes
|
||||
* between directory and path.
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - calls strlcpy at least once
|
||||
* - calls fill_pathname_slash()
|
||||
*
|
||||
* Deprecated. Use fill_pathname_join_special() instead
|
||||
* if you can ensure @dir != @out_path
|
||||
*
|
||||
* @return Length of the string copied into @out_path
|
||||
**/
|
||||
size_t fill_pathname_join(char *out_path, const char *dir,
|
||||
const char *path, size_t size);
|
||||
|
||||
/**
|
||||
* fill_pathname_join_special:
|
||||
* @out_path : output path
|
||||
* @dir : directory. Cannot be identical to @out_path
|
||||
* @path : path
|
||||
* @size : size of output path
|
||||
*
|
||||
*
|
||||
* Specialized version of fill_pathname_join.
|
||||
* Unlike fill_pathname_join(),
|
||||
* @dir and @out_path CANNOT be identical.
|
||||
*
|
||||
* Joins a directory (@dir) and path (@path) together.
|
||||
* Makes sure not to get two consecutive slashes
|
||||
* between directory and path.
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - calls strlcpy 2x
|
||||
* - calls find_last_slash()
|
||||
*
|
||||
* @return Length of the string copied into @out_path
|
||||
**/
|
||||
size_t fill_pathname_join_special(char *out_path,
|
||||
const char *dir, const char *path, size_t size);
|
||||
|
||||
size_t fill_pathname_join_special_ext(char *out_path,
|
||||
const char *dir, const char *path,
|
||||
const char *last, const char *ext,
|
||||
size_t size);
|
||||
|
||||
size_t fill_pathname_join_concat_noext(char *out_path,
|
||||
const char *dir, const char *path,
|
||||
const char *concat,
|
||||
size_t size);
|
||||
|
||||
size_t fill_pathname_join_concat(char *out_path,
|
||||
const char *dir, const char *path,
|
||||
const char *concat,
|
||||
size_t size);
|
||||
|
||||
void fill_pathname_join_noext(char *out_path,
|
||||
const char *dir, const char *path, size_t size);
|
||||
|
||||
/**
|
||||
* fill_pathname_join_delim:
|
||||
* @out_path : output path
|
||||
|
@ -408,45 +521,57 @@ void fill_pathname_join_noext(char *out_path,
|
|||
*
|
||||
* Joins a directory (@dir) and path (@path) together
|
||||
* using the given delimiter (@delim).
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - can call strlen
|
||||
* - can call strlcpy
|
||||
* - can call strlcat
|
||||
**/
|
||||
size_t fill_pathname_join_delim(char *out_path, const char *dir,
|
||||
const char *path, const char delim, size_t size);
|
||||
|
||||
size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
|
||||
const char *path, const char delim, const char *concat,
|
||||
size_t size);
|
||||
size_t fill_pathname_expand_special(char *out_path,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
size_t fill_pathname_abbreviate_special(char *out_path,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
/**
|
||||
* fill_short_pathname_representation:
|
||||
* @out_rep : output representation
|
||||
* @in_path : input path
|
||||
* @size : size of output representation
|
||||
* fill_pathname_abbreviated_or_relative:
|
||||
*
|
||||
* Generates a short representation of path. It should only
|
||||
* be used for displaying the result; the output representation is not
|
||||
* binding in any meaningful way (for a normal path, this is the same as basename)
|
||||
* In case of more complex URLs, this should cut everything except for
|
||||
* the main image file.
|
||||
* Fills the supplied path with either the abbreviated path or
|
||||
* the relative path, which ever one has less depth / number of slashes
|
||||
*
|
||||
* If lengths of abbreviated and relative paths are the same,
|
||||
* the relative path will be used
|
||||
* @in_path can be an absolute, relative or abbreviated path
|
||||
*
|
||||
* E.g.: "/path/to/game.img" -> game.img
|
||||
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
|
||||
*/
|
||||
size_t fill_short_pathname_representation(char* out_rep,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
void fill_short_pathname_representation_noext(char* out_rep,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
void fill_pathname_expand_special(char *out_path,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
void fill_pathname_abbreviate_special(char *out_path,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
|
||||
* @return Length of the string copied into @out_path
|
||||
**/
|
||||
size_t fill_pathname_abbreviated_or_relative(char *out_path,
|
||||
const char *in_refpath, const char *in_path, size_t size);
|
||||
|
||||
/**
|
||||
* pathname_conform_slashes_to_os:
|
||||
*
|
||||
* @path : path
|
||||
*
|
||||
* Leaf function.
|
||||
*
|
||||
* Changes the slashes to the correct kind for the os
|
||||
* So forward slash on linux and backslash on Windows
|
||||
**/
|
||||
void pathname_conform_slashes_to_os(char *path);
|
||||
|
||||
/**
|
||||
* pathname_make_slashes_portable:
|
||||
* @path : path
|
||||
*
|
||||
* Leaf function.
|
||||
*
|
||||
* Change all slashes to forward so they are more
|
||||
* portable between Windows and Linux
|
||||
**/
|
||||
void pathname_make_slashes_portable(char *path);
|
||||
|
||||
/**
|
||||
|
@ -464,8 +589,8 @@ void path_basedir_wrapper(char *path);
|
|||
*
|
||||
* Checks if character (@c) is a slash.
|
||||
*
|
||||
* Returns: true (1) if character is a slash, otherwise false (0).
|
||||
*/
|
||||
* @return true if character is a slash, otherwise false.
|
||||
**/
|
||||
#ifdef _WIN32
|
||||
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
||||
#else
|
||||
|
@ -477,8 +602,8 @@ void path_basedir_wrapper(char *path);
|
|||
*
|
||||
* Gets the default slash separator.
|
||||
*
|
||||
* Returns: default slash separator.
|
||||
*/
|
||||
* @return default slash separator.
|
||||
**/
|
||||
#ifdef _WIN32
|
||||
#define PATH_DEFAULT_SLASH() "\\"
|
||||
#define PATH_DEFAULT_SLASH_C() '\\'
|
||||
|
@ -494,8 +619,13 @@ void path_basedir_wrapper(char *path);
|
|||
*
|
||||
* Assumes path is a directory. Appends a slash
|
||||
* if not already there.
|
||||
|
||||
* Hidden non-leaf function cost:
|
||||
* - calls find_last_slash()
|
||||
* - can call strlcat once if it returns false
|
||||
* - calls strlen
|
||||
**/
|
||||
void fill_pathname_slash(char *path, size_t size);
|
||||
size_t fill_pathname_slash(char *path, size_t size);
|
||||
|
||||
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
||||
void fill_pathname_application_path(char *buf, size_t size);
|
||||
|
@ -509,7 +639,16 @@ void fill_pathname_home_dir(char *buf, size_t size);
|
|||
*
|
||||
* Create directory on filesystem.
|
||||
*
|
||||
* Returns: true (1) if directory could be created, otherwise false (0).
|
||||
* Recursive function.
|
||||
*
|
||||
* Hidden non-leaf function cost:
|
||||
* - Calls strdup
|
||||
* - Calls path_parent_dir()
|
||||
* - Calls strcmp
|
||||
* - Calls path_is_directory()
|
||||
* - Calls path_mkdir()
|
||||
*
|
||||
* @return true if directory could be created, otherwise false.
|
||||
**/
|
||||
bool path_mkdir(const char *dir);
|
||||
|
||||
|
@ -519,10 +658,15 @@ bool path_mkdir(const char *dir);
|
|||
*
|
||||
* Checks if path is a directory.
|
||||
*
|
||||
* Returns: true (1) if path is a directory, otherwise false (0).
|
||||
* @return true if path is a directory, otherwise false.
|
||||
*/
|
||||
bool path_is_directory(const char *path);
|
||||
|
||||
/* Time format strings with AM-PM designation require special
|
||||
* handling due to platform dependence */
|
||||
void strftime_am_pm(char *s, size_t len, const char* format,
|
||||
const void* timeptr);
|
||||
|
||||
bool path_is_character_special(const char *path);
|
||||
|
||||
int path_stat(const char *path);
|
||||
|
|
103
platform/libretro/libretro-common/include/filters.h
Normal file
103
platform/libretro/libretro-common/include/filters.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (filters.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_SDK_FILTERS_H
|
||||
#define _LIBRETRO_SDK_FILTERS_H
|
||||
|
||||
/* for MSVC; should be benign under any circumstances */
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <retro_inline.h>
|
||||
#include <retro_math.h>
|
||||
|
||||
/**
|
||||
* sinc:
|
||||
*
|
||||
* Pure function.
|
||||
**/
|
||||
static INLINE double sinc(double val)
|
||||
{
|
||||
if (fabs(val) < 0.00001)
|
||||
return 1.0;
|
||||
return sin(val) / val;
|
||||
}
|
||||
|
||||
/**
|
||||
* paeth:
|
||||
*
|
||||
* Pure function.
|
||||
* Paeth prediction filter.
|
||||
**/
|
||||
static INLINE int paeth(int a, int b, int c)
|
||||
{
|
||||
int p = a + b - c;
|
||||
int pa = abs(p - a);
|
||||
int pb = abs(p - b);
|
||||
int pc = abs(p - c);
|
||||
|
||||
if (pa <= pb && pa <= pc)
|
||||
return a;
|
||||
else if (pb <= pc)
|
||||
return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* besseli0:
|
||||
*
|
||||
* Pure function.
|
||||
*
|
||||
* Modified Bessel function of first order.
|
||||
* Check Wiki for mathematical definition ...
|
||||
**/
|
||||
static INLINE double besseli0(double x)
|
||||
{
|
||||
int i;
|
||||
double sum = 0.0;
|
||||
double factorial = 1.0;
|
||||
double factorial_mult = 0.0;
|
||||
double x_pow = 1.0;
|
||||
double two_div_pow = 1.0;
|
||||
double x_sqr = x * x;
|
||||
|
||||
/* Approximate. This is an infinite sum.
|
||||
* Luckily, it converges rather fast. */
|
||||
for (i = 0; i < 18; i++)
|
||||
{
|
||||
sum += x_pow * two_div_pow / (factorial * factorial);
|
||||
factorial_mult += 1.0;
|
||||
x_pow *= x_sqr;
|
||||
two_div_pow *= 0.25;
|
||||
factorial *= factorial_mult;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static INLINE double kaiser_window_function(double index, double beta)
|
||||
{
|
||||
return besseli0(beta * sqrtf(1 - index * index));
|
||||
}
|
||||
|
||||
#endif
|
102
platform/libretro/libretro-common/include/formats/image.h
Normal file
102
platform/libretro/libretro-common/include/formats/image.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (image.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_IMAGE_CONTEXT_H
|
||||
#define __RARCH_IMAGE_CONTEXT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
enum image_process_code
|
||||
{
|
||||
IMAGE_PROCESS_ERROR = -2,
|
||||
IMAGE_PROCESS_ERROR_END = -1,
|
||||
IMAGE_PROCESS_NEXT = 0,
|
||||
IMAGE_PROCESS_END = 1
|
||||
};
|
||||
|
||||
struct texture_image
|
||||
{
|
||||
uint32_t *pixels;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
bool supports_rgba;
|
||||
};
|
||||
|
||||
enum image_type_enum
|
||||
{
|
||||
IMAGE_TYPE_NONE = 0,
|
||||
IMAGE_TYPE_PNG,
|
||||
IMAGE_TYPE_JPEG,
|
||||
IMAGE_TYPE_BMP,
|
||||
IMAGE_TYPE_TGA
|
||||
};
|
||||
|
||||
enum image_type_enum image_texture_get_type(const char *path);
|
||||
|
||||
bool image_texture_set_color_shifts(unsigned *r_shift, unsigned *g_shift,
|
||||
unsigned *b_shift, unsigned *a_shift,
|
||||
struct texture_image *out_img);
|
||||
|
||||
bool image_texture_color_convert(unsigned r_shift,
|
||||
unsigned g_shift, unsigned b_shift, unsigned a_shift,
|
||||
struct texture_image *out_img);
|
||||
|
||||
bool image_texture_load_buffer(struct texture_image *img,
|
||||
enum image_type_enum type, void *buffer, size_t buffer_len);
|
||||
|
||||
bool image_texture_load(struct texture_image *img, const char *path);
|
||||
void image_texture_free(struct texture_image *img);
|
||||
|
||||
/* Image transfer */
|
||||
|
||||
void image_transfer_free(void *data, enum image_type_enum type);
|
||||
|
||||
void *image_transfer_new(enum image_type_enum type);
|
||||
|
||||
bool image_transfer_start(void *data, enum image_type_enum type);
|
||||
|
||||
void image_transfer_set_buffer_ptr(
|
||||
void *data,
|
||||
enum image_type_enum type,
|
||||
void *ptr,
|
||||
size_t len);
|
||||
|
||||
int image_transfer_process(
|
||||
void *data,
|
||||
enum image_type_enum type,
|
||||
uint32_t **buf, size_t size,
|
||||
unsigned *width, unsigned *height);
|
||||
|
||||
bool image_transfer_iterate(void *data, enum image_type_enum type);
|
||||
|
||||
bool image_transfer_is_valid(void *data, enum image_type_enum type);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
64
platform/libretro/libretro-common/include/formats/rpng.h
Normal file
64
platform/libretro/libretro-common/include/formats/rpng.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rpng.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_FORMAT_RPNG_H__
|
||||
#define __LIBRETRO_SDK_FORMAT_RPNG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct rpng rpng_t;
|
||||
|
||||
rpng_t *rpng_init(const char *path);
|
||||
|
||||
bool rpng_is_valid(rpng_t *rpng);
|
||||
|
||||
bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len);
|
||||
|
||||
rpng_t *rpng_alloc(void);
|
||||
|
||||
void rpng_free(rpng_t *rpng);
|
||||
|
||||
bool rpng_iterate_image(rpng_t *rpng);
|
||||
|
||||
int rpng_process_image(rpng_t *rpng,
|
||||
void **data, size_t size, unsigned *width, unsigned *height);
|
||||
|
||||
bool rpng_start(rpng_t *rpng);
|
||||
|
||||
bool rpng_save_image_argb(const char *path, const uint32_t *data,
|
||||
unsigned width, unsigned height, unsigned pitch);
|
||||
bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
|
||||
unsigned width, unsigned height, unsigned pitch);
|
||||
|
||||
uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
|
||||
unsigned width, unsigned height, signed pitch, uint64_t *bytes);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
190
platform/libretro/libretro-common/include/retro_math.h
Normal file
190
platform/libretro/libretro-common/include/retro_math.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_math.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_COMMON_MATH_H
|
||||
#define _LIBRETRO_COMMON_MATH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
#include <retro_inline.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#if !defined(USE_MATH_DEFINES)
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* next_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get next power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: next power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t next_pow2(uint32_t v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* prev_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get previous power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: previous power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t prev_pow2(uint32_t v)
|
||||
{
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return v - (v >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* clamp:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get the clamped value based on initial value.
|
||||
*
|
||||
* Returns: clamped value (derived from @v).
|
||||
**/
|
||||
static INLINE float clamp_value(float v, float min, float max)
|
||||
{
|
||||
return v <= min ? min : v >= max ? max : v;
|
||||
}
|
||||
|
||||
/**
|
||||
* saturate_value:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get the clamped 0.0-1.0 value based on initial value.
|
||||
*
|
||||
* Returns: clamped 0.0-1.0 value (derived from @v).
|
||||
**/
|
||||
static INLINE float saturate_value(float v)
|
||||
{
|
||||
return clamp_value(v, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* dot_product:
|
||||
* @a : left hand vector value
|
||||
* @b : right hand vector value
|
||||
*
|
||||
* Get the dot product of the two passed in vectors.
|
||||
*
|
||||
* Returns: dot product value (derived from @a and @b).
|
||||
**/
|
||||
static INLINE float dot_product(const float* a, const float* b)
|
||||
{
|
||||
return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_rgb_to_yxy:
|
||||
* @rgb : in RGB colour space value
|
||||
* @Yxy : out Yxy colour space value
|
||||
*
|
||||
* Convert from RGB colour space to Yxy colour space.
|
||||
*
|
||||
* Returns: Yxy colour space value (derived from @rgb).
|
||||
**/
|
||||
static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)
|
||||
{
|
||||
float inv;
|
||||
float xyz[3];
|
||||
float one[3] = {1.0, 1.0, 1.0};
|
||||
float rgb_xyz[3][3] = {
|
||||
{0.4124564, 0.3575761, 0.1804375},
|
||||
{0.2126729, 0.7151522, 0.0721750},
|
||||
{0.0193339, 0.1191920, 0.9503041}
|
||||
};
|
||||
|
||||
xyz[0] = dot_product(rgb_xyz[0], rgb);
|
||||
xyz[1] = dot_product(rgb_xyz[1], rgb);
|
||||
xyz[2] = dot_product(rgb_xyz[2], rgb);
|
||||
|
||||
inv = 1.0f / dot_product(xyz, one);
|
||||
Yxy[0] = xyz[1];
|
||||
Yxy[1] = xyz[0] * inv;
|
||||
Yxy[2] = xyz[1] * inv;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_yxy_to_rgb:
|
||||
* @rgb : in Yxy colour space value
|
||||
* @Yxy : out rgb colour space value
|
||||
*
|
||||
* Convert from Yxy colour space to rgb colour space.
|
||||
*
|
||||
* Returns: rgb colour space value (derived from @Yxy).
|
||||
**/
|
||||
static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
|
||||
{
|
||||
float xyz[3];
|
||||
float xyz_rgb[3][3] = {
|
||||
{3.2404542, -1.5371385, -0.4985314},
|
||||
{-0.9692660, 1.8760108, 0.0415560},
|
||||
{0.0556434, -0.2040259, 1.0572252}
|
||||
};
|
||||
xyz[0] = Yxy[0] * Yxy[1] / Yxy[2];
|
||||
xyz[1] = Yxy[0];
|
||||
xyz[2] = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];
|
||||
|
||||
rgb[0] = dot_product(xyz_rgb[0], xyz);
|
||||
rgb[1] = dot_product(xyz_rgb[1], xyz);
|
||||
rgb[2] = dot_product(xyz_rgb[2], xyz);
|
||||
}
|
||||
|
||||
#endif
|
106
platform/libretro/libretro-common/include/streams/trans_stream.h
Normal file
106
platform/libretro/libretro-common/include/streams/trans_stream.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (trans_stream.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBRETRO_SDK_TRANS_STREAM_H__
|
||||
#define LIBRETRO_SDK_TRANS_STREAM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
enum trans_stream_error
|
||||
{
|
||||
TRANS_STREAM_ERROR_NONE = 0,
|
||||
TRANS_STREAM_ERROR_AGAIN, /* more work to do */
|
||||
TRANS_STREAM_ERROR_ALLOCATION_FAILURE, /* malloc failure */
|
||||
TRANS_STREAM_ERROR_INVALID, /* invalid state */
|
||||
TRANS_STREAM_ERROR_BUFFER_FULL, /* output buffer full */
|
||||
TRANS_STREAM_ERROR_OTHER
|
||||
};
|
||||
|
||||
struct trans_stream_backend
|
||||
{
|
||||
const char *ident;
|
||||
const struct trans_stream_backend *reverse;
|
||||
|
||||
/* Create a stream data structure */
|
||||
void *(*stream_new)(void);
|
||||
|
||||
/* Free it */
|
||||
void (*stream_free)(void *);
|
||||
|
||||
/* (Optional) Set extra properties, defined per transcoder */
|
||||
bool (*define)(void *, const char *, uint32_t);
|
||||
|
||||
/* Set our input source */
|
||||
void (*set_in)(void *, const uint8_t *, uint32_t);
|
||||
|
||||
/* Set our output target */
|
||||
void (*set_out)(void *, uint8_t *, uint32_t);
|
||||
|
||||
/* Perform a transcoding, flushing/finalizing if asked to. Writes out how
|
||||
* many bytes were read and written. Error target optional. */
|
||||
bool (*trans)(void *, bool, uint32_t *, uint32_t *, enum trans_stream_error *);
|
||||
};
|
||||
|
||||
/**
|
||||
* trans_stream_trans_full:
|
||||
* @backend : transcoding backend
|
||||
* @data : (optional) existing stream data, or a target
|
||||
* for the new stream data to be saved
|
||||
* @in : input data
|
||||
* @in_size : input size
|
||||
* @out : output data
|
||||
* @out_size : output size
|
||||
* @error : (optional) output for error code
|
||||
*
|
||||
* Perform a full transcoding from a source to a destination.
|
||||
*/
|
||||
bool trans_stream_trans_full(
|
||||
struct trans_stream_backend *backend, void **data,
|
||||
const uint8_t *in, uint32_t in_size,
|
||||
uint8_t *out, uint32_t out_size,
|
||||
enum trans_stream_error *error);
|
||||
|
||||
const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void);
|
||||
const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void);
|
||||
const struct trans_stream_backend* trans_stream_get_pipe_backend(void);
|
||||
|
||||
extern const struct trans_stream_backend zlib_deflate_backend;
|
||||
extern const struct trans_stream_backend zlib_inflate_backend;
|
||||
extern const struct trans_stream_backend pipe_backend;
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
92
platform/libretro/libretro-common/streams/trans_stream.c
Normal file
92
platform/libretro/libretro-common/streams/trans_stream.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (trans_stream.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <streams/trans_stream.h>
|
||||
|
||||
/**
|
||||
* trans_stream_trans_full:
|
||||
* @data : (optional) existing stream data, or a target
|
||||
* for the new stream data to be saved
|
||||
* @in : input data
|
||||
* @in_size : input size
|
||||
* @out : output data
|
||||
* @out_size : output size
|
||||
* @error : (optional) output for error code
|
||||
*
|
||||
* Perform a full transcoding from a source to a destination.
|
||||
*/
|
||||
bool trans_stream_trans_full(
|
||||
struct trans_stream_backend *backend, void **data,
|
||||
const uint8_t *in, uint32_t in_size,
|
||||
uint8_t *out, uint32_t out_size,
|
||||
enum trans_stream_error *error)
|
||||
{
|
||||
void *rdata;
|
||||
bool ret;
|
||||
uint32_t rd, wn;
|
||||
|
||||
if (data && *data)
|
||||
rdata = *data;
|
||||
else
|
||||
{
|
||||
if (!(rdata = backend->stream_new()))
|
||||
{
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_ALLOCATION_FAILURE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
backend->set_in(rdata, in, in_size);
|
||||
backend->set_out(rdata, out, out_size);
|
||||
ret = backend->trans(rdata, true, &rd, &wn, error);
|
||||
|
||||
if (data)
|
||||
*data = rdata;
|
||||
else
|
||||
backend->stream_free(rdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void)
|
||||
{
|
||||
#if HAVE_ZLIB
|
||||
return &zlib_deflate_backend;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void)
|
||||
{
|
||||
#if HAVE_ZLIB
|
||||
return &zlib_inflate_backend;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct trans_stream_backend* trans_stream_get_pipe_backend(void)
|
||||
{
|
||||
return &pipe_backend;
|
||||
}
|
111
platform/libretro/libretro-common/streams/trans_stream_pipe.c
Normal file
111
platform/libretro/libretro-common/streams/trans_stream_pipe.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (trans_stream_pipe.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <streams/trans_stream.h>
|
||||
|
||||
struct pipe_trans_stream
|
||||
{
|
||||
const uint8_t *in;
|
||||
uint8_t *out;
|
||||
uint32_t in_size, out_size;
|
||||
};
|
||||
|
||||
static void *pipe_stream_new(void)
|
||||
{
|
||||
struct pipe_trans_stream *stream =
|
||||
(struct pipe_trans_stream*)malloc(sizeof(*stream));
|
||||
if (!stream)
|
||||
return NULL;
|
||||
|
||||
stream->in = NULL;
|
||||
stream->out = NULL;
|
||||
stream->in_size = 0;
|
||||
stream->out_size = 0;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static void pipe_stream_free(void *data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void pipe_set_in(void *data, const uint8_t *in, uint32_t in_size)
|
||||
{
|
||||
struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
p->in = in;
|
||||
p->in_size = in_size;
|
||||
}
|
||||
|
||||
static void pipe_set_out(void *data, uint8_t *out, uint32_t out_size)
|
||||
{
|
||||
struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
p->out = out;
|
||||
p->out_size = out_size;
|
||||
}
|
||||
|
||||
static bool pipe_trans(
|
||||
void *data, bool flush,
|
||||
uint32_t *rd, uint32_t *wn,
|
||||
enum trans_stream_error *error)
|
||||
{
|
||||
struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;
|
||||
|
||||
if (p->out_size < p->in_size)
|
||||
{
|
||||
memcpy(p->out, p->in, p->out_size);
|
||||
*rd = *wn = p->out_size;
|
||||
p->in += p->out_size;
|
||||
p->out += p->out_size;
|
||||
*error = TRANS_STREAM_ERROR_BUFFER_FULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(p->out, p->in, p->in_size);
|
||||
*rd = *wn = p->in_size;
|
||||
p->in += p->in_size;
|
||||
p->out += p->in_size;
|
||||
*error = TRANS_STREAM_ERROR_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
const struct trans_stream_backend pipe_backend = {
|
||||
"pipe",
|
||||
&pipe_backend,
|
||||
pipe_stream_new,
|
||||
pipe_stream_free,
|
||||
NULL,
|
||||
pipe_set_in,
|
||||
pipe_set_out,
|
||||
pipe_trans
|
||||
};
|
330
platform/libretro/libretro-common/streams/trans_stream_zlib.c
Normal file
330
platform/libretro/libretro-common/streams/trans_stream_zlib.c
Normal file
|
@ -0,0 +1,330 @@
|
|||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (trans_stream_zlib.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zlib.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <streams/trans_stream.h>
|
||||
|
||||
struct zlib_trans_stream
|
||||
{
|
||||
z_stream z;
|
||||
int ex; /* window_bits or level */
|
||||
bool inited;
|
||||
};
|
||||
|
||||
static void *zlib_deflate_stream_new(void)
|
||||
{
|
||||
struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
|
||||
malloc(sizeof(*ret));
|
||||
if (!ret)
|
||||
return NULL;
|
||||
ret->inited = false;
|
||||
ret->ex = 9;
|
||||
|
||||
ret->z.next_in = NULL;
|
||||
ret->z.avail_in = 0;
|
||||
ret->z.total_in = 0;
|
||||
ret->z.next_out = NULL;
|
||||
ret->z.avail_out = 0;
|
||||
ret->z.total_out = 0;
|
||||
|
||||
ret->z.msg = NULL;
|
||||
ret->z.state = NULL;
|
||||
|
||||
ret->z.zalloc = NULL;
|
||||
ret->z.zfree = NULL;
|
||||
ret->z.opaque = NULL;
|
||||
|
||||
ret->z.data_type = 0;
|
||||
ret->z.adler = 0;
|
||||
ret->z.reserved = 0;
|
||||
return (void *)ret;
|
||||
}
|
||||
|
||||
static void *zlib_inflate_stream_new(void)
|
||||
{
|
||||
struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
|
||||
malloc(sizeof(*ret));
|
||||
if (!ret)
|
||||
return NULL;
|
||||
ret->inited = false;
|
||||
ret->ex = MAX_WBITS;
|
||||
|
||||
ret->z.next_in = NULL;
|
||||
ret->z.avail_in = 0;
|
||||
ret->z.total_in = 0;
|
||||
ret->z.next_out = NULL;
|
||||
ret->z.avail_out = 0;
|
||||
ret->z.total_out = 0;
|
||||
|
||||
ret->z.msg = NULL;
|
||||
ret->z.state = NULL;
|
||||
|
||||
ret->z.zalloc = NULL;
|
||||
ret->z.zfree = NULL;
|
||||
ret->z.opaque = NULL;
|
||||
|
||||
ret->z.data_type = 0;
|
||||
ret->z.adler = 0;
|
||||
ret->z.reserved = 0;
|
||||
return (void *)ret;
|
||||
}
|
||||
|
||||
static void zlib_deflate_stream_free(void *data)
|
||||
{
|
||||
struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
|
||||
if (!z)
|
||||
return;
|
||||
if (z->inited)
|
||||
deflateEnd(&z->z);
|
||||
free(z);
|
||||
}
|
||||
|
||||
static void zlib_inflate_stream_free(void *data)
|
||||
{
|
||||
struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
|
||||
if (!z)
|
||||
return;
|
||||
if (z->inited)
|
||||
inflateEnd(&z->z);
|
||||
if (z)
|
||||
free(z);
|
||||
}
|
||||
|
||||
static bool zlib_deflate_define(void *data, const char *prop, uint32_t val)
|
||||
{
|
||||
struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
|
||||
if (string_is_equal(prop, "level"))
|
||||
{
|
||||
if (z)
|
||||
z->ex = (int) val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool zlib_inflate_define(void *data, const char *prop, uint32_t val)
|
||||
{
|
||||
struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
|
||||
if (string_is_equal(prop, "window_bits"))
|
||||
{
|
||||
if (z)
|
||||
z->ex = (int) val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void zlib_deflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
|
||||
{
|
||||
struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
|
||||
|
||||
if (!z)
|
||||
return;
|
||||
|
||||
z->z.next_in = (uint8_t *) in;
|
||||
z->z.avail_in = in_size;
|
||||
|
||||
if (!z->inited)
|
||||
{
|
||||
deflateInit(&z->z, z->ex);
|
||||
z->inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void zlib_inflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
|
||||
{
|
||||
struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
|
||||
|
||||
if (!z)
|
||||
return;
|
||||
|
||||
z->z.next_in = (uint8_t *) in;
|
||||
z->z.avail_in = in_size;
|
||||
if (!z->inited)
|
||||
{
|
||||
inflateInit2(&z->z, z->ex);
|
||||
z->inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void zlib_set_out(void *data, uint8_t *out, uint32_t out_size)
|
||||
{
|
||||
struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
|
||||
|
||||
if (!z)
|
||||
return;
|
||||
|
||||
z->z.next_out = out;
|
||||
z->z.avail_out = out_size;
|
||||
}
|
||||
|
||||
static bool zlib_deflate_trans(
|
||||
void *data, bool flush,
|
||||
uint32_t *rd, uint32_t *wn,
|
||||
enum trans_stream_error *error)
|
||||
{
|
||||
int zret = 0;
|
||||
bool ret = false;
|
||||
uint32_t pre_avail_in = 0;
|
||||
uint32_t pre_avail_out = 0;
|
||||
struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
|
||||
z_stream *z = &zt->z;
|
||||
|
||||
if (!zt->inited)
|
||||
{
|
||||
deflateInit(z, zt->ex);
|
||||
zt->inited = true;
|
||||
}
|
||||
|
||||
pre_avail_in = z->avail_in;
|
||||
pre_avail_out = z->avail_out;
|
||||
zret = deflate(z, flush ? Z_FINISH : Z_NO_FLUSH);
|
||||
|
||||
if (zret == Z_OK)
|
||||
{
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_AGAIN;
|
||||
}
|
||||
else if (zret == Z_STREAM_END)
|
||||
{
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_OTHER;
|
||||
return false;
|
||||
}
|
||||
ret = true;
|
||||
|
||||
if (z->avail_out == 0)
|
||||
{
|
||||
/* Filled buffer, maybe an error */
|
||||
if (z->avail_in != 0)
|
||||
{
|
||||
ret = false;
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_BUFFER_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
*rd = pre_avail_in - z->avail_in;
|
||||
*wn = pre_avail_out - z->avail_out;
|
||||
|
||||
if (flush && zret == Z_STREAM_END)
|
||||
{
|
||||
deflateEnd(z);
|
||||
zt->inited = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool zlib_inflate_trans(
|
||||
void *data, bool flush,
|
||||
uint32_t *rd, uint32_t *wn,
|
||||
enum trans_stream_error *error)
|
||||
{
|
||||
int zret;
|
||||
bool ret = false;
|
||||
uint32_t pre_avail_in = 0;
|
||||
uint32_t pre_avail_out = 0;
|
||||
struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
|
||||
z_stream *z = &zt->z;
|
||||
|
||||
if (!zt->inited)
|
||||
{
|
||||
inflateInit2(z, zt->ex);
|
||||
zt->inited = true;
|
||||
}
|
||||
|
||||
pre_avail_in = z->avail_in;
|
||||
pre_avail_out = z->avail_out;
|
||||
zret = inflate(z, flush ? Z_FINISH : Z_NO_FLUSH);
|
||||
|
||||
if (zret == Z_OK)
|
||||
{
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_AGAIN;
|
||||
}
|
||||
else if (zret == Z_STREAM_END)
|
||||
{
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_OTHER;
|
||||
return false;
|
||||
}
|
||||
ret = true;
|
||||
|
||||
if (z->avail_out == 0)
|
||||
{
|
||||
/* Filled buffer, maybe an error */
|
||||
if (z->avail_in != 0)
|
||||
{
|
||||
ret = false;
|
||||
if (error)
|
||||
*error = TRANS_STREAM_ERROR_BUFFER_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
*rd = pre_avail_in - z->avail_in;
|
||||
*wn = pre_avail_out - z->avail_out;
|
||||
|
||||
if (flush && zret == Z_STREAM_END)
|
||||
{
|
||||
inflateEnd(z);
|
||||
zt->inited = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct trans_stream_backend zlib_deflate_backend = {
|
||||
"zlib_deflate",
|
||||
&zlib_inflate_backend,
|
||||
zlib_deflate_stream_new,
|
||||
zlib_deflate_stream_free,
|
||||
zlib_deflate_define,
|
||||
zlib_deflate_set_in,
|
||||
zlib_set_out,
|
||||
zlib_deflate_trans
|
||||
};
|
||||
|
||||
const struct trans_stream_backend zlib_inflate_backend = {
|
||||
"zlib_inflate",
|
||||
&zlib_deflate_backend,
|
||||
zlib_inflate_stream_new,
|
||||
zlib_inflate_stream_free,
|
||||
zlib_inflate_define,
|
||||
zlib_inflate_set_in,
|
||||
zlib_set_out,
|
||||
zlib_inflate_trans
|
||||
};
|
|
@ -19,6 +19,10 @@
|
|||
#include <libkern/OSCacheControl.h>
|
||||
#endif
|
||||
|
||||
#include "libretro-common/include/formats/image.h" // really, for IMAGE_PROCESS_NEXT?!?
|
||||
#include "libretro-common/include/formats/rpng.h"
|
||||
#include "libretro-common/include/file/file_path.h"
|
||||
|
||||
#include "libretro-common/include/memmap.h"
|
||||
/* Ouf, libretro-common defines replacement functions, but not the flags :-| */
|
||||
#ifndef PROT_READ
|
||||
|
@ -39,6 +43,7 @@
|
|||
#include <platform/common/upscale.h>
|
||||
#endif
|
||||
#include <platform/common/emu.h>
|
||||
#include <platform/libpicofe/plat.h> // need this for PXMAKE in readpng :-/
|
||||
|
||||
#ifdef _3DS
|
||||
#include "3ds/3ds_utils.h"
|
||||
|
@ -154,8 +159,14 @@ static bool retro_audio_buff_underrun = false;
|
|||
static unsigned audio_latency = 0;
|
||||
static bool update_audio_latency = false;
|
||||
static uint16_t pico_events;
|
||||
int pico_inp_mode, pico_pen_visible;
|
||||
// Sega Pico stuff
|
||||
int pico_inp_mode;
|
||||
int pico_pen_x = 320/2, pico_pen_y = 240/2;
|
||||
static int pico_page;
|
||||
static int pico_w, pico_h;
|
||||
static char pico_overlay_path[PATH_MAX];
|
||||
static unsigned short *pico_overlay;
|
||||
|
||||
|
||||
static void retro_audio_buff_status_cb(
|
||||
bool active, unsigned occupancy, bool underrun_likely)
|
||||
|
@ -1284,7 +1295,7 @@ static const char *find_bios(int *region, const char *cd_fname)
|
|||
f = fopen(path, "rb");
|
||||
if (f != NULL) {
|
||||
log_cb(RETRO_LOG_INFO, "found MSU rom: %s\n", path);
|
||||
fclose(f);
|
||||
fclose(f);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
@ -1454,11 +1465,11 @@ bool retro_load_game(const struct retro_game_info *info)
|
|||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right (green)" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Red Button" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Pen Button" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,"Switch input" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Pen sensor" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Pen visibility" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Previous page" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Next page" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Pen State" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,"Pen on Storyware" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Pen on Pad" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Previous Page" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Next Page" },
|
||||
|
||||
{ 0 },
|
||||
};
|
||||
|
@ -1598,6 +1609,7 @@ bool retro_load_game(const struct retro_game_info *info)
|
|||
break;
|
||||
}
|
||||
|
||||
strncpy(pico_overlay_path, content_path, sizeof(pico_overlay_path)-4);
|
||||
if (PicoIn.AHW & PAHW_PICO)
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc_pico);
|
||||
else if (PicoIn.AHW & PAHW_SMS)
|
||||
|
@ -2060,34 +2072,160 @@ void emu_status_msg(const char *format, ...)
|
|||
static void draw_pico_ptr(void)
|
||||
{
|
||||
int up = (PicoPicohw.pen_pos[0]|PicoPicohw.pen_pos[1]) & 0x8000;
|
||||
int x, y, pitch = vout_width, offs;
|
||||
int x, y, pitch = vout_width;
|
||||
unsigned short *p = (unsigned short *)((char *)vout_buf + vout_offset);
|
||||
int o = (up ? 0x0000 : 0xffff), _ = (up ? 0xffff : 0x0000);
|
||||
// storyware pages are actually squished, 2:1
|
||||
int h = (pico_inp_mode == 1 ? 160 : vout_height);
|
||||
if (h < 224) y++;
|
||||
|
||||
x = ((pico_pen_x * vout_width * ((1ULL<<32) / 320 + 1)) >> 32);
|
||||
y = ((pico_pen_y * vout_height * ((1ULL<<32) / 224 + 1)) >> 32);
|
||||
x = ((pico_pen_x * vout_width * ((1ULL<<32) / 320 + 1)) >> 32);
|
||||
y = ((pico_pen_y * h * ((1ULL<<32) / 224 + 1)) >> 32);
|
||||
p += x + y * pitch;
|
||||
|
||||
p[-pitch-1] ^= _; p[-pitch] ^= o; p[-pitch+1] ^= _;
|
||||
p[-1] ^= o; p[0] ^= o; p[1] ^= o;
|
||||
p[pitch-1] ^= _; p[pitch] ^= o; p[pitch+1] ^= _;
|
||||
p[-pitch-1] ^= o; p[-pitch] ^= _; p[-pitch+1] ^= _; p[-pitch+2] ^= o;
|
||||
p[-1] ^= _; p[0] ^= o; p[1] ^= o; p[2] ^= _;
|
||||
p[pitch-1] ^= _; p[pitch] ^= o; p[pitch+1] ^= o; p[pitch+2] ^= _;
|
||||
p[2*pitch-1]^= o; p[2*pitch]^= _; p[2*pitch+1]^= _; p[2*pitch+2]^= o;
|
||||
}
|
||||
|
||||
static int readpng(unsigned short *dest, const char *fname, int req_w, int req_h)
|
||||
{
|
||||
rpng_t *rpng = rpng_alloc();
|
||||
FILE *pf = fopen(fname, "rb");
|
||||
void *png = NULL, *img = NULL;
|
||||
size_t len;
|
||||
unsigned int x, y, w = req_w, h = req_h;
|
||||
int ret = -1;
|
||||
|
||||
if (!rpng || !pf) {
|
||||
lprintf("can't read png file %s", fname);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// who designed this, reading the whole file for inflating, really?
|
||||
fseek(pf, 0, SEEK_END);
|
||||
len = ftell(pf);
|
||||
fseek(pf, 0, SEEK_SET);
|
||||
if (!(png = malloc(len))) {
|
||||
lprintf("oom while reading png file %s", fname);
|
||||
goto done;
|
||||
}
|
||||
fread(png, 1, len, pf);
|
||||
|
||||
// again, who designed this? why all this superfluous iterating here?
|
||||
rpng_set_buf_ptr(rpng, png, len);
|
||||
rpng_start(rpng);
|
||||
while (rpng_iterate_image(rpng));
|
||||
do {
|
||||
ret = rpng_process_image(rpng, &img, len, &w, &h);
|
||||
} while (ret == IMAGE_PROCESS_NEXT);
|
||||
|
||||
// there's already a scaled pngread in libpicofe, but who cares :-/
|
||||
if (img && rpng_is_valid(rpng)) {
|
||||
int x_scale = w*65536 / req_w;
|
||||
int y_scale = h*65536 / req_h;
|
||||
int x_ofs, y_ofs, x_pos, y_pos;
|
||||
|
||||
if (x_scale < y_scale)
|
||||
x_scale = y_scale;
|
||||
else y_scale = x_scale;
|
||||
x_ofs = req_w - w*65536 / x_scale;
|
||||
y_ofs = req_h - h*65536 / y_scale;
|
||||
|
||||
dest += y_ofs/2*req_w + x_ofs/2;
|
||||
for (y_pos = 0; y_pos < h*65536; y_pos += y_scale+1)
|
||||
{
|
||||
unsigned char *src = (unsigned char *)img + 4*w*(y_pos >> 16);
|
||||
for (x_pos = 0, len = 0; x_pos < w*65536; x_pos += x_scale+1, len++)
|
||||
{
|
||||
// to add insult to injury, rpng writes the image endian dependant!
|
||||
unsigned int d = *(unsigned int *)&src[4*(x_pos >> 16)];
|
||||
int r = d >> 16, g = d >> 8, b = d;
|
||||
*dest++ = PXMAKE(r & 0xff, g & 0xff, b & 0xff);
|
||||
}
|
||||
dest += req_w - len;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
if (img) free(img);
|
||||
if (png) free(png);
|
||||
if (pf) fclose(pf);
|
||||
rpng_free(rpng);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned short *load_pico_overlay(int page, int w, int h)
|
||||
{
|
||||
static const char *pic_exts[] = { "png", "PNG" };
|
||||
char buffer[PATH_MAX];
|
||||
char *ext, *fname = NULL;
|
||||
int extpos, i;
|
||||
|
||||
if (pico_page == page && pico_w == w && pico_h == h)
|
||||
return pico_overlay;
|
||||
pico_page = page;
|
||||
pico_w = w, pico_h = h;
|
||||
|
||||
ext = strrchr(pico_overlay_path, '.');
|
||||
extpos = ext ? ext-pico_overlay_path : strlen(pico_overlay_path);
|
||||
strcpy(buffer, pico_overlay_path);
|
||||
buffer[extpos++] = '_';
|
||||
if (page < 0) {
|
||||
buffer[extpos++] = 'p';
|
||||
buffer[extpos++] = 'a';
|
||||
buffer[extpos++] = 'd';
|
||||
} else
|
||||
buffer[extpos++] = '0'+PicoPicohw.page;
|
||||
buffer[extpos++] = '.';
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pic_exts); i++) {
|
||||
strcpy(buffer+extpos, pic_exts[i]);
|
||||
if (path_is_valid(buffer) == RETRO_VFS_STAT_IS_VALID) {
|
||||
printf("found Pico file: %s\n", buffer);
|
||||
fname = buffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pico_overlay = realloc(pico_overlay, w*h*2);
|
||||
memset(pico_overlay, 0, w*h*2);
|
||||
if (!fname || !pico_overlay || readpng(pico_overlay, fname, w, h)) {
|
||||
if (pico_overlay)
|
||||
free(pico_overlay);
|
||||
pico_overlay = NULL;
|
||||
}
|
||||
|
||||
return pico_overlay;
|
||||
}
|
||||
|
||||
void emu_pico_overlay(u16 *pd, int w, int h, int pitch)
|
||||
{
|
||||
u16 *overlay = NULL;
|
||||
int y, oh = h;
|
||||
|
||||
// get overlay
|
||||
if (pico_inp_mode == 1) {
|
||||
oh = (w/2 < h ? w/2 : h); // storyware has squished h
|
||||
overlay = load_pico_overlay(PicoPicohw.page, w, oh);
|
||||
} else if (pico_inp_mode == 2)
|
||||
overlay = load_pico_overlay(-1, w, oh);
|
||||
|
||||
// copy overlay onto buffer
|
||||
if (overlay) {
|
||||
for (y = 0; y < oh; y++)
|
||||
memcpy(pd + y*pitch, overlay + y*w, w*2);
|
||||
if (y < h)
|
||||
memset(pd + y*pitch, 0, w*2);
|
||||
}
|
||||
}
|
||||
|
||||
void run_events_pico(unsigned int events)
|
||||
{
|
||||
int lim_x;
|
||||
|
||||
if (events & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT)) {
|
||||
pico_inp_mode++;
|
||||
if (pico_inp_mode > 2)
|
||||
pico_inp_mode = 0;
|
||||
switch (pico_inp_mode) {
|
||||
case 2: emu_status_msg("Input: Pen on Pad"); break;
|
||||
case 1: emu_status_msg("Input: Pen on Storyware"); break;
|
||||
case 0: emu_status_msg("Input: Joystick"); break;
|
||||
}
|
||||
PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
|
||||
}
|
||||
if (events & (1 << RETRO_DEVICE_ID_JOYPAD_L)) {
|
||||
PicoPicohw.page--;
|
||||
if (PicoPicohw.page < 0)
|
||||
|
@ -2101,8 +2239,22 @@ void run_events_pico(unsigned int events)
|
|||
emu_status_msg("Page %i", PicoPicohw.page);
|
||||
}
|
||||
if (events & (1 << RETRO_DEVICE_ID_JOYPAD_X)) {
|
||||
pico_pen_visible = !pico_pen_visible;
|
||||
emu_status_msg("%s Pen", pico_pen_visible ? "Show" : "Hide");
|
||||
if (pico_inp_mode == 2) {
|
||||
pico_inp_mode = 0;
|
||||
emu_status_msg("Input: D-Pad");
|
||||
} else {
|
||||
pico_inp_mode = 2;
|
||||
emu_status_msg("Input: Pen on Pad");
|
||||
}
|
||||
}
|
||||
if (events & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT)) {
|
||||
if (pico_inp_mode == 1) {
|
||||
pico_inp_mode = 0;
|
||||
emu_status_msg("Input: D-Pad");
|
||||
} else {
|
||||
pico_inp_mode = 1;
|
||||
emu_status_msg("Input: Pen on Storyware");
|
||||
}
|
||||
}
|
||||
if (events & (1 << RETRO_DEVICE_ID_JOYPAD_START)) {
|
||||
PicoPicohw.pen_pos[0] ^= 0x8000;
|
||||
|
@ -2110,6 +2262,10 @@ void run_events_pico(unsigned int events)
|
|||
emu_status_msg("Pen %s", PicoPicohw.pen_pos[0] & 0x8000 ? "Up" : "Down");
|
||||
}
|
||||
|
||||
if ((PicoIn.pad[0] & 0x20) && pico_inp_mode && pico_overlay) {
|
||||
pico_inp_mode = 0;
|
||||
emu_status_msg("Input: D-Pad");
|
||||
}
|
||||
if (pico_inp_mode == 0)
|
||||
return;
|
||||
|
||||
|
@ -2122,12 +2278,12 @@ void run_events_pico(unsigned int events)
|
|||
|
||||
if (pico_pen_y < PICO_PEN_ADJUST_Y)
|
||||
pico_pen_y = PICO_PEN_ADJUST_Y;
|
||||
if (pico_pen_y > 224-1 - PICO_PEN_ADJUST_Y)
|
||||
pico_pen_y = 224-1 - PICO_PEN_ADJUST_Y;
|
||||
if (pico_pen_y > 223-1 - PICO_PEN_ADJUST_Y)
|
||||
pico_pen_y = 223-1 - PICO_PEN_ADJUST_Y;
|
||||
if (pico_pen_x < PICO_PEN_ADJUST_X)
|
||||
pico_pen_x = PICO_PEN_ADJUST_X;
|
||||
if (pico_pen_x > 320-1 - PICO_PEN_ADJUST_X)
|
||||
pico_pen_x = 320-1 - PICO_PEN_ADJUST_X;
|
||||
if (pico_pen_x > 319-1 - PICO_PEN_ADJUST_X)
|
||||
pico_pen_x = 319-1 - PICO_PEN_ADJUST_X;
|
||||
|
||||
PicoPicohw.pen_pos[0] &= 0x8000;
|
||||
PicoPicohw.pen_pos[1] &= 0x8000;
|
||||
|
@ -2332,8 +2488,15 @@ void retro_run(void)
|
|||
}
|
||||
}
|
||||
|
||||
if ((PicoIn.AHW & PAHW_PICO) && pico_pen_visible)
|
||||
if (pico_inp_mode) draw_pico_ptr();
|
||||
if (PicoIn.AHW & PAHW_PICO) {
|
||||
int h = vout_height, w = vout_width;
|
||||
unsigned short *pd = (unsigned short *)((char *)vout_buf + vout_offset);
|
||||
|
||||
if (pico_inp_mode)
|
||||
emu_pico_overlay(pd, w, h, vout_width);
|
||||
if (pico_inp_mode /*== 2 || overlay*/)
|
||||
draw_pico_ptr();
|
||||
}
|
||||
|
||||
buff = (char*)vout_buf + vout_offset;
|
||||
#endif
|
||||
|
@ -2445,9 +2608,13 @@ void retro_deinit(void)
|
|||
free(vout_buf);
|
||||
#endif
|
||||
vout_buf = NULL;
|
||||
|
||||
if (vout_ghosting_buf)
|
||||
free(vout_ghosting_buf);
|
||||
vout_ghosting_buf = NULL;
|
||||
if (pico_overlay)
|
||||
free(pico_overlay);
|
||||
pico_overlay = NULL;
|
||||
|
||||
libretro_supports_bitmasks = false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue