예제 #1
0
void WindowsHeadlessHost::LoadNativeAssets()
{
	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(""));
	VFSRegister("", new DirectoryAssetReader("../"));
	VFSRegister("", new DirectoryAssetReader("../Windows/assets/"));
	VFSRegister("", new DirectoryAssetReader("../Windows/"));
}
예제 #2
0
void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID)
{
  std::string user_data_path = savegame_directory;

  // We want this to be FIRST.
  VFSRegister("", new DirectoryAssetReader("assets/"));
  VFSRegister("", new DirectoryAssetReader(user_data_path.c_str()));

  host = new NativeHost();

  logger = new AndroidLogger();

  LogManager::Init();
  LogManager *logman = LogManager::GetInstance();
  ILOG("Logman: %p", logman);

	if (argc > 1) 
	{
		boot_filename = argv[1];

		if (!File::Exists(boot_filename))
		{
			fprintf(stdout, "File not found: %s\n", boot_filename.c_str());
			exit(1);
		}
	}

	config_filename = user_data_path + "/config.ini";

	g_Config.Load(config_filename.c_str());

	if (g_Config.currentDirectory == "") {
#ifdef ANDROID
		g_Config.currentDirectory = external_directory;
#else
		g_Config.currentDirectory = getenv("HOME");
#endif
	}

  for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
  {
    LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
    logman->SetEnable(type, true);
    logman->SetLogLevel(type, LogTypes::LDEBUG);
#ifdef ANDROID
    logman->AddListener(type, logger);
#endif
  }
  logman->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
  INFO_LOG(BOOT, "Logger inited.");
}
예제 #3
0
void WindowsHeadlessHost::LoadNativeAssets()
{
	// Native is kinda talkative, but that's annoying in our case.
	out = _fdopen(_dup(_fileno(stdout)), "wt");
	freopen("NUL", "wt", stdout);

	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(""));
	VFSRegister("", new DirectoryAssetReader("../"));

	gl_lost_manager_init();

	// See SendDebugOutput() for how things get back on track.
}
예제 #4
0
extern "C" void Java_com_henrikrydgard_libnative_NativeApp_init
	(JNIEnv *env, jclass, jint xxres, jint yyres, jint dpi, jstring japkpath,
	 jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jinstallID, jboolean juseNativeAudio) {
	jniEnvUI = env;

	ILOG("NativeApp.init() -- begin");

	memset(&input_state, 0, sizeof(input_state));
	renderer_inited = false;
	first_lost = true;

	pad_buttons_down = 0;
	pad_buttons_async_set = 0;
	pad_buttons_async_clear = 0;

	left_joystick_x_async = 0;
	left_joystick_y_async = 0;
	right_joystick_x_async = 0;
	right_joystick_y_async = 0;

	KeyQueueBlank(key_queue_async);

	std::string apkPath = GetJavaString(env, japkpath);
	ILOG("NativeApp::Init: APK path: %s", apkPath.c_str());
	VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));

	std::string externalDir = GetJavaString(env, jexternalDir);
	std::string user_data_path = GetJavaString(env, jdataDir) + "/";
	std::string library_path = GetJavaString(env, jlibraryDir) + "/";
	std::string installID = GetJavaString(env, jinstallID);

	ILOG("NativeApp.init(): External storage path: %s", externalDir.c_str());

	std::string app_name;
	std::string app_nice_name;
	bool landscape;

	net::Init();

	g_dpi = dpi;
	g_dpi_scale = 240.0f / (float)g_dpi;
	pixel_xres = xxres;
	pixel_yres = yyres;
	pixel_in_dps = (float)pixel_xres / (float)dp_xres;

	NativeGetAppInfo(&app_name, &app_nice_name, &landscape);

	const char *argv[2] = {app_name.c_str(), 0};
	NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), installID.c_str());

	use_opensl_audio = juseNativeAudio;
	if (use_opensl_audio) {
		// TODO: PPSSPP doesn't support 48khz yet so let's not use that yet.
		ILOG("Using OpenSL audio! frames/buffer: %i   optimal sr: %i   actual sr: 44100", optimalFramesPerBuffer, optimalSampleRate);
		optimalSampleRate = 44100;
		AndroidAudio_Init(&NativeMix, library_path, optimalFramesPerBuffer, optimalSampleRate);
	}
	ILOG("NativeApp.init() -- end");
}	
예제 #5
0
extern "C" void Java_com_henrikrydgard_libnative_NativeApp_init
	(JNIEnv *env, jclass, jint xxres, jint yyres, jint dpi, jstring japkpath,
	 jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jinstallID, jboolean juseNativeAudio) {
	jniEnvUI = env;

	ILOG("NativeApp.init() -- begin");

	memset(&input_state, 0, sizeof(input_state));
	renderer_inited = false;
	first_lost = true;

	pad_buttons_down = 0;
	pad_buttons_async_set = 0;
	pad_buttons_async_clear = 0;

	std::string apkPath = GetJavaString(env, japkpath);
	ILOG("NativeApp::Init: APK path: %s", apkPath.c_str());
	VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));

	std::string externalDir = GetJavaString(env, jexternalDir);
	std::string user_data_path = GetJavaString(env, jdataDir) + "/";
	std::string library_path = GetJavaString(env, jlibraryDir) + "/";
	std::string installID = GetJavaString(env, jinstallID);

	ILOG("NativeApp.init(): External storage path: %s", externalDir.c_str());

	std::string app_name;
	std::string app_nice_name;
	bool landscape;

	net::Init();

	g_dpi = dpi;
	g_dpi_scale = 240.0f / (float)g_dpi;
	pixel_xres = xxres;
	pixel_yres = yyres;
	pixel_in_dps = (float)pixel_xres / (float)dp_xres;

	NativeGetAppInfo(&app_name, &app_nice_name, &landscape);

	const char *argv[2] = {app_name.c_str(), 0};
	NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), installID.c_str());

	use_native_audio = juseNativeAudio;
	if (use_native_audio) {
		AndroidAudio_Init(&NativeMix, library_path);
	}
	ILOG("NativeApp.init() -- end");
}	
예제 #6
0
void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID, bool fs)
{
    host = new NativeHost();

    logger = new AndroidLogger();

	LogManager::Init();
	LogManager *logman = LogManager::GetInstance();
	ILOG("Logman: %p", logman);

    LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
	for(int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
	{
		LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
        logman->SetLogLevel(type, logLevel);
    }

    VFSRegister("", new DirectoryAssetReader(external_directory));
}
예제 #7
0
extern "C" void Java_com_henrikrydgard_libnative_NativeApp_init
	(JNIEnv *env, jclass, jint dpi, jstring jdevicetype, jstring jlangRegion, jstring japkpath,
		jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jshortcutParam,
		jstring jinstallID, jboolean juseNativeAudio) {
	jniEnvUI = env;

	ILOG("NativeApp.init() -- begin");

	memset(&input_state, 0, sizeof(input_state));
	renderer_inited = false;
	first_lost = true;

	g_buttonTracker.Reset();

	left_joystick_x_async = 0;
	left_joystick_y_async = 0;
	right_joystick_x_async = 0;
	right_joystick_y_async = 0;
	hat_joystick_x_async = 0;
	hat_joystick_y_async = 0;

	std::string apkPath = GetJavaString(env, japkpath);
	VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));

	systemName = GetJavaString(env, jdevicetype);
	langRegion = GetJavaString(env, jlangRegion);

	std::string externalDir = GetJavaString(env, jexternalDir);
	std::string user_data_path = GetJavaString(env, jdataDir) + "/";
	library_path = GetJavaString(env, jlibraryDir) + "/";
	std::string shortcut_param = GetJavaString(env, jshortcutParam);
	std::string installID = GetJavaString(env, jinstallID);

	ILOG("NativeApp.init(): External storage path: %s", externalDir.c_str());
	ILOG("NativeApp.init(): Launch shortcut parameter: %s", shortcut_param.c_str());

	std::string app_name;
	std::string app_nice_name;
	bool landscape;

	net::Init();

	g_dpi = dpi;
	g_dpi_scale = 240.0f / (float)g_dpi;
	ILOG("DPI detected: %i %f", dpi, g_dpi_scale);

	NativeGetAppInfo(&app_name, &app_nice_name, &landscape);


	// If shortcut_param is not empty, pass it as additional varargs argument to NativeInit() method.
	// NativeInit() is expected to treat extra argument as boot_filename, which in turn will start game immediately.
	// NOTE: Will only work if ppsspp started from Activity.onCreate(). Won't work if ppsspp app start from onResume().

	if (shortcut_param.empty()) {
		const char *argv[2] = {app_name.c_str(), 0};
		NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), installID.c_str());
	}
	else {
		const char *argv[3] = {app_name.c_str(), shortcut_param.c_str(), 0};
		NativeInit(2, argv, user_data_path.c_str(), externalDir.c_str(), installID.c_str());
	}

	use_opensl_audio = juseNativeAudio;
	ILOG("NativeApp.init() -- end");
}
예제 #8
0
void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID)
{
	std::string config_filename;
	Common::EnableCrashingOnCrashes();

	std::string user_data_path = savegame_directory;

	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(user_data_path.c_str()));

	config_filename = user_data_path + "ppsspp.ini";

	g_Config.Load(config_filename.c_str());

	const char *fileToLog = 0;

	bool hideLog = true;
#ifdef _DEBUG
	hideLog = false;
