libretro, add Pico pad overlay and storyware pages handling

This commit is contained in:
kub 2024-03-25 18:49:19 +01:00
parent 15cc45c0da
commit 5f9901e098
17 changed files with 3415 additions and 477 deletions

File diff suppressed because it is too large Load diff

View 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;
}

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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);

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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
};

View 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
};

View file

@ -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;
}