Merge branch 'master' of http://github.com/Themaister/RetroArch
Conflicts: qb/config.libs.sh
@ -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();
|
||||
|
25
360/menu.cpp
@ -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,12 +526,11 @@ 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));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
5
Makefile
@ -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)
|
||||
|
10
Makefile.win
@ -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
@ -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
@ -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>
|
4
android/.settings/org.eclipse.jdt.core.prefs
Normal 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
|
24
android/AndroidManifest.xml
Normal 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>
|
BIN
android/bin/classes/com/retroarch/BuildConfig.class
Normal file
BIN
android/bin/classes/com/retroarch/MainActivity.class
Normal file
BIN
android/bin/classes/com/retroarch/R$attr.class
Normal file
BIN
android/bin/classes/com/retroarch/R$drawable.class
Normal file
BIN
android/bin/classes/com/retroarch/R$layout.class
Normal file
BIN
android/bin/classes/com/retroarch/R$string.class
Normal file
BIN
android/bin/classes/com/retroarch/R.class
Normal file
3
android/bin/jarlist.cache
Normal file
@ -0,0 +1,3 @@
|
||||
# cache for current jar dependecy. DO NOT EDIT.
|
||||
# format is <lastModified> <length> <SHA-1> <path>
|
||||
# Encoding is UTF-8
|
6
android/gen/com/retroarch/BuildConfig.java
Normal file
@ -0,0 +1,6 @@
|
||||
/** Automatically generated file. DO NOT MODIFY */
|
||||
package com.retroarch;
|
||||
|
||||
public final class BuildConfig {
|
||||
public final static boolean DEBUG = true;
|
||||
}
|
42
android/gen/com/retroarch/R.java
Normal 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;
|
||||
}
|
||||
}
|
20
android/proguard-project.txt
Normal 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 *;
|
||||
#}
|
14
android/project.properties
Normal 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
|
BIN
android/res/drawable-hdpi/ic_action_close.png
Normal file
After Width: | Height: | Size: 729 B |
BIN
android/res/drawable-hdpi/ic_action_history.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
android/res/drawable-hdpi/ic_action_load.png
Normal file
After Width: | Height: | Size: 725 B |
BIN
android/res/drawable-hdpi/ic_action_open.png
Normal file
After Width: | Height: | Size: 578 B |
BIN
android/res/drawable-hdpi/ic_action_quit.png
Normal file
After Width: | Height: | Size: 797 B |
BIN
android/res/drawable-hdpi/ic_action_save.png
Normal file
After Width: | Height: | Size: 614 B |
BIN
android/res/drawable-hdpi/ic_action_settings.png
Normal file
After Width: | Height: | Size: 608 B |
BIN
android/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
android/res/drawable-ldpi/ic_action_close.png
Normal file
After Width: | Height: | Size: 349 B |
BIN
android/res/drawable-ldpi/ic_action_history.png
Normal file
After Width: | Height: | Size: 188 B |
BIN
android/res/drawable-ldpi/ic_action_load.png
Normal file
After Width: | Height: | Size: 406 B |
BIN
android/res/drawable-ldpi/ic_action_open.png
Normal file
After Width: | Height: | Size: 281 B |
BIN
android/res/drawable-ldpi/ic_action_quit.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
android/res/drawable-ldpi/ic_action_save.png
Normal file
After Width: | Height: | Size: 306 B |
BIN
android/res/drawable-ldpi/ic_action_settings.png
Normal file
After Width: | Height: | Size: 304 B |
BIN
android/res/drawable-ldpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 925 B |
BIN
android/res/drawable-mdpi/ic_action_close.png
Normal file
After Width: | Height: | Size: 472 B |
BIN
android/res/drawable-mdpi/ic_action_history.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
android/res/drawable-mdpi/ic_action_load.png
Normal file
After Width: | Height: | Size: 506 B |
BIN
android/res/drawable-mdpi/ic_action_open.png
Normal file
After Width: | Height: | Size: 407 B |
BIN
android/res/drawable-mdpi/ic_action_quit.png
Normal file
After Width: | Height: | Size: 536 B |
BIN
android/res/drawable-mdpi/ic_action_save.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
android/res/drawable-mdpi/ic_action_settings.png
Normal file
After Width: | Height: | Size: 395 B |
BIN
android/res/drawable-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
android/res/drawable-xhdpi/ic_action_close.png
Normal file
After Width: | Height: | Size: 729 B |
BIN
android/res/drawable-xhdpi/ic_action_history.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
android/res/drawable-xhdpi/ic_action_load.png
Normal file
After Width: | Height: | Size: 725 B |
BIN
android/res/drawable-xhdpi/ic_action_open.png
Normal file
After Width: | Height: | Size: 578 B |
BIN
android/res/drawable-xhdpi/ic_action_quit.png
Normal file
After Width: | Height: | Size: 797 B |
BIN
android/res/drawable-xhdpi/ic_action_save.png
Normal file
After Width: | Height: | Size: 614 B |
BIN
android/res/drawable-xhdpi/ic_action_settings.png
Normal file
After Width: | Height: | Size: 608 B |
BIN
android/res/drawable-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
12
android/res/layout/main.xml
Normal 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>
|
13
android/res/menu/main_menu.xml
Normal 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>
|
7
android/res/values/strings.xml
Normal 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>
|
69
android/src/com/retroarch/MainActivity.java
Normal 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());
|
||||
}
|
||||
}
|
130
android/src/com/retroarch/audio_android.java
Normal 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;
|
||||
}
|
||||
}
|
95
android/src/com/retroarch/rgl.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
42
driver.c
@ -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");
|
||||
@ -437,19 +444,21 @@ static void init_filter(void)
|
||||
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.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;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -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);
|
||||
|
25
dynamic.c
@ -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
@ -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);
|
||||
|
373
file_path.c
@ -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))
|
||||
if (!string_list_append(&list, tmp))
|
||||
goto error;
|
||||
|
||||
tmp = strtok(NULL, delim);
|
||||
}
|
||||
|
||||
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])
|
||||
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*));
|
||||
}
|
||||
}
|
||||
#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)
|
||||
|
@ -332,6 +332,7 @@ struct global
|
||||
unsigned rotation;
|
||||
bool shutdown;
|
||||
unsigned performance_level;
|
||||
bool rgb32;
|
||||
} system;
|
||||
|
||||
struct
|
||||
|
14
libretro.h
@ -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);
|
||||
|
@ -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);
|
||||
|
95
ps3/menu.c
@ -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;
|
||||
|
@ -157,5 +157,6 @@ enum
|
||||
|
||||
void menu_init (void);
|
||||
void menu_loop (void);
|
||||
void menu_free (void);
|
||||
|
||||
#endif /* MENU_H_ */
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
143
screenshot.c
@ -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);
|
||||
#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;
|
||||
}
|
||||
|
||||
|