#endif

	bool gfxLog = false;
	// Parse command line
	LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'd':
				// Enable debug logging
				logLevel = LogTypes::LDEBUG;
				break;
			case 'g':
				gfxLog = true;
				break;
			case 'j':
				g_Config.iCpuCore = CPU_JIT;
				g_Config.bSaveSettings = false;
				break;
			case 'f':
				g_Config.iCpuCore = CPU_FASTINTERPRETER;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.iCpuCore = CPU_INTERPRETER;
				g_Config.bSaveSettings = false;
				break;
			case 'l':
				hideLog = false;
				break;
			case 's':
				g_Config.bAutoRun = false;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strcmp(argv[i], "--log") && i < argc - 1)
					fileToLog = argv[++i];
				if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
					fileToLog = argv[i] + strlen("--log=");
				if (!strcmp(argv[i], "--state") && i < argc - 1)
					stateToLoad = argv[++i];
				if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
					stateToLoad = argv[i] + strlen("--state=");
				break;
			}
		}
		else if (fileToStart.isNull())
		{
			fileToStart = QString(argv[i]);
			if (!QFile::exists(fileToStart))
			{
				qCritical("File '%s' does not exist!", qPrintable(fileToStart));
				exit(1);
			}
		}
		else
		{
			qCritical("Can only boot one file. Ignoring file '%s'", qPrintable(fileToStart));
		}
	}

	if (g_Config.currentDirectory == "")
	{
		g_Config.currentDirectory = getenv("HOME");
	}

	g_Config.memCardDirectory = std::string(getenv("HOME"))+"/.ppsspp/";
	g_Config.flashDirectory = g_Config.memCardDirectory+"/flash/";


	LogManager::Init();
	if (fileToLog != NULL)
			LogManager::GetInstance()->ChangeFileLog(fileToLog);
	//LogManager::GetInstance()->GetConsoleListener()->Open(hideLog, 150, 120, "PPSSPP Debug Console");
	LogManager::GetInstance()->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
}
예제 #9
0
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
  (JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jint jxres, jint jyres, jstring jlangRegion, jstring japkpath,
		jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jshortcutParam,
		jstring jinstallID, jint jAndroidVersion) {
	jniEnvUI = env;

	setCurrentThreadName("androidInit");

	ILOG("NativeApp.init() -- begin");
	PROFILE_INIT();

	memset(&input_state, 0, sizeof(input_state));
	renderer_inited = false;
	first_lost = true;
	androidVersion = jAndroidVersion;
	deviceType = jdeviceType;

	g_buttonTracker.Reset();

	left_joystick_x_async = 0;
	left_joystick_y_async = 0;
	right_joystick_x_async = 0;
	right_joystick_y_async = 0;
	hat_joystick_x_async = 0;
	hat_joystick_y_async = 0;
	display_xres = jxres;
	display_yres = jyres;

	std::string apkPath = GetJavaString(env, japkpath);
	VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));

	systemName = GetJavaString(env, jmodel);
	langRegion = GetJavaString(env, jlangRegion);

	std::string externalDir = GetJavaString(env, jexternalDir);
	std::string user_data_path = GetJavaString(env, jdataDir) + "/";
	library_path = GetJavaString(env, jlibraryDir) + "/";
	std::string shortcut_param = GetJavaString(env, jshortcutParam);
	std::string installID = GetJavaString(env, jinstallID);

	ILOG("NativeApp.init(): External storage path: %s", externalDir.c_str());
	ILOG("NativeApp.init(): Launch shortcut parameter: %s", shortcut_param.c_str());

	std::string app_name;
	std::string app_nice_name;
	std::string version;
	bool landscape;

	net::Init();

	NativeGetAppInfo(&app_name, &app_nice_name, &landscape, &version);

	// If shortcut_param is not empty, pass it as additional varargs argument to NativeInit() method.
	// NativeInit() is expected to treat extra argument as boot_filename, which in turn will start game immediately.
	// NOTE: Will only work if ppsspp started from Activity.onCreate(). Won't work if ppsspp app start from onResume().

	if (shortcut_param.empty()) {
		const char *argv[2] = {app_name.c_str(), 0};
		NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), installID.c_str());
	}
	else {
		const char *argv[3] = {app_name.c_str(), shortcut_param.c_str(), 0};
		NativeInit(2, argv, user_data_path.c_str(), externalDir.c_str(), installID.c_str());
	}

	ILOG("NativeApp.init() -- end");
}
예제 #10
0
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
	(JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
		jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jcacheDir, jstring jshortcutParam,
		jint jAndroidVersion, jstring jboard) {
	setCurrentThreadName("androidInit");

	// Makes sure we get early permission grants.
	ProcessFrameCommands(env);

	ILOG("NativeApp.init() -- begin");
	PROFILE_INIT();

	renderer_inited = false;
	androidVersion = jAndroidVersion;
	deviceType = jdeviceType;

	left_joystick_x_async = 0;
	left_joystick_y_async = 0;
	right_joystick_x_async = 0;
	right_joystick_y_async = 0;
	hat_joystick_x_async = 0;
	hat_joystick_y_async = 0;

	std::string apkPath = GetJavaString(env, japkpath);
	VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));

	systemName = GetJavaString(env, jmodel);
	langRegion = GetJavaString(env, jlangRegion);

	std::string externalDir = GetJavaString(env, jexternalDir);
	std::string user_data_path = GetJavaString(env, jdataDir);
	if (user_data_path.size() > 0)
		user_data_path += "/";
	library_path = GetJavaString(env, jlibraryDir) + "/";
	std::string shortcut_param = GetJavaString(env, jshortcutParam);
	std::string cacheDir = GetJavaString(env, jcacheDir);
	std::string buildBoard = GetJavaString(env, jboard);
	boardName = buildBoard;
	ILOG("NativeApp.init(): External storage path: %s", externalDir.c_str());
	ILOG("NativeApp.init(): Launch shortcut parameter: %s", shortcut_param.c_str());

	std::string app_name;
	std::string app_nice_name;
	std::string version;
	bool landscape;

	// Unfortunately, on the Samsung Galaxy S7, this isn't in /proc/cpuinfo.
	// We also can't read it from __system_property_get.
	if (buildBoard == "universal8890") {
		cpu_info.sQuirks.bExynos8890DifferingCachelineSizes = true;
	}

	NativeGetAppInfo(&app_name, &app_nice_name, &landscape, &version);

	// If shortcut_param is not empty, pass it as additional varargs argument to NativeInit() method.
	// NativeInit() is expected to treat extra argument as boot_filename, which in turn will start game immediately.
	// NOTE: Will only work if ppsspp started from Activity.onCreate(). Won't work if ppsspp app start from onResume().

	if (shortcut_param.empty()) {
		const char *argv[2] = {app_name.c_str(), 0};
		NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
	} else {
		const char *argv[3] = {app_name.c_str(), shortcut_param.c_str(), 0};
		NativeInit(2, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
	}

retry:
	// Now that we've loaded config, set javaGL.
	javaGL = NativeQueryConfig("androidJavaGL") == "true";

	switch (g_Config.iGPUBackend) {
	case (int)GPUBackend::OPENGL:
		useCPUThread = true;
		if (javaGL) {
			ILOG("NativeApp.init() -- creating OpenGL context (JavaGL)");
			graphicsContext = new AndroidJavaEGLGraphicsContext();
		} else {
			graphicsContext = new AndroidEGLGraphicsContext();
		}
		break;
	case (int)GPUBackend::VULKAN:
	{
		ILOG("NativeApp.init() -- creating Vulkan context");
		useCPUThread = false;  // The Vulkan render manager manages its own thread.
		// We create and destroy the Vulkan graphics context in the "EGL" thread.
		AndroidVulkanContext *ctx = new AndroidVulkanContext();
		if (!ctx->InitAPI()) {
			ILOG("Failed to initialize Vulkan, switching to OpenGL");
			g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
			SetGPUBackend(GPUBackend::OPENGL);
			goto retry;
		} else {
			graphicsContext = ctx;
		}
		break;
	}
	default:
		ELOG("NativeApp.init(): iGPUBackend %d not supported. Switching to OpenGL.", (int)g_Config.iGPUBackend);
		g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
		goto retry;
		// Crash();
	}

	if (useCPUThread) {
		ILOG("NativeApp.init() - launching emu thread");
		EmuThreadStart();
	}
}
예제 #11
0
파일: NativeApp.cpp 프로젝트: Kyhel/ppsspp
void NativeInit(int argc, const char *argv[],
								const char *savegame_directory, const char *external_directory, const char *installID) {
#ifdef ANDROID_NDK_PROFILER
	setenv("CPUPROFILE_FREQUENCY", "500", 1);
	setenv("CPUPROFILE", "/sdcard/gmon.out", 1);
	monstartup("ppsspp_jni.so");
#endif

	bool skipLogo = false;
	EnableFZ();
	setlocale( LC_ALL, "C" );
	std::string user_data_path = savegame_directory;
	isMessagePending = false;

#ifdef IOS
	user_data_path += "/";
#elif defined(__APPLE__)
	if (File::Exists(File::GetExeDirectory() + "assets"))
		VFSRegister("", new DirectoryAssetReader((File::GetExeDirectory() + "assets/").c_str()));
	// It's common to be in a build-xyz/ directory.
	else
		VFSRegister("", new DirectoryAssetReader((File::GetExeDirectory() + "../assets/").c_str()));
	VFSRegister("", new DirectoryAssetReader((File::GetExeDirectory()).c_str()));
#endif

	// We want this to be FIRST.
#ifdef USING_QT_UI
	VFSRegister("", new AssetsAssetReader());
#elif defined(BLACKBERRY) || defined(IOS)
	// Packed assets are included in app
	VFSRegister("", new DirectoryAssetReader(external_directory));
#else
	VFSRegister("", new DirectoryAssetReader("assets/"));
#endif
	VFSRegister("", new DirectoryAssetReader(savegame_directory));

	host = new NativeHost();

#if defined(ANDROID)
	g_Config.internalDataDirectory = savegame_directory;
	// Maybe there should be an option to use internal memory instead, but I think
	// that for most people, using external memory (SDCard/USB Storage) makes the
	// most sense.
	g_Config.memCardDirectory = std::string(external_directory) + "/";
	g_Config.flash0Directory = std::string(external_directory) + "/flash0/";
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(IOS)
	g_Config.memCardDirectory = user_data_path;
	g_Config.flash0Directory = std::string(external_directory) + "/flash0/";
#elif !defined(_WIN32)
	char* config = getenv("XDG_CONFIG_HOME");
	if (!config) {
		config = getenv("HOME");
		strcat(config, "/.config");
	}
	g_Config.memCardDirectory = std::string(config) + "/ppsspp/";
	std::string program_path = File::GetExeDirectory();
	if (program_path.empty())
		g_Config.flash0Directory = g_Config.memCardDirectory + "/flash0/";
	else if (File::Exists(program_path + "flash0"))
		g_Config.flash0Directory = program_path + "flash0/";
	// It's common to be in a build-xyz/ directory.
	else
		g_Config.flash0Directory = program_path + "../flash0/";
#endif

#ifndef _WIN32
	logger = new AndroidLogger();

	LogManager::Init();
	LogManager *logman = LogManager::GetInstance();
	ILOG("Logman: %p", logman);

	g_Config.AddSearchPath(user_data_path);
	g_Config.AddSearchPath(g_Config.memCardDirectory + "PSP/SYSTEM/");
	g_Config.SetDefaultPath(g_Config.memCardDirectory + "PSP/SYSTEM/");
	g_Config.Load();
	g_Config.externalDirectory = external_directory;
#endif

#ifdef ANDROID
	// On Android, create a PSP directory tree in the external_directory,
	// to hopefully reduce confusion a bit. 
	ILOG("Creating %s", (g_Config.memCardDirectory + "PSP").c_str());
	mkDir((g_Config.memCardDirectory + "PSP").c_str());
	mkDir((g_Config.memCardDirectory + "PSP/SAVEDATA").c_str());
	mkDir((g_Config.memCardDirectory + "PSP/GAME").c_str());
#endif

	const char *fileToLog = 0;
	const char *stateToLoad = 0;

	bool gfxLog = false;
	// Parse command line
	LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'd':
				// Enable debug logging
				// Note that you must also change the max log level in Log.h.
				logLevel = LogTypes::LDEBUG;
				break;
			case 'g':
				gfxLog = true;
				break;
			case 'j':
				g_Config.bJit = true;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.bJit = false;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
					fileToLog = argv[i] + strlen("--log=");
				if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
					stateToLoad = argv[i] + strlen("--state=");
				break;
			}
		} else {
			if (boot_filename.empty()) {
				boot_filename = argv[i];
				skipLogo = true;

				FileInfo info;
				if (!getFileInfo(boot_filename.c_str(), &info) || info.exists == false) {
					fprintf(stderr, "File not found: %s\n", boot_filename.c_str());
					exit(1);
				}
			} else {
				fprintf(stderr, "Can only boot one file");
				exit(1);
			}
		}
	}

	if (fileToLog != NULL)
		LogManager::GetInstance()->ChangeFileLog(fileToLog);

