Conflicts:
	qb/config.libs.sh
This commit is contained in:
Toad King 2012-06-18 18:50:22 -04:00
commit 4f3e54529b
77 changed files with 1074 additions and 504 deletions

View File

@ -320,7 +320,7 @@ begin_shutdown:
if(path_file_exists(SYS_CONFIG_FILE))
rarch_config_save(SYS_CONFIG_FILE);
menu_deinit();
menu_free();
video_xdk360.stop();
input_xdk360.free(NULL);
rarch_exec();

View File

@ -70,10 +70,12 @@ static void filebrowser_fetch_directory_entries(const char *path, filebrowser_t
rompath_title->SetText(strw_buffer);
romlist->DeleteItems(0, romlist->GetItemCount());
romlist->InsertItems(0, browser->file_count);
for(unsigned i = 0; i < browser->file_count; i++)
romlist->InsertItems(0, browser->current_dir.size);
for(unsigned i = 0; i < browser->current_dir.size; i++)
{
rarch_convert_char_to_wchar(strw_buffer, browser->cur[i].d_name, sizeof(strw_buffer));
char fname_tmp[256];
fill_pathname_base(fname_tmp, browser->current_dir.elems[i], sizeof(fname_tmp));
rarch_convert_char_to_wchar(strw_buffer, fname_tmp, sizeof(strw_buffer));
romlist->SetText(i, strw_buffer);
}
}
@ -524,13 +526,12 @@ HRESULT CRetroArchFileBrowser::OnNotifyPress( HXUIOBJ hObjPressed, BOOL& bHandle
if(hObjPressed == m_romlist)
{
int index = m_romlist.GetCurSel();
if(browser.cur[index].d_type != FILE_ATTRIBUTE_DIRECTORY)
if(path_file_exists(browser.current_dir.elems[index]))
{
struct retro_system_info info;
retro_get_system_info(&info);
bool block_zip_extract = info.block_extract;
const char * strbuffer = rarch_convert_wchar_to_const_char((const wchar_t*)m_romlist.GetText(index));
const char * strbuffer = rarch_convert_wchar_to_const_char((const wchar_t*)m_romlist.GetText(index));
if((strstr(strbuffer, ".zip") || strstr(strbuffer, ".ZIP")) && !block_zip_extract)
{
@ -545,7 +546,7 @@ HRESULT CRetroArchFileBrowser::OnNotifyPress( HXUIOBJ hObjPressed, BOOL& bHandle
rarch_settings_change(S_START_RARCH);
}
}
else if(browser.cur[index].d_type == FILE_ATTRIBUTE_DIRECTORY)
else if(path_is_directory(browser.current_dir.elems[index]))
{
const char * strbuffer = rarch_convert_wchar_to_const_char((const wchar_t *)m_romlist.GetText(index));
@ -578,7 +579,7 @@ HRESULT CRetroArchShaderBrowser::OnNotifyPress( HXUIOBJ hObjPressed, BOOL& bHand
if(hObjPressed == m_shaderlist)
{
int index = m_shaderlist.GetCurSel();
if(tmp_browser.cur[index].d_type != FILE_ATTRIBUTE_DIRECTORY)
if(path_file_exists(tmp_browser.current_dir.elems[index]))
{
const char * strbuffer = rarch_convert_wchar_to_const_char((const wchar_t *)m_shaderlist.GetText(index));
@ -599,7 +600,7 @@ HRESULT CRetroArchShaderBrowser::OnNotifyPress( HXUIOBJ hObjPressed, BOOL& bHand
if (g_console.info_msg_enable)
rarch_settings_msg(S_MSG_SHADER_LOADING_SUCCEEDED, S_DELAY_180);
}
else if(tmp_browser.cur[index].d_type == FILE_ATTRIBUTE_DIRECTORY)
else if(path_is_directory(tmp_browser.current_dir.elems[index]))
{
const char * strbuffer = rarch_convert_wchar_to_const_char((const wchar_t *)m_shaderlist.GetText(index));
snprintf(path, sizeof(path), "%s\\%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmp_browser), strbuffer);
@ -619,13 +620,13 @@ HRESULT CRetroArchCoreBrowser::OnNotifyPress( HXUIOBJ hObjPressed, BOOL& bHandle
if(hObjPressed == m_romlist)
{
int index = m_romlist.GetCurSel();
if(tmp_browser.cur[index].d_type != FILE_ATTRIBUTE_DIRECTORY)
if(path_file_exists(tmp_browser.current_dir.elems[index]))
{
const char * strbuffer = rarch_convert_wchar_to_const_char((const wchar_t *)m_romlist.GetText(index));
snprintf(g_console.launch_app_on_exit, sizeof(g_console.launch_app_on_exit), "%s\\%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmp_browser), strbuffer);
rarch_settings_change(S_RETURN_TO_LAUNCHER);
}
else if(tmp_browser.cur[index].d_type == FILE_ATTRIBUTE_DIRECTORY)
else if(path_is_directory(tmp_browser.current_dir.elems[index]))
{
const char * strbuffer = rarch_convert_wchar_to_const_char((const wchar_t *)m_romlist.GetText(index));
snprintf(path, sizeof(path), "%s%s\\", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmp_browser), strbuffer);
@ -838,8 +839,10 @@ int menu_init (void)
return 0;
}
void menu_deinit (void)
void menu_free (void)
{
filebrowser_free(&browser);
filebrowser_free(&tmp_browser);
app.Uninit();
}

View File

@ -215,7 +215,7 @@ class CRetroArchControls: public CXuiSceneImpl
};
int menu_init (void);
void menu_deinit (void);
void menu_free (void);
void menu_loop (void);
extern CRetroArch app;

View File

@ -164,6 +164,11 @@ ifeq ($(HAVE_SDL_IMAGE), 1)
DEFINES += $(SDL_IMAGE_CFLAGS)
endif
ifeq ($(HAVE_LIBPNG), 1)
LIBS += $(LIBPNG_LIBS)
DEFINES += $(LIBPNG_CFLAGS)
endif
ifeq ($(HAVE_FFMPEG), 1)
OBJ += record/ffemu.o
LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS)

View File

@ -32,7 +32,6 @@ libretro ?= -lretro
LIBS = -lm
DEFINES = -I. -DHAVE_CONFIGFILE -DHAVE_SDL -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.6\"
LDFLAGS = -L. -static-libgcc
LDCXXFLAGS = -s
ifeq ($(TDM_GCC),)
LDCXXFLAGS += -static-libstdc++
@ -153,7 +152,14 @@ ifneq ($(V), 1)
Q := @
endif
CFLAGS += -Wall -Wno-unused-result -O3 -I.
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g
else
CFLAGS += -O3
LDCXXFLAGS += -s
endif
CFLAGS += -Wall -Wno-unused-result -I.
ifeq ($(CXX_BUILD), 1)
CFLAGS += -std=c++0x -xc++ -D__STDC_CONSTANT_MACROS
else

8
android/.classpath Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

33
android/.project Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>RetroArch</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.source=1.5

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.retroarch"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<!-- Tell the system this app requires OpenGL ES 2.0. -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
</manifest>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
# cache for current jar dependecy. DO NOT EDIT.
# format is <lastModified> <length> <SHA-1> <path>
# Encoding is UTF-8

View File

@ -0,0 +1,6 @@
/** Automatically generated file. DO NOT MODIFY */
package com.retroarch;
public final class BuildConfig {
public final static boolean DEBUG = true;
}

View File

@ -0,0 +1,42 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.retroarch;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int ic_action_close=0x7f020000;
public static final int ic_action_history=0x7f020001;
public static final int ic_action_load=0x7f020002;
public static final int ic_action_open=0x7f020003;
public static final int ic_action_quit=0x7f020004;
public static final int ic_action_save=0x7f020005;
public static final int ic_action_settings=0x7f020006;
public static final int ic_launcher=0x7f020007;
}
public static final class id {
public static final int close=0x7f060001;
public static final int history=0x7f060004;
public static final int load=0x7f060002;
public static final int open=0x7f060000;
public static final int quit=0x7f060006;
public static final int save=0x7f060003;
public static final int settings=0x7f060005;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class menu {
public static final int main_menu=0x7f050000;
}
public static final class string {
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
}
}

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,14 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-15

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
</LinearLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/open" android:showAsAction="ifRoom|withText" android:title="Open ROM" android:icon="@drawable/ic_action_open"></item>
<item android:id="@+id/close" android:showAsAction="collapseActionView" android:title="Close ROM" android:icon="@drawable/ic_action_close"></item>
<item android:id="@+id/load" android:showAsAction="collapseActionView" android:title="Load" android:icon="@drawable/ic_action_load"></item>
<item android:id="@+id/save" android:showAsAction="collapseActionView" android:title="Save" android:icon="@drawable/ic_action_save"></item>
<item android:id="@+id/history" android:showAsAction="collapseActionView" android:title="History" android:icon="@drawable/ic_action_history"></item>
<item android:id="@+id/settings" android:showAsAction="collapseActionView" android:title="Settings" android:icon="@drawable/ic_action_settings"></item>
<item android:id="@+id/quit" android:showAsAction="collapseActionView" android:title="Quit" android:icon="@drawable/ic_action_quit"></item>
</menu>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, MainActivity!</string>
<string name="app_name">RetroArch</string>
</resources>

View File

@ -0,0 +1,69 @@
package com.retroarch;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class MainActivity extends Activity
{
private GLSurfaceView ctx_gl;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ctx_gl = new rgl_context(this);
setContentView(ctx_gl);
}
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.quit:
android.os.Process.killProcess(android.os.Process.myPid());
return true;
default:
Toast.makeText(this, "MenuItem " + item.getTitle() + " selected.", Toast.LENGTH_SHORT).show();
return true;
}
}
@Override
protected void onPause()
{
super.onPause();
ctx_gl.onPause();
}
@Override
protected void onResume()
{
super.onResume();
ctx_gl.onResume();
}
}
class rgl_context extends GLSurfaceView
{
public rgl_context(Context context)
{
super(context);
setEGLContextClientVersion(2);
setRenderer(new rgl());
}
}

View File

@ -0,0 +1,130 @@
package com.retroarch;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
public class audio_android
{
private static AudioTrack _track;
private static int _minSamples;
private static float _volume = AudioTrack.getMaxVolume();
private static int _rate;
private static int _bits;
private static int _channels;
private audio_android()
{
}
public static void pause()
{
if (_track != null && _track.getPlayState() != AudioTrack.PLAYSTATE_PAUSED)
_track.pause();
}
public static void resume()
{
if (_track != null && _track.getPlayState() != AudioTrack.PLAYSTATE_PLAYING)
_track.play();
}
public int getMinSamples()
{
return _minSamples;
}
public static int write(short[] data, int size)
{
int retVal = 0;
if (_track == null)
return retVal;
retVal = _track.write(data, 0, size);
return retVal;
}
void set_volume(int vol)
{
final float min = AudioTrack.getMinVolume();
final float max = AudioTrack.getMaxVolume();
_volume = min + (max - min) * vol / 100;
if (_track != null)
_track.setStereoVolume(_volume, _volume);
}
public static void free()
{
if (_track != null)
{
_track.pause();
_track.release();
_track = null;
}
}
public static boolean init(int rate, int bits, int channels)
{
_track = null;
_rate = rate;
_bits = bits;
_channels = channels;
// generate format
int format = (_bits == 16
? AudioFormat.ENCODING_PCM_16BIT
: AudioFormat.ENCODING_PCM_8BIT);
// determine channel config
int channelConfig = (_channels == 2
? AudioFormat.CHANNEL_OUT_STEREO
: AudioFormat.CHANNEL_OUT_MONO);
int bufferSize = AudioTrack.getMinBufferSize(_rate, channelConfig,
format);
_minSamples = bufferSize;
try
{
_track = new AudioTrack(
AudioManager.STREAM_MUSIC,
_rate,
channelConfig,
format,
bufferSize,
AudioTrack.MODE_STREAM);
if (_track.getState() == AudioTrack.STATE_UNINITIALIZED)
_track = null;
}
catch (IllegalArgumentException e)
{
_track = null;
return false;
}
// set max volume
_track.setStereoVolume(_volume, _volume);
return true;
}
public static int getMaxBufferSize()
{
return _minSamples;
}
}

View File

@ -0,0 +1,95 @@
package com.retroarch;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.ByteOrder;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
public class rgl implements GLSurfaceView.Renderer
{
private int cprg;
private int v_position_handle;
private FloatBuffer triangle_vbo;
private void triangles_init()
{
float triangle_coords[] = {
// X, Y, Z
-0.5f, -0.25f, 0,
0.5f, -0.25f, 0,
0.0f, 0.559016994f, 0
};
ByteBuffer vbb = ByteBuffer.allocateDirect(triangle_coords.length * 4);
vbb.order(ByteOrder.nativeOrder());
triangle_vbo = vbb.asFloatBuffer();
triangle_vbo.put(triangle_coords);
triangle_vbo.position(0);
}
private void shader_init()
{
final String vprg =
"attribute vec4 vPosition; \n" +
"void main(){ \n" +
" gl_Position = vPosition; \n" +
"} \n";
final String fprg =
"precision mediump float; \n" +
"void main(){ \n" +
" gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n" +
"} \n";
int vertex_shader, fragment_shader;
vertex_shader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertex_shader, vprg);
GLES20.glCompileShader(vertex_shader);
fragment_shader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragment_shader, fprg);
GLES20.glCompileShader(fragment_shader);
cprg = GLES20.glCreateProgram();
GLES20.glAttachShader(cprg, vertex_shader);
GLES20.glAttachShader(cprg, fragment_shader);
GLES20.glLinkProgram(cprg);
//get handle to the vertex shader's vPosition member
v_position_handle = GLES20.glGetAttribLocation(cprg, "vPosition");
; }
public void onSurfaceCreated(GL10 unused, EGLConfig config)
{
//background color
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
triangles_init();
shader_init();
}
public void onDrawFrame(GL10 unused)
{
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(cprg);
// Triangle
GLES20.glVertexAttribPointer(v_position_handle, 3, GLES20.GL_FLOAT, false, 12, triangle_vbo);
GLES20.glEnableVertexAttribArray(v_position_handle);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
public void onSurfaceChanged(GL10 unused, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
}
}

View File

@ -110,6 +110,12 @@ static const bool _sdl_image_supp = true;
static const bool _sdl_image_supp = false;
#endif
#ifdef HAVE_LIBPNG
static const bool _libpng_supp = true;
#else
static const bool _libpng_supp = false;
#endif
#ifdef HAVE_FBO
static const bool _fbo_supp = true;
#else

View File

@ -14,216 +14,37 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef _XBOX
#include <xtl.h>
#endif
#include "file_browser.h"
static int less_than_key(const void * a, const void * b)
{
DirectoryEntry * a_dir = (DirectoryEntry*)a;
DirectoryEntry * b_dir = (DirectoryEntry*)b;
/* compare a directory to a file directory is always lesser than*/
if ((a_dir->d_type == FS_TYPES_DIRECTORY && b_dir->d_type == FS_TYPES_FILE))
return -1;
else if (a_dir->d_type == FS_TYPES_FILE && b_dir->d_type == FS_TYPES_DIRECTORY)
return 1;
return strcasecmp(a_dir->d_name, b_dir->d_name);
}
static const char * filebrowser_get_extension(const char * filename)
{
const char * ext = strrchr(filename, '.');
if (ext)
return ext+1;
else
return "";
}
static void filebrowser_clear_current_entries(filebrowser_t * filebrowser)
{
for(uint32_t i = 0; i < MAX_FILE_LIMIT; i++)
{
filebrowser->cur[filebrowser->file_count].d_type = 0;
filebrowser->cur[filebrowser->file_count].d_namlen = 0;
strlcpy(filebrowser->cur[filebrowser->file_count].d_name, "\0", sizeof(filebrowser->cur[filebrowser->file_count].d_name));
}
}
static void filebrowser_parse_directory(filebrowser_t * filebrowser,
const char * path, const char * extensions)
{
int error = 0;
#if defined(_XBOX)
filebrowser->file_count = 0;
strlcpy(filebrowser->dir[filebrowser->directory_stack_size], path,
sizeof(filebrowser->dir[filebrowser->directory_stack_size]));
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
filebrowser->current_dir.elems = dir_list_new(path, extensions, true);
filebrowser->current_dir.size = dir_list_size(filebrowser->current_dir.elems);
filebrowser->current_dir.ptr = 0;
char path_buf[PATH_MAX];
if (strlcpy(path_buf, path, sizeof(path_buf)) >= sizeof(path_buf))
{
error = 1;
goto error;
}
if (strlcat(path_buf, "\\*", sizeof(path_buf)) >= sizeof(path_buf))
{
error = 1;
goto error;
}
hFind = FindFirstFile(path_buf, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
error = 1;
goto error;
}
do
{
strlcpy(filebrowser->dir[filebrowser->directory_stack_size], path, sizeof(filebrowser->dir[filebrowser->directory_stack_size]));
bool found_dir = false;
if(!(ffd.dwFileAttributes & FS_TYPES_DIRECTORY))
{
char tmp_extensions[512];
strlcpy(tmp_extensions, extensions, sizeof(tmp_extensions));
const char * current_extension = filebrowser_get_extension(ffd.cFileName);
bool found_rom = false;
if(current_extension)
{
char * pch = strtok(tmp_extensions, "|");
while (pch != NULL)
{
if(strcmp(current_extension, pch) == 0)
{
found_rom = true;
break;
}
pch = strtok(NULL, "|");
}
}
if(!found_rom)
continue;
}
else if (ffd.dwFileAttributes & FS_TYPES_DIRECTORY)
found_dir = true;
filebrowser->cur[filebrowser->file_count].d_type = found_dir ? FS_TYPES_DIRECTORY : FS_TYPES_FILE;
snprintf(filebrowser->cur[filebrowser->file_count].d_name, sizeof(filebrowser->cur[filebrowser->file_count].d_name), ffd.cFileName);
filebrowser->file_count++;
}while (FindNextFile(hFind, &ffd) != 0 && (filebrowser->file_count + 1) < MAX_FILE_LIMIT);
#elif defined(__CELLOS_LV2__)
int fd;
/* bad path*/
if (strcmp(path,"") == 0)
{
error = 1;
goto error;
}
/* delete old path*/
filebrowser_clear_current_entries(filebrowser);
if (cellFsOpendir(path, &fd) == CELL_FS_SUCCEEDED)
{
uint64_t nread = 0;
strlcpy(filebrowser->dir[filebrowser->directory_stack_size], path, sizeof(filebrowser->dir[filebrowser->directory_stack_size]));
filebrowser->file_count = 0;
filebrowser->currently_selected = 0;
CellFsDirent dirent;
while (cellFsReaddir(fd, &dirent, &nread) == CELL_FS_SUCCEEDED)
{
if (nread == 0)
break;
if ((dirent.d_type != FS_TYPES_FILE) && (dirent.d_type != FS_TYPES_DIRECTORY))
continue;
if (dirent.d_type == FS_TYPES_DIRECTORY && !(strcmp(dirent.d_name, ".")))
continue;
if (dirent.d_type == FS_TYPES_FILE)
{
char tmp_extensions[512];
strlcpy(tmp_extensions, extensions, sizeof(tmp_extensions));
const char * current_extension = filebrowser_get_extension(dirent.d_name);
bool found_rom = false;
if(current_extension)
{
char * pch = strtok(tmp_extensions, "|");
while (pch != NULL)
{
if(strcmp(current_extension, pch) == 0)
{
found_rom = true;
break;
}
pch = strtok(NULL, "|");
}
}
if(!found_rom)
continue;
}
filebrowser->cur[filebrowser->file_count].d_type = dirent.d_type;
filebrowser->cur[filebrowser->file_count].d_namlen = dirent.d_namlen;
strlcpy(filebrowser->cur[filebrowser->file_count].d_name, dirent.d_name, sizeof(filebrowser->cur[filebrowser->file_count].d_name));
++filebrowser->file_count;
}
cellFsClosedir(fd);
}
else
{
error = 1;
goto error;
}
#endif
qsort(filebrowser->cur, filebrowser->file_count, sizeof(DirectoryEntry), less_than_key);
error:
if(error)
{
RARCH_ERR("Failed to open directory: \"%s\"\n", path);
}
#ifdef _XBOX
FindClose(hFind);
#endif
dir_list_sort(filebrowser->current_dir.elems, true);
}
void filebrowser_new(filebrowser_t * filebrowser, const char * start_dir,
const char * extensions)
{
filebrowser_clear_current_entries(filebrowser);
filebrowser->directory_stack_size = 0;
strlcpy(filebrowser->extensions, extensions, sizeof(filebrowser->extensions));
filebrowser_parse_directory(filebrowser, start_dir, filebrowser->extensions);
filebrowser_parse_directory(filebrowser, start_dir, extensions);
}
void filebrowser_reset_start_directory(filebrowser_t * filebrowser, const char * start_dir,
const char * extensions)
void filebrowser_free(filebrowser_t * filebrowser)
{
filebrowser->directory_stack_size = 0;
strlcpy(filebrowser->extensions, extensions, sizeof(filebrowser->extensions));
dir_list_free(filebrowser->current_dir.elems);
filebrowser_parse_directory(filebrowser, start_dir, filebrowser->extensions);
filebrowser->current_dir.elems = NULL;
filebrowser->current_dir.size = 0;
filebrowser->current_dir.ptr = 0;
}
void filebrowser_push_directory(filebrowser_t * filebrowser, const char * path,
@ -244,3 +65,8 @@ void filebrowser_pop_directory (filebrowser_t * filebrowser)
filebrowser_parse_directory(filebrowser, filebrowser->dir[filebrowser->directory_stack_size],
filebrowser->extensions);
}
const char * filebrowser_get_current_path (filebrowser_t *filebrowser)
{
return filebrowser->current_dir.elems[filebrowser->current_dir.ptr];
}

View File

@ -17,89 +17,63 @@
#ifndef FILEBROWSER_H_
#define FILEBROWSER_H_
#define MAXJOLIET 255
#define MAX_DIR_STACK 25
#include <stdint.h>
#include <stdlib.h>
#ifdef __CELLOS_LV2__
#include <stdbool.h>
#include <cell/cell_fs.h>
#include <sys/types.h>
#define FS_MAX_PATH 256
#define FS_MAX_FS_PATH_LENGTH 255
#define MAX_FILE_LIMIT 8192
#elif defined(_XBOX)
#define FS_MAX_PATH MAX_PATH
#define FS_MAX_FS_PATH_LENGTH 2048
#define MAX_FILE_LIMIT 4096
#endif
#if defined(_XBOX)
#define FS_TYPES_DIRECTORY (FILE_ATTRIBUTE_DIRECTORY)
#define FS_TYPES_FILE (FILE_ATTRIBUTE_NORMAL)
#elif defined(__CELLOS_LV2__)
#define FS_TYPES_DIRECTORY (CELL_FS_TYPE_DIRECTORY)
#define FS_TYPES_FILE (CELL_FS_TYPE_REGULAR)
#endif
typedef struct {
uint8_t d_type;
uint8_t d_namlen;
char d_name[FS_MAX_PATH];
} DirectoryEntry;
typedef struct
{
uint32_t file_count; /* amount of files in current dir*/
uint32_t currently_selected; /* currently select browser entry*/
uint32_t directory_stack_size;
char dir[MAX_DIR_STACK][FS_MAX_FS_PATH_LENGTH]; /* info of the current directory*/
DirectoryEntry cur[MAX_FILE_LIMIT]; /* current file listing*/
char extensions[FS_MAX_PATH]; /* allowed extensions*/
char dir[MAX_DIR_STACK][512];
struct {
char **elems;
size_t size;
size_t ptr;
} current_dir;
char extensions[PATH_MAX];
} filebrowser_t;
void filebrowser_new(filebrowser_t * filebrowser, const char * start_dir, const char * extensions);
void filebrowser_reset_start_directory(filebrowser_t * filebrowser, const char * start_dir, const char * extensions);
void filebrowser_new(filebrowser_t *filebrowser, const char * start_dir, const char * extensions);
void filebrowser_free(filebrowser_t *filebrowser);
void filebrowser_push_directory(filebrowser_t * filebrowser, const char * path, bool with_extension);
void filebrowser_pop_directory (filebrowser_t * filebrowser);
#define FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(filebrowser) (filebrowser.dir[filebrowser.directory_stack_size])
#define FILEBROWSER_GET_CURRENT_DIRECTORY_FILE_COUNT(filebrowser) (filebrowser.file_count)
#define FILEBROWSER_GOTO_ENTRY(filebrowser, i) filebrowser.currently_selected = i;
#define FILEBROWSER_GET_CURRENT_DIRECTORY_FILE_COUNT(filebrowser) (filebrowser.current_dir.size)
#define FILEBROWSER_GOTO_ENTRY(filebrowser, i) filebrowser.current_dir.ptr = i;
#define FILEBROWSER_INCREMENT_ENTRY(filebrowser) \
{ \
filebrowser.currently_selected++; \
if (filebrowser.currently_selected >= filebrowser.file_count) \
filebrowser.currently_selected = 0; \
filebrowser.current_dir.ptr++; \
if (filebrowser.current_dir.ptr >= filebrowser.current_dir.size) \
filebrowser.current_dir.ptr = 0; \
}
#define FILEBROWSER_INCREMENT_ENTRY_POINTER(filebrowser) \
{ \
filebrowser->currently_selected++; \
if (filebrowser->currently_selected >= filebrowser->file_count) \
filebrowser->currently_selected = 0; \
filebrowser->current_dir.ptr++; \
if (filebrowser->current_dir.ptr >= filebrowser->current_dir.size) \
filebrowser->current_dir.ptr = 0; \
}
#define FILEBROWSER_DECREMENT_ENTRY(filebrowser) \
{ \
filebrowser.currently_selected--; \
if (filebrowser.currently_selected >= filebrowser.file_count) \
filebrowser.currently_selected = filebrowser.file_count - 1; \
filebrowser.current_dir.ptr--; \
if (filebrowser.current_dir.ptr >= filebrowser.current_dir.size) \
filebrowser.current_dir.ptr = filebrowser.current_dir.size - 1; \
}
#define FILEBROWSER_DECREMENT_ENTRY_POINTER(filebrowser) \
{ \
filebrowser->currently_selected--; \
if (filebrowser->currently_selected >= filebrowser->file_count) \
filebrowser->currently_selected = filebrowser->file_count - 1; \
filebrowser->current_dir.ptr--; \
if (filebrowser->current_dir.ptr >= filebrowser->current_dir.size) \
filebrowser->current_dir.ptr = filebrowser->current_dir.size - 1; \
}
#define FILEBROWSER_GET_CURRENT_FILENAME(filebrowser) (filebrowser.cur[filebrowser.currently_selected].d_name)
#define FILEBROWSER_GET_CURRENT_ENTRY_INDEX(filebrowser) (filebrowser.currently_selected)
#define FILEBROWSER_IS_CURRENT_A_FILE(filebrowser) (filebrowser.cur[filebrowser.currently_selected].d_type == CELL_FS_TYPE_REGULAR)
#define FILEBROWSER_IS_CURRENT_A_DIRECTORY(filebrowser) (filebrowser.cur[filebrowser.currently_selected].d_type == CELL_FS_TYPE_DIRECTORY)
#define FILEBROWSER_GET_CURRENT_FILENAME(filebrowser) (filebrowser.current_dir.elems[filebrowser.current_dir.ptr])
#define FILEBROWSER_GET_CURRENT_ENTRY_INDEX(filebrowser) (filebrowser.current_dir.ptr)
#define FILEBROWSER_IS_CURRENT_A_FILE(filebrowser) (path_file_exists(filebrowser.current_dir.elems[filebrowser.current_dir.ptr]))
#define FILEBROWSER_IS_CURRENT_A_DIRECTORY(filebrowser) (path_is_directory(filebrowser.current_dir.elems[filebrowser.current_dir.ptr]))
#endif /* FILEBROWSER_H_ */

View File

@ -43,13 +43,10 @@ const char *rarch_manage_libretro_install(const char *full_path, const char *pat
// file first.
RARCH_LOG("Upgrading emulator core...\n");
#if defined(__CELLOS_LV2__)
ret = cellFsUnlink(tmp_pathnewfile);
if (ret == CELL_FS_SUCCEEDED)
#elif defined(_XBOX)
ret = DeleteFile(tmp_pathnewfile);
if (ret != 0)
#endif
ret = remove(tmp_pathnewfile);
if (ret == 0)
{
RARCH_LOG("Succeeded in removing pre-existing libretro core: [%s].\n", tmp_pathnewfile);
}
@ -58,26 +55,21 @@ const char *rarch_manage_libretro_install(const char *full_path, const char *pat
}
//now attempt the renaming.
#if defined(__CELLOS_LV2__)
ret = cellFsRename(full_path, tmp_pathnewfile);
ret = rename(full_path, tmp_pathnewfile);
if (ret != CELL_FS_SUCCEEDED)
#elif defined(_XBOX)
ret = MoveFileExA(full_path, tmp_pathnewfile, NULL);
if (ret == 0)
#endif
{
RARCH_ERR("Failed to rename CORE executable.\n");
}
else
{
RARCH_LOG("Libsnes core [%s] renamed to: [%s].\n", full_path, tmp_pathnewfile);
retstr = tmp_pathnewfile;
goto done;
}
else
{
RARCH_ERR("Failed to rename CORE executable.\n");
RARCH_WARN("CORE executable was not found, or some other errors occurred. Will attempt to load libretro core path from config file.\n");
}
}
RARCH_WARN("CORE executable was not found, or some other errors occurred. Will attempt to load libretro core path from config file.\n");
done:
return retstr;
}

View File

@ -87,9 +87,9 @@ static void find_and_set_first_file(void)
// we can find in the RetroArch cores directory
#if defined(_XBOX)
char ** dir_list = dir_list_new("game:\\", ".xex", false);
char ** dir_list = dir_list_new("game:\\", "xex", false);
#elif defined(__CELLOS_LV2__)
char ** dir_list = dir_list_new(LIBRETRO_DIR_PATH, ".SELF", false);
char ** dir_list = dir_list_new(LIBRETRO_DIR_PATH, "SELF", false);
#endif
if (!dir_list)

View File

@ -403,6 +403,12 @@ static void init_filter(void)
if (*g_settings.video.filter_path == '\0')
return;
if (g_extern.system.rgb32)
{
RARCH_WARN("libretro implementation uses XRGB8888 format. CPU filters only support 0RGB1555.\n");
return;
}
RARCH_LOG("Loading bSNES filter from \"%s\"\n", g_settings.video.filter_path);
g_extern.filter.lib = dylib_load(g_settings.video.filter_path);
if (!g_extern.filter.lib)
@ -417,6 +423,7 @@ static void init_filter(void)
(void (*)(uint32_t*, uint32_t*,
unsigned, const uint16_t*,
unsigned, unsigned, unsigned))dylib_proc(g_extern.filter.lib, "filter_render");
if (!g_extern.filter.psize || !g_extern.filter.prender)
{
RARCH_ERR("Failed to find functions in filter...\n");
@ -428,28 +435,30 @@ static void init_filter(void)
g_extern.filter.active = true;
struct retro_game_geometry *geom = &g_extern.system.av_info.geometry;
unsigned width = geom->max_width;
unsigned width = geom->max_width;
unsigned height = geom->max_height;
g_extern.filter.psize(&width, &height);
unsigned pow2_x = next_pow2(width);
unsigned pow2_y = next_pow2(height);
unsigned pow2_x = next_pow2(width);
unsigned pow2_y = next_pow2(height);
unsigned maxsize = pow2_x > pow2_y ? pow2_x : pow2_y;
g_extern.filter.scale = maxsize / RARCH_SCALE_BASE;
g_extern.filter.buffer = (uint32_t*)malloc(RARCH_SCALE_BASE * RARCH_SCALE_BASE * g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
g_extern.filter.pitch = RARCH_SCALE_BASE * g_extern.filter.scale * sizeof(uint32_t);
g_extern.filter.buffer = (uint32_t*)malloc(RARCH_SCALE_BASE * RARCH_SCALE_BASE *
g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
rarch_assert(g_extern.filter.buffer);
g_extern.filter.colormap = (uint32_t*)malloc(32768 * sizeof(uint32_t));
g_extern.filter.pitch = RARCH_SCALE_BASE * g_extern.filter.scale * sizeof(uint32_t);
g_extern.filter.colormap = (uint32_t*)malloc(0x10000 * sizeof(uint32_t));
rarch_assert(g_extern.filter.colormap);
// Set up conversion map from 16-bit XRGB1555 to 32-bit ARGB.
for (unsigned i = 0; i < 32768; i++)
for (unsigned i = 0; i < 0x10000; i++)
{
unsigned r = (i >> 10) & 31;
unsigned g = (i >> 5) & 31;
unsigned b = (i >> 0) & 31;
unsigned r = (i >> 10) & 0x1f;
unsigned g = (i >> 5) & 0x1f;
unsigned b = (i >> 0) & 0x1f;
r = (r << 3) | (r >> 2);
g = (g << 3) | (g >> 2);
@ -477,17 +486,14 @@ static void init_shader_dir(void)
if (!*g_settings.video.shader_dir)
return;
g_extern.shader_dir.elems = dir_list_new(g_settings.video.shader_dir, ".shader", false);
g_extern.shader_dir.size = 0;
g_extern.shader_dir.ptr = 0;
if (g_extern.shader_dir.elems)
{
while (g_extern.shader_dir.elems[g_extern.shader_dir.size])
{
RARCH_LOG("Found shader \"%s\"\n", g_extern.shader_dir.elems[g_extern.shader_dir.size]);
g_extern.shader_dir.size++;
}
}
g_extern.shader_dir.elems = dir_list_new(g_settings.video.shader_dir, "shader", false);
g_extern.shader_dir.size = dir_list_size(g_extern.shader_dir.elems);
g_extern.shader_dir.ptr = 0;
dir_list_sort(g_extern.shader_dir.elems, false);
for (unsigned i = 0; i < g_extern.shader_dir.size; i++)
RARCH_LOG("Found shader \"%s\"\n", g_extern.shader_dir.elems[i]);
}
static void deinit_shader_dir(void)
@ -495,8 +501,8 @@ static void deinit_shader_dir(void)
// It handles NULL, no worries :D
dir_list_free(g_extern.shader_dir.elems);
g_extern.shader_dir.elems = NULL;
g_extern.shader_dir.size = 0;
g_extern.shader_dir.ptr = 0;
g_extern.shader_dir.size = 0;
g_extern.shader_dir.ptr = 0;
}
#endif
@ -559,7 +565,7 @@ void init_video_input(void)
video.force_aspect = g_settings.video.force_aspect;
video.smooth = g_settings.video.smooth;
video.input_scale = scale;
video.rgb32 = g_extern.filter.active;
video.rgb32 = g_extern.filter.active || g_extern.system.rgb32;
const input_driver_t *tmp = driver.input;
driver.video_data = video_init_func(&video, &driver.input, &driver.input_data);

View File

@ -331,6 +331,31 @@ static bool environment_cb(unsigned cmd, void *data)
RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", g_settings.system_directory);
break;
case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT:
{
enum retro_pixel_format pix_fmt = *(const enum retro_pixel_format*)data;
bool rgb32 = false;
switch (pix_fmt)
{
case RETRO_PIXEL_FORMAT_0RGB1555:
rgb32 = false;
RARCH_LOG("Environ SET_PIXEL_FORMAT: 0RGB1555.\n");
break;
#ifndef RARCH_CONSOLE
case RETRO_PIXEL_FORMAT_XRGB8888:
rgb32 = true;
RARCH_LOG("Environ SET_PIXEL_FORMAT: XRGB8888.\n");
break;
#endif
default:
return false;
}
g_extern.system.rgb32 = rgb32;
break;
}
default:
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
return false;

6
file.h
View File

@ -24,10 +24,6 @@
#include <sys/types.h>
#include "general.h"
#ifdef __CELLOS_LV2__
#include <cell/cell_fs.h>
#endif
// Generic file, path and directory handling.
ssize_t read_file(const char *path, void **buf);
@ -44,6 +40,8 @@ bool init_rom_file(enum rarch_game_type type);
// If ext is NULL, any file will be picked.
// If non-NULL, only files with extension ext are added.
char **dir_list_new(const char *dir, const char *ext, bool include_dirs);
size_t dir_list_size(char * const *dir_list);
void dir_list_sort(char **dir_list, bool dir_first);
void dir_list_free(char **dir_list);
bool path_is_directory(const char *path);

View File

@ -20,9 +20,10 @@
#include <string.h>
#include <time.h>
#include "compat/strl.h"
#include "compat/posix_string.h"
#ifdef __CELLOS_LV2__
#include <cell/cell_fs.h>
#define S_ISDIR(x) (x & CELL_FS_S_IFDIR)
#endif
#if defined(_WIN32) && !defined(_XBOX)
@ -43,141 +44,273 @@
#endif
// Yep, this is C alright ;)
char **dir_list_new(const char *dir, const char *ext, bool include_dirs)
struct string_list
{
size_t cur_ptr = 0;
size_t cur_size = 32;
char **dir_list = NULL;
char **data;
size_t size;
size_t cap;
};
#ifdef _WIN32
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
static bool string_list_capacity(struct string_list *list, size_t cap)
{
rarch_assert(cap > list->size);
char path_buf[PATH_MAX];
char **new_data = (char**)realloc(list->data, cap * sizeof(char*));
if (!new_data)
return false;
if (strlcpy(path_buf, dir, sizeof(path_buf)) >= sizeof(path_buf))
goto error;
#ifdef _XBOX
if (strlcat(path_buf, "*", sizeof(path_buf)) >= sizeof(path_buf))
#else
if (strlcat(path_buf, "/*", sizeof(path_buf)) >= sizeof(path_buf))
#endif
list->data = new_data;
list->cap = cap;
return true;
}
static bool string_list_init(struct string_list *list)
{
memset(list, 0, sizeof(*list));
return string_list_capacity(list, 32);
}
static bool string_list_append(struct string_list *list, const char *elem)
{
if (list->size + 1 >= list->cap && !string_list_capacity(list, list->cap * 2))
return false;
if (!(list->data[list->size] = strdup(elem)))
return false;
list->size++;
return true;
}
static char **string_list_finalize(struct string_list *list)
{
rarch_assert(list->cap > list->size);
list->data[list->size] = NULL;
return list->data;
}
static void string_list_cleanup(struct string_list *list)
{
for (size_t i = 0; i < list->size; i++)
free(list->data[i]);
free(list->data);
memset(list, 0, sizeof(*list));
}
static void string_list_free(char **list)
{
if (!list)
return;
char **orig = list;
while (*list)
free(*list++);
free(orig);
}
static char **string_split(const char *str, const char *delim)
{
char *copy = NULL;
const char *tmp = NULL;
struct string_list list;
if (!string_list_init(&list))
goto error;
if (ext)
copy = strdup(str);
if (!copy)
return NULL;
tmp = strtok(copy, delim);
while (tmp)
{
if (strlcat(path_buf, ext, sizeof(path_buf)) >= sizeof(path_buf))
goto error;
}
hFind = FindFirstFile(path_buf, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
goto error;
#else
DIR *directory = NULL;
const struct dirent *entry = NULL;
directory = opendir(dir);
if (!directory)
goto error;
#endif
dir_list = (char**)calloc(cur_size, sizeof(char*));
if (!dir_list)
goto error;
#ifdef _WIN32 // Hard to read? Blame non-POSIX heathens!
do
#else
while ((entry = readdir(directory)))
#endif
{
// Not a perfect search of course, but hopefully good enough in practice.
#ifdef _WIN32
if (include_dirs)
{
if (ext && !strstr(ffd.cFileName, ext) && !path_is_directory(ffd.cFileName))
continue;
}
else
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
if (ext && !strstr(ffd.cFileName, ext))
continue;
}
#else
if (include_dirs)
{
if (ext && !strstr(entry->d_name, ext) && !path_is_directory(entry->d_name))
continue;
}
else
{
if (ext && !strstr(entry->d_name, ext))
continue;
}
#endif
dir_list[cur_ptr] = (char*)malloc(PATH_MAX);
if (!dir_list[cur_ptr])
if (!string_list_append(&list, tmp))
goto error;
strlcpy(dir_list[cur_ptr], dir, PATH_MAX);
#ifndef _XBOX
strlcat(dir_list[cur_ptr], "/", PATH_MAX);
#endif
#ifdef _WIN32
strlcat(dir_list[cur_ptr], ffd.cFileName, PATH_MAX);
#else
strlcat(dir_list[cur_ptr], entry->d_name, PATH_MAX);
#endif
cur_ptr++;
if (cur_ptr + 1 == cur_size) // Need to reserve for NULL.
{
cur_size *= 2;
dir_list = (char**)realloc(dir_list, cur_size * sizeof(char*));
if (!dir_list)
goto error;
// Make sure it's all NULL'd out since we cannot rely on realloc to do this.
memset(dir_list + cur_ptr, 0, (cur_size - cur_ptr) * sizeof(char*));
}
tmp = strtok(NULL, delim);
}
#if defined(_WIN32)
while (FindNextFile(hFind, &ffd) != 0);
#endif
#ifdef _WIN32
FindClose(hFind);
#else
closedir(directory);
#endif
return dir_list;
free(copy);
return string_list_finalize(&list);
error:
RARCH_ERR("Failed to open directory: \"%s\"\n", dir);
#ifdef _WIN32
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
#else
if (directory)
closedir(directory);
#endif
dir_list_free(dir_list);
string_list_cleanup(&list);
free(copy);
return NULL;
}
void dir_list_free(char **dir_list)
static bool string_list_find_elem(char * const *list, const char *elem)
{
if (!list)
return false;
for (; *list; list++)
if (strcmp(*list, elem) == 0)
return true;
return false;
}
static const char *path_get_extension(const char *path)
{
const char *ext = strrchr(path, '.');
if (ext)
return ext + 1;
else
return "";
}
size_t dir_list_size(char * const *dir_list)
{
if (!dir_list)
return 0;
size_t size = 0;
while (*dir_list++)
size++;
return size;
}
static int qstrcmp_plain(const void *a, const void *b)
{
return strcasecmp(*(const char * const*)a, *(const char * const*)b);
}
static int qstrcmp_dir(const void *a_, const void *b_)
{
const char *a = *(const char * const*)a_;
const char *b = *(const char * const*)b_;
// Sort directories before files.
int a_dir = path_is_directory(a);
int b_dir = path_is_directory(b);
if (a_dir != b_dir)
return b_dir - a_dir;
return strcasecmp(a, b);
}
void dir_list_sort(char **dir_list, bool dir_first)
{
if (!dir_list)
return;
char **orig = dir_list;
while (*dir_list)
free(*dir_list++);
free(orig);
qsort(dir_list, dir_list_size(dir_list), sizeof(char*), dir_first ? qstrcmp_dir : qstrcmp_plain);
}
#ifdef _WIN32 // Because the API is just fucked up ...
char **dir_list_new(const char *dir, const char *ext, bool include_dirs)
{
struct string_list list;
if (!string_list_init(&list))
return NULL;
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
char path_buf[PATH_MAX];
snprintf(path_buf, sizeof(path_buf), "%s\\*", dir);
char **ext_list = NULL;
if (ext)
ext_list = string_split(ext, "|");
hFind = FindFirstFile(path_buf, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
goto error;
do
{
const char *name = ffd.cFileName;
const char *file_ext = path_get_extension(name);
bool is_dir = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if (!include_dirs && is_dir)
continue;
if (!is_dir && ext_list && !string_list_find_elem(ext_list, file_ext))
continue;
char file_path[PATH_MAX];
snprintf(file_path, sizeof(file_path), "%s\\%s", dir, name);
if (!string_list_append(&list, file_path))
goto error;
}
while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
string_list_free(ext_list);
return string_list_finalize(&list);
error:
RARCH_ERR("Failed to open directory: \"%s\"\n", dir);
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
string_list_cleanup(&list);
string_list_free(ext_list);
return NULL;
}
#else
char **dir_list_new(const char *dir, const char *ext, bool include_dirs)
{
struct string_list list;
if (!string_list_init(&list))
return NULL;
DIR *directory = NULL;
const struct dirent *entry = NULL;
char **ext_list = NULL;
if (ext)
ext_list = string_split(ext, "|");
directory = opendir(dir);
if (!directory)
goto error;
while ((entry = readdir(directory)))
{
const char *name = entry->d_name;
const char *file_ext = path_get_extension(name);
bool is_dir = entry->d_type == DT_DIR;
if (!include_dirs && is_dir)
continue;
if (!is_dir && ext_list && !string_list_find_elem(ext_list, file_ext))
continue;
char file_path[PATH_MAX];
snprintf(file_path, sizeof(file_path), "%s/%s", dir, name);
if (!string_list_append(&list, file_path))
goto error;
}
closedir(directory);
string_list_free(ext_list);
return string_list_finalize(&list);
error:
RARCH_ERR("Failed to open directory: \"%s\"\n", dir);
if (directory)
closedir(directory);
string_list_cleanup(&list);
string_list_free(ext_list);
return NULL;
}
#endif
void dir_list_free(char **dir_list)
{
string_list_free(dir_list);
}
bool path_is_directory(const char *path)
@ -185,12 +318,6 @@ bool path_is_directory(const char *path)
#ifdef _WIN32
DWORD ret = GetFileAttributes(path);
return (ret & FILE_ATTRIBUTE_DIRECTORY) && (ret != INVALID_FILE_ATTRIBUTES);
#elif defined(__CELLOS_LV2__)
CellFsStat buf;
if (cellFsStat(path, &buf) < 0)
return false;
return buf.st_mode & CELL_FS_S_IFDIR;
#else
struct stat buf;
if (stat(path, &buf) < 0)

View File

@ -332,6 +332,7 @@ struct global
unsigned rotation;
bool shutdown;
unsigned performance_level;
bool rgb32;
} system;
struct

View File

@ -150,7 +150,19 @@ extern "C" {
// The returned value can be NULL.
// If so, no such directory is defined,
// and it's up to the implementation to find a suitable directory.
//
#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10
// const enum retro_pixel_format * --
// Sets the internal pixel format used by the implementation.
// The default pixel format is RETRO_PIXEL_FORMAT_XRGB1555.
// If the call returns false, the frontend does not support this pixel format.
// This function should be called inside retro_load_game() or retro_get_system_av_info().
enum retro_pixel_format
{
RETRO_PIXEL_FORMAT_0RGB1555 = 0, // 0RGB1555, native endian. 0 bit must be set to 0.
RETRO_PIXEL_FORMAT_XRGB8888 // XRGB8888, native endian. X bits are ignored.
};
struct retro_message
{
@ -225,7 +237,7 @@ struct retro_game_info
// Environment callback. Gives implementations a way of performing uncommon tasks. Extensible.
typedef bool (*retro_environment_t)(unsigned cmd, void *data);
// Render a frame. Pixel format is 15-bit XRGB1555 native endian.
// Render a frame. Pixel format is 15-bit 0RGB1555 native endian unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
// Width and height specify dimensions of buffer.
// Pitch specifices length in bytes between two lines in buffer.
typedef void (*retro_video_refresh_t)(const void *data, unsigned width, unsigned height, size_t pitch);

View File

@ -78,7 +78,7 @@ char MULTIMAN_EXECUTABLE[PATH_MAX];
int rarch_main(int argc, char *argv[]);
SYS_PROCESS_PARAM(1001, 0x100000)
SYS_PROCESS_PARAM(1001, 0x200000)
#undef main
@ -418,8 +418,8 @@ begin_shutdown:
rarch_main_deinit();
input_ps3.free(NULL);
video_gl.stop();
menu_free();
if(g_console.oskutil_handle.is_running)
oskutil_unload(&g_console.oskutil_handle);

View File

@ -220,7 +220,7 @@ static void browser_update(filebrowser_t * b)
if (CTRL_LSTICK_DOWN(state))
{
if(b->currently_selected < b->file_count-1)
if(b->current_dir.ptr < b->current_dir.size-1)
{
FILEBROWSER_INCREMENT_ENTRY_POINTER(b);
set_delay = DELAY_SMALLEST;
@ -229,7 +229,7 @@ static void browser_update(filebrowser_t * b)
if (CTRL_DOWN(state))
{
if(b->currently_selected < b->file_count-1)
if(b->current_dir.ptr < b->current_dir.size-1)
{
FILEBROWSER_INCREMENT_ENTRY_POINTER(b);
set_delay = DELAY_SMALLEST;
@ -238,7 +238,7 @@ static void browser_update(filebrowser_t * b)
if (CTRL_LSTICK_UP(state))
{
if(b->currently_selected > 0)
if(b->current_dir.ptr > 0)
{
FILEBROWSER_DECREMENT_ENTRY_POINTER(b);
set_delay = DELAY_SMALLEST;
@ -247,7 +247,7 @@ static void browser_update(filebrowser_t * b)
if (CTRL_UP(state))
{
if(b->currently_selected > 0)
if(b->current_dir.ptr > 0)
{
FILEBROWSER_DECREMENT_ENTRY_POINTER(b);
set_delay = DELAY_SMALLEST;
@ -256,66 +256,66 @@ static void browser_update(filebrowser_t * b)
if (CTRL_RIGHT(state))
{
b->currently_selected = (MIN(b->currently_selected + 5, b->file_count-1));
b->current_dir.ptr = (MIN(b->current_dir.ptr + 5, b->current_dir.size-1));
set_delay = DELAY_SMALL;
}
if (CTRL_LSTICK_RIGHT(state))
{
b->currently_selected = (MIN(b->currently_selected + 5, b->file_count-1));
b->current_dir.ptr = (MIN(b->current_dir.ptr + 5, b->current_dir.size-1));
set_delay = DELAY_SMALLEST;
}
if (CTRL_LEFT(state))
{
if (b->currently_selected <= 5)
b->currently_selected = 0;
if (b->current_dir.ptr <= 5)
b->current_dir.ptr = 0;
else
b->currently_selected -= 5;
b->current_dir.ptr -= 5;
set_delay = DELAY_SMALL;
}
if (CTRL_LSTICK_LEFT(state))
{
if (b->currently_selected <= 5)
b->currently_selected = 0;
if (b->current_dir.ptr <= 5)
b->current_dir.ptr = 0;
else
b->currently_selected -= 5;
b->current_dir.ptr -= 5;
set_delay = DELAY_SMALLEST;
}
if (CTRL_R1(state))
{
b->currently_selected = (MIN(b->currently_selected + NUM_ENTRY_PER_PAGE, b->file_count-1));
b->current_dir.ptr = (MIN(b->current_dir.ptr + NUM_ENTRY_PER_PAGE, b->current_dir.size-1));
set_delay = DELAY_MEDIUM;
}
if (CTRL_R2(state))
{
b->currently_selected = (MIN(b->currently_selected + 50, b->file_count-1));
if(!b->currently_selected)
b->currently_selected = 0;
b->current_dir.ptr = (MIN(b->current_dir.ptr + 50, b->current_dir.size-1));
if(!b->current_dir.ptr)
b->current_dir.ptr = 0;
set_delay = DELAY_SMALL;
}
if (CTRL_L2(state))
{
if (b->currently_selected <= 50)
b->currently_selected= 0;
if (b->current_dir.ptr <= 50)
b->current_dir.ptr= 0;
else
b->currently_selected -= 50;
b->current_dir.ptr -= 50;
set_delay = DELAY_SMALL;
}
if (CTRL_L1(state))
{
if (b->currently_selected <= NUM_ENTRY_PER_PAGE)
b->currently_selected= 0;
if (b->current_dir.ptr <= NUM_ENTRY_PER_PAGE)
b->current_dir.ptr= 0;
else
b->currently_selected -= NUM_ENTRY_PER_PAGE;
b->current_dir.ptr -= NUM_ENTRY_PER_PAGE;
set_delay = DELAY_MEDIUM;
}
@ -330,11 +330,11 @@ static void browser_update(filebrowser_t * b)
static void browser_render(filebrowser_t * b)
{
gl_t *gl = driver.video_data;
uint32_t file_count = b->file_count;
uint32_t file_count = b->current_dir.size;
int current_index, page_number, page_base, i;
float currentX, currentY, ySpacing;
current_index = b->currently_selected;
current_index = b->current_dir.ptr;
page_number = current_index / NUM_ENTRY_PER_PAGE;
page_base = page_number * NUM_ENTRY_PER_PAGE;
@ -344,8 +344,10 @@ static void browser_render(filebrowser_t * b)
for ( i = page_base; i < file_count && i < page_base + NUM_ENTRY_PER_PAGE; ++i)
{
char fname_tmp[256];
fill_pathname_base(fname_tmp, b->current_dir.elems[i], sizeof(fname_tmp));
currentY = currentY + ySpacing;
cellDbgFontPuts(currentX, currentY, FONT_SIZE, i == current_index ? RED : b->cur[i].d_type == CELL_FS_TYPE_DIRECTORY ? GREEN : WHITE, b->cur[i].d_name);
cellDbgFontPuts(currentX, currentY, FONT_SIZE, i == current_index ? RED : WHITE, fname_tmp);
gl_render_msg_post(gl);
}
gl_render_msg_post(gl);
@ -818,8 +820,7 @@ static void apply_scaling (unsigned init_mode)
static void select_file(uint32_t menu_id)
{
char extensions[256], title[256], object[256], comment[256], dir_path[PATH_MAX],
path[PATH_MAX], *separatorslash;
char extensions[256], title[256], object[256], comment[256], dir_path[PATH_MAX], path[PATH_MAX];
uint64_t state, diff_state, button_was_pressed;
gl_t * gl = driver.video_data;
@ -881,7 +882,7 @@ static void select_file(uint32_t menu_id)
if(IS_TIMER_EXPIRED(gl))
{
if (CTRL_START(button_was_pressed))
filebrowser_reset_start_directory(&tmpBrowser, "/", extensions);
filebrowser_new(&tmpBrowser, "/", extensions);
if (CTRL_CROSS(button_was_pressed))
{
@ -889,19 +890,17 @@ static void select_file(uint32_t menu_id)
{
/*if 'filename' is in fact '..' - then pop back directory instead of
adding '..' to filename path */
if(tmpBrowser.currently_selected == 0)
if(tmpBrowser.current_dir.ptr == 0)
filebrowser_pop_directory(&tmpBrowser);
else
{
separatorslash = (strcmp(FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmpBrowser),"/") == 0) ? "" : "/";
snprintf(path, sizeof(path), "%s%s%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmpBrowser), separatorslash, FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
snprintf(path, sizeof(path), FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
filebrowser_push_directory(&tmpBrowser, path, true);
}
}
else if (FILEBROWSER_IS_CURRENT_A_FILE(tmpBrowser))
{
snprintf(path, sizeof(path), "%s/%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmpBrowser), FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
printf("path: %s\n", path);
snprintf(path, sizeof(path), FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
switch(menu_id)
{
@ -962,7 +961,7 @@ static void select_file(uint32_t menu_id)
static void select_directory(uint32_t menu_id)
{
char path[1024], newpath[1024], *separatorslash;
char path[1024], newpath[1024];
uint64_t state, diff_state, button_was_pressed;
gl_t * gl = driver.video_data;
@ -981,13 +980,13 @@ static void select_directory(uint32_t menu_id)
if(IS_TIMER_EXPIRED(gl))
{
if (CTRL_START(button_was_pressed))
filebrowser_reset_start_directory(&tmpBrowser, "/","empty");
filebrowser_new(&tmpBrowser, "/","empty");
if (CTRL_SQUARE(button_was_pressed))
{
if(FILEBROWSER_IS_CURRENT_A_DIRECTORY(tmpBrowser))
{
snprintf(path, sizeof(path), "%s/%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmpBrowser), FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
snprintf(path, sizeof(path), FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
switch(menu_id)
{
case PATH_SAVESTATES_DIR_CHOICE:
@ -1035,12 +1034,11 @@ static void select_directory(uint32_t menu_id)
/* if 'filename' is in fact '..' - then pop back directory instead of
* adding '..' to filename path */
if(tmpBrowser.currently_selected == 0)
if(tmpBrowser.current_dir.ptr == 0)
filebrowser_pop_directory(&tmpBrowser);
else
{
separatorslash = (strcmp(FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmpBrowser),"/") == 0) ? "" : "/";
snprintf(newpath, sizeof(newpath), "%s%s%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(tmpBrowser), separatorslash, FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
snprintf(newpath, sizeof(newpath), FILEBROWSER_GET_CURRENT_FILENAME(tmpBrowser));
filebrowser_push_directory(&tmpBrowser, newpath, false);
}
}
@ -1895,7 +1893,7 @@ static void select_setting(menu * menu_obj)
static void select_rom(void)
{
char newpath[1024], *separatorslash;
char newpath[1024];
uint64_t state, diff_state, button_was_pressed;
gl_t * gl = driver.video_data;
@ -1914,7 +1912,7 @@ static void select_rom(void)
}
if (CTRL_START(button_was_pressed))
filebrowser_reset_start_directory(&browser, "/", rarch_console_get_rom_ext());
filebrowser_new(&browser, "/", rarch_console_get_rom_ext());
if (CTRL_CROSS(button_was_pressed))
{
@ -1922,14 +1920,13 @@ static void select_rom(void)
{
/*if 'filename' is in fact '..' - then pop back directory instead of adding '..' to filename path */
if(browser.currently_selected == 0)
if(browser.current_dir.ptr == 0)
{
filebrowser_pop_directory(&browser);
}
else
{
separatorslash = (strcmp(FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(browser),"/") == 0) ? "" : "/";
snprintf(newpath, sizeof(newpath), "%s%s%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(browser), separatorslash, FILEBROWSER_GET_CURRENT_FILENAME(browser));
snprintf(newpath, sizeof(newpath), FILEBROWSER_GET_CURRENT_FILENAME(browser));
filebrowser_push_directory(&browser, newpath, true);
}
}
@ -1940,13 +1937,13 @@ static void select_rom(void)
retro_get_system_info(&info);
bool block_zip_extract = info.block_extract;
snprintf(rom_path_temp, sizeof(rom_path_temp), "%s/%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(browser), FILEBROWSER_GET_CURRENT_FILENAME(browser));
snprintf(rom_path_temp, sizeof(rom_path_temp), FILEBROWSER_GET_CURRENT_FILENAME(browser));
if((strstr(rom_path_temp, ".zip") || strstr(rom_path_temp, ".ZIP")) && !block_zip_extract)
rarch_extract_zipfile(rom_path_temp);
else
{
snprintf(g_console.rom_path, sizeof(g_console.rom_path), "%s/%s", FILEBROWSER_GET_CURRENT_DIRECTORY_NAME(browser), FILEBROWSER_GET_CURRENT_FILENAME(browser));
snprintf(g_console.rom_path, sizeof(g_console.rom_path), FILEBROWSER_GET_CURRENT_FILENAME(browser));
rarch_settings_change(S_START_RARCH);
}
}
@ -2462,6 +2459,12 @@ void menu_init (void)
filebrowser_new(&browser, g_console.default_rom_startup_dir, rarch_console_get_rom_ext());
}
void menu_free (void)
{
filebrowser_free(&browser);
filebrowser_free(&tmpBrowser);
}
void menu_loop(void)
{
gl_t * gl = driver.video_data;

View File

@ -157,5 +157,6 @@ enum
void menu_init (void);
void menu_loop (void);
void menu_free (void);
#endif /* MENU_H_ */

View File

@ -21,7 +21,6 @@ else
HAVE_RPI=no
fi
if [ "$LIBRETRO" ]; then
echo "Explicit libsnes used, disabling dynamic libsnes loading ..."
HAVE_DYNAMIC='no'
@ -93,6 +92,7 @@ fi
check_pkgconf XML libxml-2.0
check_pkgconf SDL_IMAGE SDL_image
check_pkgconf LIBPNG libpng
if [ "$HAVE_THREADS" != 'no' ]; then
if [ "$HAVE_FFMPEG" != 'no' ]; then
@ -140,6 +140,6 @@ check_pkgconf PYTHON python3
add_define_make OS "$OS"
# Creates config.mk and config.h.
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY NETWORK_CMD SOCKET_LEGACY FBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 X264RGB SINC BSV_MOVIE RPI"
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL DYLIB GETOPT_LONG THREADS CG XML SDL_IMAGE LIBPNG DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY NETWORK_CMD SOCKET_LEGACY FBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 X264RGB SINC BSV_MOVIE RPI"
create_config_make config.mk $VARS
create_config_header config.h $VARS
create_config_header config.h $VARS

View File

@ -21,6 +21,7 @@ HAVE_PULSE=auto # Enable PulseAudio support
HAVE_FREETYPE=auto # Enable FreeType support
HAVE_XVIDEO=auto # Enable XVideo support
HAVE_SDL_IMAGE=auto # Enable SDL_image support
HAVE_LIBPNG=auto # Enable libpng support
HAVE_PYTHON=auto # Enable Python 3 support for shaders
HAVE_SINC=yes # Disable SINC resampler
HAVE_BSV_MOVIE=yes # Disable BSV movie support

View File

@ -499,6 +499,7 @@ static void print_features(void)
_PSUPP(cg, "Cg", "Cg pixel shaders");
_PSUPP(xml, "XML", "bSNES XML pixel shaders");
_PSUPP(sdl_image, "SDL_image", "SDL_image image loading");
_PSUPP(libpng, "libpng", "libpng screenshot support");
_PSUPP(fbo, "FBO", "OpenGL render-to-texture (multi-pass shaders)");
_PSUPP(dynamic, "Dynamic", "Dynamic run-time loading of libretro library");
_PSUPP(ffmpeg, "FFmpeg", "On-the-fly recording of gameplay with libavcodec");
@ -1175,7 +1176,7 @@ static void init_recording(void)
params.filename = g_extern.record_path;
params.fps = fps;
params.samplerate = samplerate;
params.rgb32 = false;
params.rgb32 = g_extern.system.rgb32;
if (g_extern.record_width || g_extern.record_height)
{

View File

@ -22,9 +22,80 @@
#include <string.h>
#include "general.h"
// Simple 24bpp .BMP writer.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
static void write_header(FILE *file, unsigned width, unsigned height)
#ifdef HAVE_LIBPNG
#include <png.h>
#endif
#ifdef HAVE_LIBPNG
static png_structp png_ptr;
static png_infop png_info_ptr;
static void destroy_png(void)
{
if (png_ptr)
png_destroy_write_struct(&png_ptr, &png_info_ptr);
}
static bool write_header_png(FILE *file, unsigned width, unsigned height)
{
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
return false;
if (setjmp(png_jmpbuf(png_ptr)))
goto error;
png_info_ptr = png_create_info_struct(png_ptr);
if (!png_info_ptr)
goto error;
png_init_io(png_ptr, file);
png_set_IHDR(png_ptr, png_info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, png_info_ptr);
png_set_compression_level(png_ptr, 9);
return true;
error:
destroy_png();
return false;
}
static void dump_lines_png(uint8_t **lines, int height)
{
if (setjmp(png_jmpbuf(png_ptr)))
{
RARCH_ERR("PNG: dump_lines_png() failed!\n");
goto end;
}
// PNG is top-down, BMP is bottom-up.
for (int i = 0, j = height - 1; i < j; i++, j--)
{
uint8_t *tmp = lines[i];
lines[i] = lines[j];
lines[j] = tmp;
}
png_set_rows(png_ptr, png_info_ptr, lines);
png_write_png(png_ptr, png_info_ptr, PNG_TRANSFORM_BGR, NULL);
png_write_end(png_ptr, NULL);
end:
destroy_png();
}
#else
static bool write_header_bmp(FILE *file, unsigned width, unsigned height)
{
unsigned line_size = (width * 3 + 3) & ~3;
unsigned size = line_size * height + 54;
@ -49,9 +120,17 @@ static void write_header(FILE *file, unsigned width, unsigned height)
0, 0, 0, 0
};
fwrite(header, 1, sizeof(header), file);
return fwrite(header, 1, sizeof(header), file) == sizeof(header);
}
static void dump_lines_file(FILE *file, uint8_t **lines, size_t line_size, unsigned height)
{
for (unsigned i = 0; i < height; i++)
fwrite(lines[i], 1, line_size, file);
}
#endif
static void dump_line_bgr(uint8_t *line, const uint8_t *src, unsigned width)
{
memcpy(line, src, width * 3);
@ -78,31 +157,42 @@ static void dump_content(FILE *file, const void *frame,
const uint16_t *frame16 = (const uint16_t*)frame;
if (!bgr24)
pitch /= 2;
pitch /= sizeof(uint16_t);
unsigned line_size = (width * 3 + 3) & ~3;
uint8_t *line = (uint8_t*)calloc(1, line_size);
if (!line)
uint8_t **lines = (uint8_t**)calloc(height, sizeof(uint8_t*));
if (!lines)
return;
size_t line_size = (width * 3 + 3) & ~3;
for (int i = 0; i < height; i++)
{
lines[i] = (uint8_t*)calloc(1, line_size);
if (!lines[i])
goto end;
}
if (bgr24) // BGR24 byte order. Can directly copy.
{
for (int j = 0; j < height; j++, frame_bgr += pitch)
{
dump_line_bgr(line, frame_bgr, width);
fwrite(line, 1, line_size, file);
}
dump_line_bgr(lines[j], frame_bgr, width);
}
else // ARGB1555
{
for (int j = 0; j < height; j++, frame16 += pitch)
{
dump_line_16(line, frame16, width);
fwrite(line, 1, line_size, file);
}
dump_line_16(lines[j], frame16, width);
}
free(line);
#ifdef HAVE_LIBPNG
dump_lines_png(lines, height);
#else
dump_lines_file(file, lines, line_size, height);
#endif
end:
for (int i = 0; i < height; i++)
free(lines[i]);
free(lines);
}
bool screenshot_dump(const char *folder, const void *frame,
@ -111,8 +201,14 @@ bool screenshot_dump(const char *folder, const void *frame,
time_t cur_time;
time(&cur_time);
#ifdef HAVE_LIBPNG
#define IMG_EXT "png"
#else
#define IMG_EXT "bmp"
#endif
char timefmt[128];
strftime(timefmt, sizeof(timefmt), "RetroArch-%m%d-%H%M%S.bmp", localtime(&cur_time));
strftime(timefmt, sizeof(timefmt), "RetroArch-%m%d-%H%M%S." IMG_EXT, localtime(&cur_time));
char filename[PATH_MAX];
snprintf(filename, sizeof(filename), "%s/%s", folder, timefmt);
@ -124,11 +220,18 @@ bool screenshot_dump(const char *folder, const void *frame,
return false;
}
write_header(file, width, height);
dump_content(file, frame, width, height, pitch, bgr24);
#ifdef HAVE_LIBPNG
bool ret = write_header_png(file, width, height);
#else
bool ret = write_header_bmp(file, width, height);
#endif
if (ret)
dump_content(file, frame, width, height, pitch, bgr24);
else
RARCH_ERR("Failed to write image header.\n");
fclose(file);
return true;
return ret;
}