#ifndef _WIN32
	if (g_Config.currentDirectory == "") {
#if defined(ANDROID)
		g_Config.currentDirectory = external_directory;
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(IOS) || defined(_WIN32)
		g_Config.currentDirectory = savegame_directory;
#else
		g_Config.currentDirectory = getenv("HOME");
#endif
	}

	for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
	{
		LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
		logman->SetEnable(type, true);
		logman->SetLogLevel(type, gfxLog && i == LogTypes::G3D ? LogTypes::LDEBUG : logLevel);
#ifdef ANDROID
		logman->AddListener(type, logger);
#endif
	}
	// Special hack for G3D as it's very spammy. Need to make a flag for this.
	if (!gfxLog)
		logman->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
	INFO_LOG(BOOT, "Logger inited.");
#endif	

	i18nrepo.LoadIni(g_Config.sLanguageIni);
	I18NCategory *d = GetI18NCategory("DesktopUI");
	// Note to translators: do not translate this/add this to PPSSPP-lang's files. 
	// It's intended to be custom for every user. 
	// Only add it to your own personal copies of PPSSPP.
#ifdef _WIN32
	// TODO: Could allow a setting to specify a font file to load?
	// TODO: Make this a constant if we can sanely load the font on other systems?
	AddFontResourceEx(L"assets/Roboto-Condensed.ttf", FR_PRIVATE, NULL);
	g_Config.sFont = d->T("Font", "Roboto");
#endif

	if (!boot_filename.empty() && stateToLoad != NULL)
		SaveState::Load(stateToLoad);

	g_gameInfoCache.Init();


	screenManager = new ScreenManager();

	if (skipLogo) {
		screenManager->switchScreen(new EmuScreen(boot_filename));
	} else {
		screenManager->switchScreen(new LogoScreen());
	}

	std::string sysName = System_GetProperty(SYSPROP_NAME);
	isOuya = KeyMap::IsOuya(sysName);
}
예제 #12
0
파일: Headless.cpp 프로젝트: Arakash/ppsspp
int main(int argc, const char* argv[])
{
#ifdef ANDROID_NDK_PROFILER
	setenv("CPUPROFILE_FREQUENCY", "500", 1);
	setenv("CPUPROFILE", "/sdcard/gmon.out", 1);
	monstartup("ppsspp_headless");
#endif

	bool fullLog = false;
	bool useJit = true;
	bool autoCompare = false;
	bool verbose = false;
	const char *stateToLoad = 0;
	GPUCore gpuCore = GPU_NULL;
	
	std::vector<std::string> testFilenames;
	const char *mountIso = 0;
	const char *screenshotFilename = 0;
	bool readMount = false;
	float timeout = std::numeric_limits<float>::infinity();

	for (int i = 1; i < argc; i++)
	{
		if (readMount)
		{
			mountIso = argv[i];
			readMount = false;
			continue;
		}
		if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--mount"))
			readMount = true;
		else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--log"))
			fullLog = true;
		else if (!strcmp(argv[i], "-i"))
			useJit = false;
		else if (!strcmp(argv[i], "-j"))
			useJit = true;
		else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compare"))
			autoCompare = true;
		else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))
			verbose = true;
		else if (!strncmp(argv[i], "--graphics=", strlen("--graphics=")) && strlen(argv[i]) > strlen("--graphics="))
		{
			const char *gpuName = argv[i] + strlen("--graphics=");
			if (!strcasecmp(gpuName, "gles"))
				gpuCore = GPU_GLES;
			else if (!strcasecmp(gpuName, "software"))
				gpuCore = GPU_SOFTWARE;
			else if (!strcasecmp(gpuName, "directx9"))
				gpuCore = GPU_DIRECTX9;
			else if (!strcasecmp(gpuName, "null"))
				gpuCore = GPU_NULL;
			else
			{
				printUsage(argv[0], "Unknown gpu backend specified after --graphics=");
				return 1;
			}
		}
		// Default to GLES if no value selected.
		else if (!strcmp(argv[i], "--graphics"))
			gpuCore = GPU_GLES;
		else if (!strncmp(argv[i], "--screenshot=", strlen("--screenshot=")) && strlen(argv[i]) > strlen("--screenshot="))
			screenshotFilename = argv[i] + strlen("--screenshot=");
		else if (!strncmp(argv[i], "--timeout=", strlen("--timeout=")) && strlen(argv[i]) > strlen("--timeout="))
			timeout = strtod(argv[i] + strlen("--timeout="), NULL);
		else if (!strcmp(argv[i], "--teamcity"))
			teamCityMode = true;
		else if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
			stateToLoad = argv[i] + strlen("--state=");
		else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
		{
			printUsage(argv[0], NULL);
			return 1;
		}
		else
			testFilenames.push_back(argv[i]);
	}

	// TODO: Allow a filename here?
	if (testFilenames.size() == 1 && testFilenames[0] == "@-")
	{
		testFilenames.clear();
		char temp[2048];
		temp[2047] = '\0';

		while (scanf("%2047s", temp) == 1)
			testFilenames.push_back(temp);
	}

	if (readMount)
	{
		printUsage(argv[0], "Missing argument after -m");
		return 1;
	}
	if (testFilenames.empty())
	{
		printUsage(argv[0], argc <= 1 ? NULL : "No executables specified");
		return 1;
	}

	HeadlessHost *headlessHost = getHost(gpuCore);
	host = headlessHost;

	std::string error_string;
	bool glWorking = host->InitGL(&error_string);

	LogManager::Init();
	LogManager *logman = LogManager::GetInstance();
	
	PrintfLogger *printfLogger = new PrintfLogger();

	for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
	{
		LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
		logman->SetEnable(type, fullLog);
		logman->SetLogLevel(type, LogTypes::LDEBUG);
		logman->AddListener(type, printfLogger);
	}

	CoreParameter coreParameter;
	coreParameter.cpuCore = useJit ? CPU_JIT : CPU_INTERPRETER;
	coreParameter.gpuCore = glWorking ? gpuCore : GPU_NULL;
	coreParameter.enableSound = false;
	coreParameter.mountIso = mountIso ? mountIso : "";
	coreParameter.startPaused = false;
	coreParameter.printfEmuLog = !autoCompare;
	coreParameter.headLess = true;
	coreParameter.renderWidth = 480;
	coreParameter.renderHeight = 272;
	coreParameter.pixelWidth = 480;
	coreParameter.pixelHeight = 272;
	coreParameter.unthrottle = true;

	g_Config.bEnableSound = false;
	g_Config.bFirstRun = false;
	g_Config.bIgnoreBadMemAccess = true;
	// Never report from tests.
	g_Config.sReportHost = "";
	g_Config.bAutoSaveSymbolMap = false;
	g_Config.iRenderingMode = 0;
	g_Config.bHardwareTransform = true;
#ifdef USING_GLES2
	g_Config.iAnisotropyLevel = 0;
#else
	g_Config.iAnisotropyLevel = 8;
#endif
	g_Config.bVertexCache = true;
	g_Config.bTrueColor = true;
	g_Config.iLanguage = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH;
	g_Config.iTimeFormat = PSP_SYSTEMPARAM_TIME_FORMAT_24HR;
	g_Config.bEncryptSave = true;
	g_Config.sNickName = "shadow";
	g_Config.iTimeZone = 60;
	g_Config.iDateFormat = PSP_SYSTEMPARAM_DATE_FORMAT_DDMMYYYY;
	g_Config.iButtonPreference = PSP_SYSTEMPARAM_BUTTON_CROSS;
	g_Config.iLockParentalLevel = 9;
	g_Config.iInternalResolution = 1;
	g_Config.bFrameSkipUnthrottle = false;
	g_Config.bEnableLogging = fullLog;
	g_Config.iNumWorkerThreads = 1;
	g_Config.iBGMVolume = MAX_CONFIG_VOLUME;
	g_Config.iSFXVolume = MAX_CONFIG_VOLUME;
	g_Config.bSoftwareSkinning = true;
	g_Config.bVertexDecoderJit = true;

#ifdef _WIN32
	InitSysDirectories();
#endif

#if defined(ANDROID)
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__)
#elif !defined(_WIN32)
	g_Config.memCardDirectory = std::string(getenv("HOME")) + "/.ppsspp/";
#endif

	// Try to find the flash0 directory.  Often this is from a subdirectory.
	for (int i = 0; i < 3; ++i)
	{
		if (!File::Exists(g_Config.flash0Directory))
			g_Config.flash0Directory += "../../flash0/";
	}
	// Or else, maybe in the executable's dir.
	if (!File::Exists(g_Config.flash0Directory))
		g_Config.flash0Directory = File::GetExeDirectory() + "flash0/";

	if (screenshotFilename != 0)
		headlessHost->SetComparisonScreenshot(screenshotFilename);

#ifdef ANDROID
	// For some reason the debugger installs it with this name?
	if (File::Exists("/data/app/org.ppsspp.ppsspp-2.apk")) {
		VFSRegister("", new ZipAssetReader("/data/app/org.ppsspp.ppsspp-2.apk", "assets/"));
	}
	if (File::Exists("/data/app/org.ppsspp.ppsspp.apk")) {
		VFSRegister("", new ZipAssetReader("/data/app/org.ppsspp.ppsspp.apk", "assets/"));
	}
#endif

	if (stateToLoad != NULL)
		SaveState::Load(stateToLoad);

	std::vector<std::string> failedTests;
	std::vector<std::string> passedTests;
	for (size_t i = 0; i < testFilenames.size(); ++i)
	{
		coreParameter.fileToStart = testFilenames[i];
		if (autoCompare)
			printf("%s:\n", coreParameter.fileToStart.c_str());
		bool passed = RunAutoTest(headlessHost, coreParameter, autoCompare, verbose, timeout);
		if (autoCompare)
		{
			std::string testName = GetTestName(coreParameter.fileToStart);
			if (passed)
			{
				passedTests.push_back(testName);
				printf("  %s - passed!\n", testName.c_str());
			}
			else
				failedTests.push_back(testName);
		}
	}

	if (autoCompare)
	{
		printf("%d tests passed, %d tests failed.\n", (int)passedTests.size(), (int)failedTests.size());
		if (!failedTests.empty())
		{
			printf("Failed tests:\n");
			for (size_t i = 0; i < failedTests.size(); ++i) {
				printf("  %s\n", failedTests[i].c_str());
			}
		}
	}

	host->ShutdownGL();
	delete host;
	host = NULL;
	headlessHost = NULL;

#ifdef ANDROID_NDK_PROFILER
	moncleanup();
#endif

	return 0;
}
예제 #13
0
파일: QtHost.cpp 프로젝트: bollu/ppsspp
void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID)
{
	isMessagePending = false;

	std::string user_data_path = savegame_directory;
	std::string memcard_path = QDir::homePath().toStdString() + "/.ppsspp/";

	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(user_data_path.c_str()));

	g_Config.AddSearchPath(user_data_path);
	g_Config.AddSearchPath(memcard_path + "PSP/SYSTEM/");
	g_Config.SetDefaultPath(g_Config.memCardDirectory + "PSP/SYSTEM/");
	g_Config.Load();

	const char *fileToLog = 0;

	// Parse command line
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'j':
				g_Config.bJit = true;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.bJit = false;
				g_Config.bSaveSettings = false;
				break;
			case 's':
				g_Config.bAutoRun = false;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strcmp(argv[i], "--log") && i < argc - 1)
					fileToLog = argv[++i];
				if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
					fileToLog = argv[i] + strlen("--log=");
				if (!strcmp(argv[i], "--state") && i < argc - 1)
					stateToLoad = argv[++i];
				if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
					stateToLoad = argv[i] + strlen("--state=");
				break;
			}
		}
		else if (fileToStart.isNull())
		{
			fileToStart = QString(argv[i]);
			if (!QFile::exists(fileToStart))
			{
				qCritical("File '%s' does not exist!", qPrintable(fileToStart));
				exit(1);
			}
		}
		else
		{
			qCritical("Can only boot one file. Ignoring file '%s'", qPrintable(fileToStart));
		}
	}

	if (g_Config.currentDirectory == "")
	{
		g_Config.currentDirectory = QDir::homePath().toStdString();
	}

	g_Config.memCardDirectory = QDir::homePath().toStdString() + "/.ppsspp/";

#if defined(Q_OS_LINUX) && !defined(ARM)
	std::string program_path = QCoreApplication::applicationDirPath().toStdString();
	if (File::Exists(program_path + "/flash0"))
		g_Config.flash0Directory = program_path + "/flash0/";
	else if (File::Exists(program_path + "/../flash0"))
		g_Config.flash0Directory = program_path + "/../flash0/";
	else
		g_Config.flash0Directory = g_Config.memCardDirectory + "/flash0/";
#else
	g_Config.flash0Directory = g_Config.memCardDirectory + "/flash0/";
#endif

	LogManager::Init();
	if (fileToLog != NULL)
		LogManager::GetInstance()->ChangeFileLog(fileToLog);

	g_gameInfoCache.Init();

#if !defined(ARM)
	// Start Desktop UI
	MainWindow* mainWindow = new MainWindow();
	mainWindow->show();
#endif
}
예제 #14
0
파일: main.cpp 프로젝트: Alceris/ppsspp
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
	setCurrentThreadName("Main");

	CoInitializeEx(NULL, COINIT_MULTITHREADED);

#ifdef _DEBUG
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
	PROFILE_INIT();

#if defined(_M_X64) && defined(_MSC_VER) && _MSC_VER < 1900
	// FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it.
	_set_FMA3_enable(0);
#endif

	EnableCrashingOnCrashes();

#ifndef _DEBUG
	bool showLog = false;
#else
	bool showLog = true;
#endif

	const std::string &exePath = File::GetExeDirectory();
	VFSRegister("", new DirectoryAssetReader((exePath + "/assets/").c_str()));
	VFSRegister("", new DirectoryAssetReader(exePath.c_str()));

	langRegion = GetDefaultLangRegion();
	osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture();

	char configFilename[MAX_PATH] = { 0 };
	const std::wstring configOption = L"--config=";

	char controlsConfigFilename[MAX_PATH] = { 0 };
	const std::wstring controlsOption = L"--controlconfig=";

	std::vector<std::wstring> wideArgs = GetWideCmdLine();

	for (size_t i = 1; i < wideArgs.size(); ++i) {
		if (wideArgs[i][0] == L'\0')
			continue;
		if (wideArgs[i][0] == L'-') {
			if (wideArgs[i].find(configOption) != std::wstring::npos && wideArgs[i].size() > configOption.size()) {
				const std::wstring tempWide = wideArgs[i].substr(configOption.size());
				const std::string tempStr = ConvertWStringToUTF8(tempWide);
				std::strncpy(configFilename, tempStr.c_str(), MAX_PATH);
			}

			if (wideArgs[i].find(controlsOption) != std::wstring::npos && wideArgs[i].size() > controlsOption.size()) {
				const std::wstring tempWide = wideArgs[i].substr(controlsOption.size());
				const std::string tempStr = ConvertWStringToUTF8(tempWide);
				std::strncpy(controlsConfigFilename, tempStr.c_str(), MAX_PATH);
			}
		}
	}

	// On Win32 it makes more sense to initialize the system directories here 
	// because the next place it was called was in the EmuThread, and it's too late by then.
	InitSysDirectories();

	// Load config up here, because those changes below would be overwritten
	// if it's not loaded here first.
	g_Config.AddSearchPath("");
	g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
	g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM));
	g_Config.Load(configFilename, controlsConfigFilename);

	bool debugLogLevel = false;

	const std::wstring gpuBackend = L"--graphics=";

	// The rest is handled in NativeInit().
	for (size_t i = 1; i < wideArgs.size(); ++i) {
		if (wideArgs[i][0] == L'\0')
			continue;

		if (wideArgs[i][0] == L'-') {
			switch (wideArgs[i][1]) {
			case L'l':
				showLog = true;
				g_Config.bEnableLogging = true;
				break;
			case L's':
				g_Config.bAutoRun = false;
				g_Config.bSaveSettings = false;
				break;
			case L'd':
				debugLogLevel = true;
				break;
			}

			if (wideArgs[i] == L"--fullscreen")
				g_Config.bFullScreen = true;

			if (wideArgs[i] == L"--windowed")
				g_Config.bFullScreen = false;

			if (wideArgs[i].find(gpuBackend) != std::wstring::npos && wideArgs[i].size() > gpuBackend.size()) {
				const std::wstring restOfOption = wideArgs[i].substr(gpuBackend.size());

				// Force software rendering off, as picking directx9 or gles implies HW acceleration.
				// Once software rendering supports Direct3D9/11, we can add more options for software,
				// such as "software-gles", "software-d3d9", and "software-d3d11", or something similar.
				// For now, software rendering force-activates OpenGL.
				if (restOfOption == L"directx9") {
					g_Config.iGPUBackend = GPU_BACKEND_DIRECT3D9;
					g_Config.bSoftwareRendering = false;
				} else if (restOfOption == L"gles") {
					g_Config.iGPUBackend = GPU_BACKEND_OPENGL;
					g_Config.bSoftwareRendering = false;
				} else if (restOfOption == L"software") {
					g_Config.iGPUBackend = GPU_BACKEND_OPENGL;
					g_Config.bSoftwareRendering = true;
				}
			}
		}
	}
#ifdef _DEBUG
	g_Config.bEnableLogging = true;
#endif

	if (iCmdShow == SW_MAXIMIZE) {
		// Consider this to mean --fullscreen.
		g_Config.bFullScreen = true;
	}

	LogManager::Init();
	// Consider at least the following cases before changing this code:
	//   - By default in Release, the console should be hidden by default even if logging is enabled.
	//   - By default in Debug, the console should be shown by default.
	//   - The -l switch is expected to show the log console, REGARDLESS of config settings.
	//   - It should be possible to log to a file without showing the console.
	LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console");
	
	if (debugLogLevel)
		LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG);

	//Windows, API init stuff
	INITCOMMONCONTROLSEX comm;
	comm.dwSize = sizeof(comm);
	comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
	InitCommonControlsEx(&comm);
	timeBeginPeriod(1);
	MainWindow::Init(_hInstance);

	g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS);

	MainWindow::Show(_hInstance);

	HWND hwndMain = MainWindow::GetHWND();
	HWND hwndDisplay = MainWindow::GetDisplayHWND();
	
	//initialize custom controls
	CtrlDisAsmView::init();
	CtrlMemView::init();
	CtrlRegisterList::init();
	CGEDebugger::Init();

	DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));

	host = new WindowsHost(_hInstance, hwndMain, hwndDisplay);
	host->SetWindowTitle(0);

	MainWindow::CreateDebugWindows();

	const bool minimized = iCmdShow == SW_MINIMIZE || iCmdShow == SW_SHOWMINIMIZED || iCmdShow == SW_SHOWMINNOACTIVE;
	if (minimized) {
		MainWindow::Minimize();
	}

	// Emu thread is always running!
	EmuThread_Start();
	InputDevice::BeginPolling();

	HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
	HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS);

	//so.. we're at the message pump of the GUI thread
	for (MSG msg; GetMessage(&msg, NULL, 0, 0); )	// for no quit
	{
		if (msg.message == WM_KEYDOWN)
		{
			//hack to enable/disable menu command accelerate keys
			MainWindow::UpdateCommands();
			 
			//hack to make it possible to get to main window from floating windows with Esc
			if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE)
				BringWindowToTop(hwndMain);
		}

		//Translate accelerators and dialog messages...
		HWND wnd;
		HACCEL accel;
		switch (g_activeWindow)
		{
		case WINDOW_MAINWINDOW:
			wnd = hwndMain;
			accel = hAccelTable;
			break;
		case WINDOW_CPUDEBUGGER:
			wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0;
			accel = hDebugAccelTable;
			break;
		case WINDOW_GEDEBUGGER:
		default:
			wnd = 0;
			accel = 0;
			break;
		}

		if (!TranslateAccelerator(wnd, accel, &msg))
		{
			if (!DialogManager::IsDialogMessage(&msg))
			{
				//and finally translate and dispatch
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}

	VFSShutdown();

	InputDevice::StopPolling();
	EmuThread_Stop();

	MainWindow::DestroyDebugWindows();
	DialogManager::DestroyAll();
	timeEndPeriod(1);
	delete host;

	g_Config.Save();
	LogManager::Shutdown();

	if (g_Config.bRestartRequired) {
		W32Util::ExitAndRestart();
	}

	CoUninitialize();

	return 0;
}
예제 #15
0
파일: NativeApp.cpp 프로젝트: arg274/ppsspp
void NativeInit(int argc, const char *argv[],
								const char *savegame_directory, const char *external_directory, const char *installID) {
	bool skipLogo = false;
	EnableFZ();
	setlocale( LC_ALL, "C" );
	std::string user_data_path = savegame_directory;
	isMessagePending = false;

#ifdef IOS
	user_data_path += "/";
#elif defined(__APPLE__)
    char program_path[4090];
    uint32_t program_path_size = sizeof(program_path);
    _NSGetExecutablePath(program_path,&program_path_size);
    *(strrchr(program_path, '/')+1) = '\0';
    char assets_path[4096];
    sprintf(assets_path,"%sassets/",program_path);
    VFSRegister("", new DirectoryAssetReader(assets_path));
#endif

	// We want this to be FIRST.
#ifndef USING_QT_UI
#if defined(BLACKBERRY) || defined(IOS)
	// Packed assets are included in app
	VFSRegister("", new DirectoryAssetReader(external_directory));
#else
	VFSRegister("", new DirectoryAssetReader("assets/"));
#endif
#endif
	VFSRegister("", new DirectoryAssetReader(savegame_directory));

	host = new NativeHost();

#if defined(ANDROID)
	g_Config.internalDataDirectory = savegame_directory;
	// Maybe there should be an option to use internal memory instead, but I think
	// that for most people, using external memory (SDCard/USB Storage) makes the
	// most sense.
	g_Config.memCardDirectory = std::string(external_directory) + "/";
	g_Config.flash0Directory = std::string(external_directory) + "/flash0/";
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(IOS)
	g_Config.memCardDirectory = user_data_path;
	g_Config.flash0Directory = std::string(external_directory) + "/flash0/";
#elif !defined(_WIN32)
	// Linux, Mac.  Does this path really make sense?
	g_Config.memCardDirectory = std::string(getenv("HOME")) + "/.ppsspp/";
	g_Config.flash0Directory = g_Config.memCardDirectory + "/flash0/";
#endif

#ifndef _WIN32
	logger = new AndroidLogger();

	LogManager::Init();
	LogManager *logman = LogManager::GetInstance();
	ILOG("Logman: %p", logman);

	g_Config.AddSearchPath(user_data_path);
	g_Config.AddSearchPath(g_Config.memCardDirectory + "PSP/SYSTEM/");
	g_Config.SetDefaultPath(g_Config.memCardDirectory + "PSP/SYSTEM/");
	g_Config.Load();
	g_Config.externalDirectory = external_directory;
#endif

#ifdef ANDROID
	// On Android, create a PSP directory tree in the external_directory,
	// to hopefully reduce confusion a bit. 
	ILOG("Creating %s", (g_Config.memCardDirectory + "PSP").c_str());
	mkDir((g_Config.memCardDirectory + "PSP").c_str());
	mkDir((g_Config.memCardDirectory + "PSP/SAVEDATA").c_str());
	mkDir((g_Config.memCardDirectory + "PSP/GAME").c_str());
#endif

	const char *fileToLog = 0;
	const char *stateToLoad = 0;

	bool gfxLog = false;
	// Parse command line
	LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'd':
				// Enable debug logging
				// Note that you must also change the max log level in Log.h.
				logLevel = LogTypes::LDEBUG;
				break;
			case 'g':
				gfxLog = true;
				break;
			case 'j':
				g_Config.bJit = true;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.bJit = false;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
					fileToLog = argv[i] + strlen("--log=");
				if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
					stateToLoad = argv[i] + strlen("--state=");
				break;
			}
		} else {
			if (boot_filename.empty()) {
				boot_filename = argv[i];
				skipLogo = true;

				FileInfo info;
				if (!getFileInfo(boot_filename.c_str(), &info) || info.exists == false) {
					fprintf(stderr, "File not found: %s\n", boot_filename.c_str());
					exit(1);
				}
			} else {
				fprintf(stderr, "Can only boot one file");
				exit(1);
			}
		}
	}

	if (fileToLog != NULL)
		LogManager::GetInstance()->ChangeFileLog(fileToLog);

#ifndef _WIN32
	if (g_Config.currentDirectory == "") {
#if defined(ANDROID)
		g_Config.currentDirectory = external_directory;
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(IOS) || defined(_WIN32)
		g_Config.currentDirectory = savegame_directory;
#else
		g_Config.currentDirectory = getenv("HOME");
#endif
	}

	for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
	{
		LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
		logman->SetEnable(type, true);
		logman->SetLogLevel(type, gfxLog && i == LogTypes::G3D ? LogTypes::LDEBUG : logLevel);
#ifdef ANDROID
		logman->AddListener(type, logger);
#endif
	}
#ifdef __SYMBIAN32__
	g_Config.bHardwareTransform = true;
	g_Config.bSeparateCPUThread = false;
	g_Config.bSeparateIOThread = false;
#endif
	// Special hack for G3D as it's very spammy. Need to make a flag for this.
	if (!gfxLog)
		logman->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
	INFO_LOG(BOOT, "Logger inited.");
#endif	

	i18nrepo.LoadIni(g_Config.sLanguageIni);
	I18NCategory *d = GetI18NCategory("DesktopUI");
	// Note to translators: do not translate this/add this to PPSSPP-lang's files. 
	// It's intended to be custom for every user. 
	// Only add it to your own personal copies of PPSSPP.
#ifdef _WIN32
	// TODO: Could allow a setting to specify a font file to load?
	// TODO: Make this a constant if we can sanely load the font on other systems?
	AddFontResourceEx(L"assets/Roboto-Condensed.ttf", FR_PRIVATE, NULL);
	g_Config.sFont = d->T("Font", "Roboto");
#endif

	if (!boot_filename.empty() && stateToLoad != NULL)
		SaveState::Load(stateToLoad);
	
	g_gameInfoCache.Init();


	screenManager = new ScreenManager();

	if (boot_filename.empty()) {
#if (defined(_WIN32) && (defined(_M_IX86) || defined(_M_X64))) || defined(ARMEABI) || defined(ARMEABI_V7A) || (defined(MACOSX) && defined(_M_IX64))
		if (Atrac3plus_Decoder::CanAutoInstall()) {
			Atrac3plus_Decoder::DoAutoInstall();
		}
#endif
	}
	
	if (skipLogo) {
		screenManager->switchScreen(new EmuScreen(boot_filename));
	} else {
		screenManager->switchScreen(new LogoScreen(boot_filename));
	}
}
예제 #16
0
파일: QtHost.cpp 프로젝트: Carter07/ppsspp
void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID)
{
	Common::EnableCrashingOnCrashes();
	isMessagePending = false;

	std::string user_data_path = savegame_directory;
	std::string memcard_path = QDir::homePath().toStdString() + "/.ppsspp/";

	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(user_data_path.c_str()));

	g_Config.AddSearchPath(user_data_path);
	g_Config.AddSearchPath(memcard_path + "PSP/SYSTEM/");
	g_Config.SetDefaultPath(g_Config.memCardDirectory + "PSP/SYSTEM/");
	g_Config.Load();

	const char *fileToLog = 0;

	bool hideLog = true;
#ifdef _DEBUG
	hideLog = false;
#endif

	bool gfxLog = false;
	// Parse command line
	LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'd':
				// Enable debug logging
				logLevel = LogTypes::LDEBUG;
				break;
			case 'g':
				gfxLog = true;
				break;
			case 'j':
				g_Config.bJit = true;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.bJit = false;
				g_Config.bSaveSettings = false;
				break;
			case 'l':
				hideLog = false;
				break;
			case 's':
				g_Config.bAutoRun = false;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strcmp(argv[i], "--log") && i < argc - 1)
					fileToLog = argv[++i];
				if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
					fileToLog = argv[i] + strlen("--log=");
				if (!strcmp(argv[i], "--state") && i < argc - 1)
					stateToLoad = argv[++i];
				if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
					stateToLoad = argv[i] + strlen("--state=");
				break;
			}
		}
		else if (fileToStart.isNull())
		{
			fileToStart = QString(argv[i]);
			if (!QFile::exists(fileToStart))
			{
				qCritical("File '%s' does not exist!", qPrintable(fileToStart));
				exit(1);
			}
		}
		else
		{
			qCritical("Can only boot one file. Ignoring file '%s'", qPrintable(fileToStart));
		}
	}

	if (g_Config.currentDirectory == "")
	{
		g_Config.currentDirectory = QDir::homePath().toStdString();
	}

	g_Config.memCardDirectory = QDir::homePath().toStdString()+"/.ppsspp/";
	g_Config.flash0Directory = g_Config.memCardDirectory+"/flash0/";

	LogManager::Init();
	if (fileToLog != NULL)
		LogManager::GetInstance()->ChangeFileLog(fileToLog);

	LogManager::GetInstance()->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);

	g_gameInfoCache.Init();

#if !defined(USING_GLES2)
	// Start Desktop UI
	MainWindow* mainWindow = new MainWindow();
	mainWindow->show();
#endif
}
예제 #17
0
파일: main.cpp 프로젝트: Myoko/ppsspp
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
	Common::EnableCrashingOnCrashes();

	char *token = szCmdLine;
	char fileToLoad[256] = "";

	token = strtok(szCmdLine," ");

	g_Config.Load();
	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(""));

	while (token)
	{
		if (strcmp(token,"-run"))
		{
			//run immediately
		}

		token = strtok(NULL," ");
	}

	//Windows, API init stuff
	INITCOMMONCONTROLSEX comm;
	comm.dwSize = sizeof(comm);
	comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
	InitCommonControlsEx(&comm);
	timeBeginPeriod(1);
	MainWindow::Init(_hInstance);

	HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
	g_hPopupMenus = LoadMenu(_hInstance, (LPCSTR)IDR_POPUPMENUS);

	MainWindow::Show(_hInstance, iCmdShow);
	host = new WindowsHost(MainWindow::GetHWND(), MainWindow::GetDisplayHWND());

	HWND hwndMain = MainWindow::GetHWND();
	HMENU menu = GetMenu(hwndMain);

	//initialize custom controls
	CtrlDisAsmView::init();
	CtrlMemView::init();
	CtrlRegisterList::init();

	DialogManager::AddDlg(memoryWindow[0] = new CMemoryDlg(_hInstance, hwndMain, currentDebugMIPS));
	DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));

	MainWindow::Update();
	MainWindow::UpdateMenus();

	LogManager::Init();
	bool hidden = false;
#ifndef _DEBUG
	hidden = true;
#endif
	LogManager::GetInstance()->GetConsoleListener()->Open(hidden, 150, 120, "PPSSPP Debug Console");
	LogManager::GetInstance()->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
	if (strlen(fileToLoad))
	{
		// TODO: load the thing
	}

	//so.. we're at the message pump of the GUI thread
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))	//while no quit
	{
		//DSound_UpdateSound();

		//hack to make it possible to get to main window from floating windows with Esc
		if (msg.hwnd != hwndMain && msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE)
			BringWindowToTop(hwndMain);

		//Translate accelerators and dialog messages...
		if (!TranslateAccelerator(hwndMain, hAccelTable, &msg))
		{
			if (!DialogManager::IsDialogMessage(&msg))
			{
				//and finally translate and dispatch
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}

	LogManager::Shutdown();
	DialogManager::DestroyAll();
	timeEndPeriod(1);
	g_Config.Save();
	delete host;
	return 0;
}
예제 #18
0
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
  (JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
		jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jcacheDir, jstring jshortcutParam,
		jint jAndroidVersion, jstring jboard) {
	jniEnvUI = env;
	setCurrentThreadName("androidInit");

	ILOG("NativeApp.init() -- begin");
	PROFILE_INIT();

	memset(&input_state, 0, sizeof(input_state));
	renderer_inited = false;
	renderer_ever_inited = false;
	androidVersion = jAndroidVersion;
	deviceType = jdeviceType;

	g_buttonTracker.Reset();

	left_joystick_x_async = 0;
	left_joystick_y_async = 0;
	right_joystick_x_async = 0;
	right_joystick_y_async = 0;
	hat_joystick_x_async = 0;
	hat_joystick_y_async = 0;

	std::string apkPath = GetJavaString(env, japkpath);
	VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));

	systemName = GetJavaString(env, jmodel);
	langRegion = GetJavaString(env, jlangRegion);

	std::string externalDir = GetJavaString(env, jexternalDir);
	std::string user_data_path = GetJavaString(env, jdataDir) + "/";
	library_path = GetJavaString(env, jlibraryDir) + "/";
	std::string shortcut_param = GetJavaString(env, jshortcutParam);
	std::string cacheDir = GetJavaString(env, jcacheDir);
	std::string buildBoard = GetJavaString(env, jboard);

	ILOG("NativeApp.init(): External storage path: %s", externalDir.c_str());
	ILOG("NativeApp.init(): Launch shortcut parameter: %s", shortcut_param.c_str());

	std::string app_name;
	std::string app_nice_name;
	std::string version;
	bool landscape;

	net::Init();

	// Unfortunately, on the Samsung Galaxy S7, this isn't in /proc/cpuinfo.
	// We also can't read it from __system_property_get.
	if (buildBoard == "universal8890") {
		cpu_info.sQuirks.bExynos8890DifferingCachelineSizes = true;
	}

	NativeGetAppInfo(&app_name, &app_nice_name, &landscape, &version);

	// If shortcut_param is not empty, pass it as additional varargs argument to NativeInit() method.
	// NativeInit() is expected to treat extra argument as boot_filename, which in turn will start game immediately.
	// NOTE: Will only work if ppsspp started from Activity.onCreate(). Won't work if ppsspp app start from onResume().

	if (shortcut_param.empty()) {
		const char *argv[2] = {app_name.c_str(), 0};
		NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
	}
	else {
		const char *argv[3] = {app_name.c_str(), shortcut_param.c_str(), 0};
		NativeInit(2, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
	}

	// Now that we've loaded config, set javaGL.
	javaGL = NativeQueryConfig("androidJavaGL") == "true";

	ILOG("NativeApp.init() -- end");
}
예제 #19
0
파일: main.cpp 프로젝트: HelicopterP/ppsspp
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
	Common::EnableCrashingOnCrashes();

	bool hideLog = true;

#ifdef _DEBUG
	hideLog = false;
#endif


	// The rest is handled in NativeInit().
	for (int i = 1; i < __argc; ++i)
	{
		if (__argv[i][0] == '\0')
			continue;

		if (__argv[i][0] == '-')
		{
			switch (__argv[i][1])
			{
			case 'l':
				hideLog = false;
				break;
			case 's':
				g_Config.bAutoRun = false;
				g_Config.bSaveSettings = false;
				break;
			}
		}
	}

	g_Config.Load();

	LogManager::Init();
	LogManager::GetInstance()->GetConsoleListener()->Open(hideLog, 150, 120, "PPSSPP Debug Console");
	LogManager::GetInstance()->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);

	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(""));

	//Windows, API init stuff
	INITCOMMONCONTROLSEX comm;
	comm.dwSize = sizeof(comm);
	comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
	InitCommonControlsEx(&comm);
	timeBeginPeriod(1);
	MainWindow::Init(_hInstance);

	g_hPopupMenus = LoadMenu(_hInstance, (LPCSTR)IDR_POPUPMENUS);

	MainWindow::Show(_hInstance, iCmdShow);

	HWND hwndMain = MainWindow::GetHWND();
	HWND hwndDisplay = MainWindow::GetDisplayHWND();
	
	//initialize custom controls
	CtrlDisAsmView::init();
	CtrlMemView::init();
	CtrlRegisterList::init();

	DialogManager::AddDlg(memoryWindow[0] = new CMemoryDlg(_hInstance, hwndMain, currentDebugMIPS));
	DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));

	host = new WindowsHost(hwndMain, hwndDisplay);

	// Emu thread is always running!
	EmuThread_Start();

	HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);

	//so.. we're at the message pump of the GUI thread
	for (MSG msg; GetMessage(&msg, NULL, 0, 0); )	// for no quit
	{
		//DSound_UpdateSound();

		if (msg.message == WM_KEYDOWN)
		{
			//hack to enable/disable menu command accelerate keys
			MainWindow::UpdateCommands();

			//hack to make it possible to get to main window from floating windows with Esc
			if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE)
				BringWindowToTop(hwndMain);
		}

		//Translate accelerators and dialog messages...
		if (!TranslateAccelerator(hwndMain, hAccelTable, &msg))
		{
			if (!DialogManager::IsDialogMessage(&msg))
			{
				//and finally translate and dispatch
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}

	VFSShutdown();

	LogManager::Shutdown();
	DialogManager::DestroyAll();
	timeEndPeriod(1);
	g_Config.Save();
	delete host;
	return 0;
}
예제 #20
0
파일: main.cpp 프로젝트: sigh0829/ppsspp
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
    Common::EnableCrashingOnCrashes();

    wchar_t modulePath[MAX_PATH];
    GetModuleFileName(NULL, modulePath, MAX_PATH);
    for (size_t i = wcslen(modulePath) - 1; i > 0; i--) {
        if (modulePath[i] == '\\') {
            modulePath[i] = 0;
            break;
        }
    }
    SetCurrentDirectory(modulePath);
    // GetCurrentDirectory(MAX_PATH, modulePath);  // for checking in the debugger
#ifndef _DEBUG
    bool hideLog = true;
#else
    bool hideLog = false;
#endif

    VFSRegister("", new DirectoryAssetReader("assets/"));
    VFSRegister("", new DirectoryAssetReader(""));

    wchar_t lcCountry[256];

    // LOCALE_SNAME is only available in WinVista+
    // Really should find a way to do this in XP too :/
    if (0 != GetLocaleInfo(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256)) {
        langRegion = ConvertWStringToUTF8(lcCountry);
        for (size_t i = 0; i < langRegion.size(); i++) {
            if (langRegion[i] == '-')
                langRegion[i] = '_';
        }
    } else {
        langRegion = "en_US";
    }

    osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture();

    std::string configFilename;
    const char *configOption = "--config=";

    std::string controlsConfigFilename;
    const char *controlsOption = "--controlconfig=";

    for (int i = 1; i < __argc; ++i)
    {
        if (__argv[i][0] == '\0')
            continue;
        if (__argv[i][0] == '-')
        {
            if (!strncmp(__argv[i], configOption, strlen(configOption)) && strlen(__argv[i]) > strlen(configOption)) {
                configFilename = __argv[i] + strlen(configOption);
            }
            if (!strncmp(__argv[i], controlsOption, strlen(controlsOption)) && strlen(__argv[i]) > strlen(controlsOption)) {
                controlsConfigFilename = __argv[i] + strlen(controlsOption);
            }
        }
    }

    if(configFilename.empty())
        configFilename = "ppsspp.ini";

    if(controlsConfigFilename.empty())
        controlsConfigFilename = "controls.ini";

    // Load config up here, because those changes below would be overwritten
    // if it's not loaded here first.
    g_Config.Load(configFilename.c_str(), controlsConfigFilename.c_str());

    // The rest is handled in NativeInit().
    for (int i = 1; i < __argc; ++i)
    {
        if (__argv[i][0] == '\0')
            continue;

        if (__argv[i][0] == '-')
        {
            switch (__argv[i][1])
            {
            case 'l':
                hideLog = false;
                break;
            case 's':
                g_Config.bAutoRun = false;
                g_Config.bSaveSettings = false;
                break;
            }

            if (!strncmp(__argv[i], "--fullscreen", strlen("--fullscreen")))
                g_Config.bFullScreen = true;

            if (!strncmp(__argv[i], "--windowed", strlen("--windowed")))
                g_Config.bFullScreen = false;
        }
    }

    LogManager::Init();
    LogManager::GetInstance()->GetConsoleListener()->Open(hideLog, 150, 120, "PPSSPP Debug Console");


    //Windows, API init stuff
    INITCOMMONCONTROLSEX comm;
    comm.dwSize = sizeof(comm);
    comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
    InitCommonControlsEx(&comm);
    timeBeginPeriod(1);
    MainWindow::Init(_hInstance);

    g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS);

    MainWindow::Show(_hInstance, iCmdShow);

    HWND hwndMain = MainWindow::GetHWND();
    HWND hwndDisplay = MainWindow::GetDisplayHWND();

    //initialize custom controls
    CtrlDisAsmView::init();
    CtrlMemView::init();
    CtrlRegisterList::init();
    CGEDebugger::Init();

    DialogManager::AddDlg(memoryWindow[0] = new CMemoryDlg(_hInstance, hwndMain, currentDebugMIPS));
    DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));

    host = new WindowsHost(hwndMain, hwndDisplay);
    host->SetWindowTitle(0);

    MainWindow::CreateDebugWindows();

    // Emu thread is always running!
    EmuThread_Start();

    HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
    HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS);

    //so.. we're at the message pump of the GUI thread
    for (MSG msg; GetMessage(&msg, NULL, 0, 0); )	// for no quit
    {
        //DSound_UpdateSound();

        if (msg.message == WM_KEYDOWN)
        {
            //hack to enable/disable menu command accelerate keys
            MainWindow::UpdateCommands();

            //hack to make it possible to get to main window from floating windows with Esc
            if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE)
                BringWindowToTop(hwndMain);
        }

        //Translate accelerators and dialog messages...
        HWND wnd;
        HACCEL accel;
        switch (g_activeWindow)
        {
        case WINDOW_MAINWINDOW:
            wnd = hwndMain;
            accel = hAccelTable;
            break;
        case WINDOW_CPUDEBUGGER:
            wnd = disasmWindow[0]->GetDlgHandle();
            accel = hDebugAccelTable;
            break;
        case WINDOW_GEDEBUGGER:
        default:
            wnd = 0;
            accel = 0;
            break;
        }

        if (!TranslateAccelerator(wnd, accel, &msg))
        {
            if (!DialogManager::IsDialogMessage(&msg))
            {
                //and finally translate and dispatch
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }

    VFSShutdown();

    EmuThread_Stop();

    DialogManager::DestroyAll();
    timeEndPeriod(1);
    delete host;
    g_Config.Save();
    LogManager::Shutdown();
    return 0;
}
예제 #21
0
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
	setCurrentThreadName("Main");

	// Windows Vista and above: alert Windows that PPSSPP is DPI aware,
	// so that we don't flicker in fullscreen on some PCs.
	MakePPSSPPDPIAware();

	// FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it.
#ifdef _M_X64
	_set_FMA3_enable(0);
#endif

	EnableCrashingOnCrashes();

	wchar_t modulePath[MAX_PATH];
	GetModuleFileName(NULL, modulePath, MAX_PATH);
	for (size_t i = wcslen(modulePath) - 1; i > 0; i--) {
		if (modulePath[i] == '\\') {
			modulePath[i] = 0;
			break;
		}
	}
	SetCurrentDirectory(modulePath);
	// GetCurrentDirectory(MAX_PATH, modulePath);  // for checking in the debugger

#ifndef _DEBUG
	bool showLog = false;
#else
	bool showLog = false;
#endif

	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(""));

	wchar_t lcCountry[256];

	// LOCALE_SNAME is only available in WinVista+
	// Really should find a way to do this in XP too :/
	if (0 != GetLocaleInfo(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256)) {
		langRegion = ConvertWStringToUTF8(lcCountry);
		for (size_t i = 0; i < langRegion.size(); i++) {
			if (langRegion[i] == '-')
				langRegion[i] = '_';
		}
	} else {
		langRegion = "en_US";
	}

	osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture();

	const char *configFilename = NULL;
	const char *configOption = "--config=";

	const char *controlsConfigFilename = NULL;
	const char *controlsOption = "--controlconfig=";

	for (int i = 1; i < __argc; ++i)
	{
		if (__argv[i][0] == '\0')
			continue;
		if (__argv[i][0] == '-')
		{
			if (!strncmp(__argv[i], configOption, strlen(configOption)) && strlen(__argv[i]) > strlen(configOption)) {
				configFilename = __argv[i] + strlen(configOption);
			}
			if (!strncmp(__argv[i], controlsOption, strlen(controlsOption)) && strlen(__argv[i]) > strlen(controlsOption)) {
				controlsConfigFilename = __argv[i] + strlen(controlsOption);
			}
		}
	}

	// On Win32 it makes more sense to initialize the system directories here 
	// because the next place it was called was in the EmuThread, and it's too late by then.
	InitSysDirectories();

	// Load config up here, because those changes below would be overwritten
	// if it's not loaded here first.
	g_Config.AddSearchPath("");
	g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
	g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM));
	g_Config.Load(configFilename, controlsConfigFilename);

	bool debugLogLevel = false;

	// The rest is handled in NativeInit().
	for (int i = 1; i < __argc; ++i)
	{
		if (__argv[i][0] == '\0')
			continue;

		if (__argv[i][0] == '-')
		{
			switch (__argv[i][1])
			{
			case 'l':
				showLog = true;
				g_Config.bEnableLogging = true;
				break;
			case 's':
				g_Config.bAutoRun = false;
				g_Config.bSaveSettings = false;
				break;
			case 'd':
				debugLogLevel = true;
				break;
			}

			if (!strncmp(__argv[i], "--fullscreen", strlen("--fullscreen")))
				g_Config.bFullScreen = true;

			if (!strncmp(__argv[i], "--windowed", strlen("--windowed")))
				g_Config.bFullScreen = false;
		}
	}
#ifdef _DEBUG
	g_Config.bEnableLogging = true;
#endif

	LogManager::Init();
	// Consider at least the following cases before changing this code:
	//   - By default in Release, the console should be hidden by default even if logging is enabled.
	//   - By default in Debug, the console should be shown by default.
	//   - The -l switch is expected to show the log console, REGARDLESS of config settings.
	//   - It should be possible to log to a file without showing the console.
	LogManager::GetInstance()->GetConsoleListener()->Init(showLog, 150, 120, "PPSSPP Debug Console");
	
	if (debugLogLevel)
		LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG);

	//Windows, API init stuff
	INITCOMMONCONTROLSEX comm;
	comm.dwSize = sizeof(comm);
	comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
	InitCommonControlsEx(&comm);
	timeBeginPeriod(1);
	MainWindow::Init(_hInstance);

	g_hPopupMenus = LoadMenu(_hInstance, (LPCWSTR)IDR_POPUPMENUS);

	MainWindow::Show(_hInstance, iCmdShow);

	HWND hwndMain = MainWindow::GetHWND();
	HWND hwndDisplay = MainWindow::GetDisplayHWND();
	
	//initialize custom controls
	CtrlDisAsmView::init();
	CtrlMemView::init();
	CtrlRegisterList::init();
	CGEDebugger::Init();

	DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));

	host = new WindowsHost(hwndMain, hwndDisplay);
	host->SetWindowTitle(0);

	MainWindow::CreateDebugWindows();

	// Emu thread is always running!
	EmuThread_Start();
	InputDevice::BeginPolling();

	HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
	HACCEL hDebugAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_DEBUGACCELS);

	//so.. we're at the message pump of the GUI thread
	for (MSG msg; GetMessage(&msg, NULL, 0, 0); )	// for no quit
	{
		if (msg.message == WM_KEYDOWN)
		{
			//hack to enable/disable menu command accelerate keys
			MainWindow::UpdateCommands();

			//hack to make it possible to get to main window from floating windows with Esc
			if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE)
				BringWindowToTop(hwndMain);
		}

		//Translate accelerators and dialog messages...
		HWND wnd;
		HACCEL accel;
		switch (g_activeWindow)
		{
		case WINDOW_MAINWINDOW:
			wnd = hwndMain;
			accel = hAccelTable;
			break;
		case WINDOW_CPUDEBUGGER:
			wnd = disasmWindow[0] ? disasmWindow[0]->GetDlgHandle() : 0;
			accel = hDebugAccelTable;
			break;
		case WINDOW_GEDEBUGGER:
		default:
			wnd = 0;
			accel = 0;
			break;
		}

		if (!TranslateAccelerator(wnd, accel, &msg))
		{
			if (!DialogManager::IsDialogMessage(&msg))
			{
				//and finally translate and dispatch
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}

	VFSShutdown();

	InputDevice::StopPolling();
	EmuThread_Stop();

	MainWindow::DestroyDebugWindows();
	DialogManager::DestroyAll();
	timeEndPeriod(1);
	delete host;
	g_Config.Save();
	LogManager::Shutdown();
	return 0;
}
예제 #22
0
void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID)
{
	EnableFZ();
	std::string user_data_path = savegame_directory;

	// We want this to be FIRST.
#ifdef BLACKBERRY
	// Packed assets are included in app/native/ dir
	VFSRegister("", new DirectoryAssetReader("app/native/assets/"));
#else
	VFSRegister("", new DirectoryAssetReader("assets/"));
#endif
	VFSRegister("", new DirectoryAssetReader(user_data_path.c_str()));

	host = new NativeHost();

	logger = new AndroidLogger();

	LogManager::Init();
	LogManager *logman = LogManager::GetInstance();
	ILOG("Logman: %p", logman);

	config_filename = user_data_path + "ppsspp.ini";

	g_Config.Load(config_filename.c_str());

	const char *fileToLog = 0;

	bool gfxLog = false;
	// Parse command line
	LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'd':
				// Enable debug logging
				logLevel = LogTypes::LDEBUG;
				break;
			case 'g':
				gfxLog = true;
				break;
			case 'j':
				g_Config.iCpuCore = CPU_JIT;
				g_Config.bSaveSettings = false;
				break;
			case 'f':
				g_Config.iCpuCore = CPU_FASTINTERPRETER;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.iCpuCore = CPU_INTERPRETER;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
					fileToLog = argv[i] + strlen("--log=");
				break;
			}
		} else {
			if (boot_filename.empty()) {
				boot_filename = argv[i];
				if (!File::Exists(boot_filename))
				{
					fprintf(stderr, "File not found: %s\n", boot_filename.c_str());
					exit(1);
				}
			} else {
				fprintf(stderr, "Can only boot one file");
				exit(1);
			}
		}
	}

	if (fileToLog != NULL)
		LogManager::GetInstance()->ChangeFileLog(fileToLog);

	if (g_Config.currentDirectory == "") {
#if defined(ANDROID) || defined(BLACKBERRY) || defined(__SYMBIAN32__)
		g_Config.currentDirectory = external_directory;
#else
		g_Config.currentDirectory = getenv("HOME");
#endif
	}

#if defined(ANDROID)
	// Maybe there should be an option to use internal memory instead, but I think
	// that for most people, using external memory (SDCard/USB Storage) makes the
	// most sense.
	g_Config.memCardDirectory = std::string(external_directory) + "/";
	g_Config.flashDirectory = std::string(external_directory)+"/flash/";
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__)
	g_Config.memCardDirectory = user_data_path;
	g_Config.flashDirectory = user_data_path+"/flash/";
#else
	g_Config.memCardDirectory = std::string(getenv("HOME"))+"/.ppsspp/";
	g_Config.flashDirectory = g_Config.memCardDirectory+"/flash/";
#endif

	for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
	{
		LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
		logman->SetEnable(type, true);
		logman->SetLogLevel(type, gfxLog && i == LogTypes::G3D ? LogTypes::LDEBUG : logLevel);
#ifdef ANDROID
		logman->AddListener(type, logger);
#endif
	}
	// Special hack for G3D as it's very spammy. Need to make a flag for this.
	if (!gfxLog)
		logman->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
	INFO_LOG(BOOT, "Logger inited.");
}
예제 #23
0
파일: NativeApp.cpp 프로젝트: Dzakus/ppsspp
void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID)
{
	EnableFZ();
	setlocale( LC_ALL, "C" );
	std::string user_data_path = savegame_directory;
	isMessagePending = false;
	// We want this to be FIRST.
#ifndef USING_QT_UI
#ifdef BLACKBERRY
	// Packed assets are included in app/native/ dir
	VFSRegister("", new DirectoryAssetReader("app/native/assets/"));
#elif defined(IOS)
	VFSRegister("", new DirectoryAssetReader(external_directory));
	user_data_path += "/";
#elif defined(__APPLE__)
    char program_path[4090];
    uint32_t program_path_size = sizeof(program_path);
    _NSGetExecutablePath(program_path,&program_path_size);
    *(strrchr(program_path, '/')+1) = '\0';
    char assets_path[4096];
    sprintf(assets_path,"%sassets/",program_path);
    VFSRegister("", new DirectoryAssetReader(assets_path));
    VFSRegister("", new DirectoryAssetReader("assets/"));
#else
	VFSRegister("", new DirectoryAssetReader("assets/"));
#endif
#endif
	VFSRegister("", new DirectoryAssetReader(user_data_path.c_str()));

	host = new NativeHost();

#ifndef _WIN32
	logger = new AndroidLogger();

	LogManager::Init();
	LogManager *logman = LogManager::GetInstance();
	ILOG("Logman: %p", logman);

	config_filename = user_data_path + "/ppsspp.ini";
	g_Config.Load(config_filename.c_str());
#endif

	const char *fileToLog = 0;
	const char *stateToLoad = 0;

	bool gfxLog = false;
	// Parse command line
	LogTypes::LOG_LEVELS logLevel = LogTypes::LINFO;
	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'd':
				// Enable debug logging
				// Note that you must also change the max log level in Log.h.
				logLevel = LogTypes::LDEBUG;
				break;
			case 'g':
				gfxLog = true;
				break;
			case 'j':
				g_Config.bJit = true;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.bJit = false;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
					fileToLog = argv[i] + strlen("--log=");
				if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
					stateToLoad = argv[i] + strlen("--state=");
				break;
			}
		} else {
			if (boot_filename.empty()) {
				boot_filename = argv[i];
				if (!File::Exists(boot_filename))
				{
					fprintf(stderr, "File not found: %s\n", boot_filename.c_str());
					exit(1);
				}
			} else {
				fprintf(stderr, "Can only boot one file");
				exit(1);
			}
		}
	}

	if (fileToLog != NULL)
		LogManager::GetInstance()->ChangeFileLog(fileToLog);

#ifndef _WIN32
	if (g_Config.currentDirectory == "") {
#if defined(ANDROID)
		g_Config.currentDirectory = external_directory;
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(IOS) || defined(_WIN32)
		g_Config.currentDirectory = savegame_directory;
#else
		g_Config.currentDirectory = getenv("HOME");
#endif
	}

#if defined(ANDROID)
	g_Config.internalDataDirectory = savegame_directory;
	// Maybe there should be an option to use internal memory instead, but I think
	// that for most people, using external memory (SDCard/USB Storage) makes the
	// most sense.
	g_Config.memCardDirectory = std::string(external_directory) + "/";
	g_Config.flashDirectory = std::string(external_directory)+"/flash/";
#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) || defined(MEEGO_EDITION_HARMATTAN) || defined(IOS) || defined(_WIN32)
	g_Config.memCardDirectory = user_data_path;
#ifdef BLACKBERRY
	g_Config.flashDirectory = "app/native/assets/flash/";
#elif defined(IOS)
	g_Config.flashDirectory = std::string(external_directory) + "flash0/";
#elif defined(MEEGO_EDITION_HARMATTAN)
	g_Config.flashDirectory = "/opt/PPSSPP/flash/";
#else
	g_Config.flashDirectory = user_data_path+"/flash/";
#endif
#else
	g_Config.memCardDirectory = std::string(getenv("HOME"))+"/.ppsspp/";
	g_Config.flashDirectory = g_Config.memCardDirectory+"/flash/";
#endif

	for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
	{
		LogTypes::LOG_TYPE type = (LogTypes::LOG_TYPE)i;
		logman->SetEnable(type, true);
		logman->SetLogLevel(type, gfxLog && i == LogTypes::G3D ? LogTypes::LDEBUG : logLevel);
#ifdef ANDROID
		logman->AddListener(type, logger);
#endif
	}
#ifdef __SYMBIAN32__
	g_Config.bHardwareTransform = true;
	g_Config.bUseVBO = false;
#endif
	// Special hack for G3D as it's very spammy. Need to make a flag for this.
	if (!gfxLog)
		logman->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
	INFO_LOG(BOOT, "Logger inited.");
#endif	

	i18nrepo.LoadIni(g_Config.languageIni);

	if (!boot_filename.empty() && stateToLoad != NULL)
		SaveState::Load(stateToLoad);
	
	g_gameInfoCache.Init();
}
예제 #24
0
파일: main.cpp 프로젝트: morristech/ppsspp
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
	Common::EnableCrashingOnCrashes();

	const char *fileToStart = NULL;
	const char *fileToLog = NULL;
	const char *stateToLoad = NULL;
	bool hideLog = true;

#ifdef _DEBUG
	hideLog = false;
#endif

	g_Config.Load();
	VFSRegister("", new DirectoryAssetReader("assets/"));
	VFSRegister("", new DirectoryAssetReader(""));

	for (int i = 1; i < __argc; ++i)
	{
		if (__argv[i][0] == '\0')
			continue;

		if (__argv[i][0] == '-')
		{
			switch (__argv[i][1])
			{
			case 'j':
				g_Config.bJit = true;
				g_Config.bSaveSettings = false;
				break;
			case 'i':
				g_Config.bJit = false;
				g_Config.bSaveSettings = false;
				break;
			case 'l':
				hideLog = false;
				break;
			case 's':
				g_Config.bAutoRun = false;
				g_Config.bSaveSettings = false;
				break;
			case '-':
				if (!strcmp(__argv[i], "--log") && i < __argc - 1)
					fileToLog = __argv[++i];
				if (!strncmp(__argv[i], "--log=", strlen("--log=")) && strlen(__argv[i]) > strlen("--log="))
					fileToLog = __argv[i] + strlen("--log=");
				if (!strcmp(__argv[i], "--state") && i < __argc - 1)
					stateToLoad = __argv[++i];
				if (!strncmp(__argv[i], "--state=", strlen("--state=")) && strlen(__argv[i]) > strlen("--state="))
					stateToLoad = __argv[i] + strlen("--state=");
				break;
			}
		}
		else if (fileToStart == NULL)
		{
			fileToStart = __argv[i];
			if (!File::Exists(fileToStart))
			{
				fprintf(stderr, "File not found: %s\n", fileToStart);
				exit(1);
			}
		}
		else
		{
			fprintf(stderr, "Can only boot one file");
			exit(1);
		}
	}

	//Windows, API init stuff
	INITCOMMONCONTROLSEX comm;
	comm.dwSize = sizeof(comm);
	comm.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES;
	InitCommonControlsEx(&comm);
	timeBeginPeriod(1);
	MainWindow::Init(_hInstance);

	HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
	g_hPopupMenus = LoadMenu(_hInstance, (LPCSTR)IDR_POPUPMENUS);

	MainWindow::Show(_hInstance, iCmdShow);
	host = new WindowsHost(MainWindow::GetHWND(), MainWindow::GetDisplayHWND());

	HWND hwndMain = MainWindow::GetHWND();
	HMENU menu = GetMenu(hwndMain);

	//initialize custom controls
	CtrlDisAsmView::init();
	CtrlMemView::init();
	CtrlRegisterList::init();

	DialogManager::AddDlg(memoryWindow[0] = new CMemoryDlg(_hInstance, hwndMain, currentDebugMIPS));
	DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));

	MainWindow::Update();
	MainWindow::UpdateMenus();

	LogManager::Init();
	if (fileToLog != NULL)
		LogManager::GetInstance()->ChangeFileLog(fileToLog);
	LogManager::GetInstance()->GetConsoleListener()->Open(hideLog, 150, 120, "PPSSPP Debug Console");
	LogManager::GetInstance()->SetLogLevel(LogTypes::G3D, LogTypes::LERROR);
	if (fileToStart != NULL)
	{
		MainWindow::SetPlaying(fileToStart);
		MainWindow::Update();
		MainWindow::UpdateMenus();
	}

	// Emu thread is always running!
	EmuThread_Start();

	if (g_Config.bBrowse)
		MainWindow::BrowseAndBoot("");

	if (!hideLog)
		SetForegroundWindow(hwndMain);

	if (fileToStart != NULL && stateToLoad != NULL)
		SaveState::Load(stateToLoad);

	//so.. we're at the message pump of the GUI thread
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))	//while no quit
	{
		//DSound_UpdateSound();

		//hack to make it possible to get to main window from floating windows with Esc
		if (msg.hwnd != hwndMain && msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE)
			BringWindowToTop(hwndMain);

		//Translate accelerators and dialog messages...
		if (!TranslateAccelerator(hwndMain, hAccelTable, &msg))
		{
			if (!DialogManager::IsDialogMessage(&msg))
			{
				//and finally translate and dispatch
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
	}

	VFSShutdown();

	LogManager::Shutdown();
	DialogManager::DestroyAll();
	timeEndPeriod(1);
	g_Config.Save();
	delete host;
	return 0;
}