mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2024-06-15 10:47:31 -04:00
Switch from GTK to FLTK
This commit is contained in:
parent
273bd14243
commit
80ec3ea21f
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -25,8 +25,6 @@ configure
|
|||
depcomp
|
||||
install-sh
|
||||
missing
|
||||
source/common/.deps/
|
||||
source/common/.dirstamp
|
||||
source/core/.deps/
|
||||
source/core/.dirstamp
|
||||
source/core/api/.deps/
|
||||
|
@ -37,10 +35,5 @@ source/core/input/.deps/
|
|||
source/core/input/.dirstamp
|
||||
source/core/vssystem/.deps/
|
||||
source/core/vssystem/.dirstamp
|
||||
source/gtkui/.deps/
|
||||
source/sdl/.deps/
|
||||
source/sdl/.dirstamp
|
||||
source/unix/.deps/
|
||||
source/unix/.dirstamp
|
||||
source/unix/gtkui/.deps/
|
||||
source/unix/gtkui/.dirstamp
|
||||
source/fltkui/.deps/
|
||||
source/fltkui/.dirstamp
|
||||
|
|
78
Makefile.am
78
Makefile.am
|
@ -7,23 +7,19 @@ EXTRA_DIST = doc
|
|||
|
||||
nestopia_CPPFLAGS = \
|
||||
-I$(top_srcdir)/source \
|
||||
-I$(top_srcdir)/source/common \
|
||||
-I$(top_srcdir)/source/gtkui \
|
||||
-I$(top_srcdir)/source/sdl \
|
||||
-I$(top_srcdir)/source/fltkui \
|
||||
-DDATADIR=\"$(datadir)/nestopia\" \
|
||||
-DDATAROOTDIR=\"$(datarootdir)\" \
|
||||
-DNST_PRAGMA_ONCE \
|
||||
$(ZLIB_CFLAGS) \
|
||||
$(LIBARCHIVE_CFLAGS) \
|
||||
$(SDL2_CFLAGS) \
|
||||
$(LIBEPOXY_CFLAGS) \
|
||||
$(GTK3_CFLAGS)
|
||||
$(FLTK_CFLAGS)
|
||||
nestopia_LDADD = \
|
||||
$(ZLIB_LIBS) \
|
||||
$(LIBARCHIVE_LIBS) \
|
||||
$(SDL2_LIBS) \
|
||||
$(LIBEPOXY_LIBS) \
|
||||
$(GTK3_LIBS)
|
||||
$(FLTK_LIBS)
|
||||
|
||||
################
|
||||
# Installation #
|
||||
|
@ -695,47 +691,37 @@ nestopia_SOURCES = \
|
|||
source/nes_ntsc/demo_impl.h
|
||||
|
||||
nestopia_SOURCES += \
|
||||
source/common/nstcommon.cpp \
|
||||
source/common/nstcommon.h \
|
||||
source/common/cheats.cpp \
|
||||
source/common/cheats.h \
|
||||
source/common/homebrew.cpp \
|
||||
source/common/homebrew.h \
|
||||
source/common/cli.cpp \
|
||||
source/common/cli.h \
|
||||
source/common/config.cpp \
|
||||
source/common/config.h \
|
||||
source/common/video.cpp \
|
||||
source/common/video.h \
|
||||
source/common/input.cpp \
|
||||
source/common/input.h \
|
||||
source/common/samples.cpp \
|
||||
source/common/samples.h \
|
||||
source/common/font.h \
|
||||
source/common/ini.cpp \
|
||||
source/common/ini.h \
|
||||
source/common/png.cpp \
|
||||
source/common/png.h \
|
||||
source/common/audio.cpp \
|
||||
source/common/audio.h \
|
||||
source/common/sdlinput.cpp \
|
||||
source/common/sdlinput.h
|
||||
source/fltkui/nstcommon.cpp \
|
||||
source/fltkui/nstcommon.h \
|
||||
source/fltkui/cheats.cpp \
|
||||
source/fltkui/cheats.h \
|
||||
source/fltkui/homebrew.cpp \
|
||||
source/fltkui/homebrew.h \
|
||||
source/fltkui/cli.cpp \
|
||||
source/fltkui/cli.h \
|
||||
source/fltkui/config.cpp \
|
||||
source/fltkui/config.h \
|
||||
source/fltkui/video.cpp \
|
||||
source/fltkui/video.h \
|
||||
source/fltkui/input.cpp \
|
||||
source/fltkui/input.h \
|
||||
source/fltkui/samples.cpp \
|
||||
source/fltkui/samples.h \
|
||||
source/fltkui/font.h \
|
||||
source/fltkui/ini.cpp \
|
||||
source/fltkui/ini.h \
|
||||
source/fltkui/png.cpp \
|
||||
source/fltkui/png.h \
|
||||
source/fltkui/audio.cpp \
|
||||
source/fltkui/audio.h
|
||||
|
||||
nestopia_SOURCES += \
|
||||
source/gtkui/gtkui_config.h \
|
||||
source/gtkui/gtkui_archive.h \
|
||||
source/gtkui/gtkui_cheats.cpp \
|
||||
source/gtkui/gtkui_callbacks.h \
|
||||
source/gtkui/gtkui_callbacks.cpp \
|
||||
source/gtkui/gtkui_dialogs.cpp \
|
||||
source/gtkui/gtkui_cheats.h \
|
||||
source/gtkui/gtkui_dialogs.h \
|
||||
source/gtkui/gtkui_archive.cpp \
|
||||
source/gtkui/gtkui.cpp \
|
||||
source/gtkui/gtkui.h \
|
||||
source/gtkui/gtkui_input.cpp \
|
||||
source/gtkui/gtkui_input.h \
|
||||
source/gtkui/gtkui_config.cpp
|
||||
source/fltkui/fltkui_config.h \
|
||||
source/fltkui/fltkui_archive.h \
|
||||
source/fltkui/fltkui_archive.cpp \
|
||||
source/fltkui/fltkui.cpp \
|
||||
source/fltkui/fltkui.h \
|
||||
source/fltkui/fltkui_config.cpp
|
||||
|
||||
# install full HTML suite
|
||||
if ENABLE_FULL_HTML
|
||||
|
|
10
configure.ac
10
configure.ac
|
@ -2,7 +2,7 @@ dnl Initialise Autoconf
|
|||
AC_PREREQ([2.69])
|
||||
AC_INIT(
|
||||
[nestopia],
|
||||
[1.50])
|
||||
[1.51.0])
|
||||
AC_CONFIG_SRCDIR([source])
|
||||
AC_LANG([C++])
|
||||
|
||||
|
@ -76,11 +76,11 @@ PKG_CHECK_MODULES([LIBARCHIVE], [libarchive])
|
|||
dnl SDL2
|
||||
PKG_CHECK_MODULES([SDL2], [sdl2])
|
||||
|
||||
dnl LibEpoxy
|
||||
PKG_CHECK_MODULES([LIBEPOXY], [epoxy])
|
||||
AC_CHECK_PROG(FLTKCONFIG,fltk-config,[fltk-config],[no])
|
||||
test "$FLTKCONFIG" == "no" && AC_MSG_ERROR([Cannot find the fltk-config executable. Is FLTK installed?])
|
||||
|
||||
dnl GTK3
|
||||
PKG_CHECK_MODULES([GTK3], [gtk+-3.0])
|
||||
AC_SUBST(FLTK_CFLAGS,"$(fltk-config --use-gl --use-images --cxxflags)")
|
||||
AC_SUBST(FLTK_LIBS,"-lGL $(fltk-config --use-gl --use-images --ldflags)")
|
||||
|
||||
dnl full HTML suite
|
||||
AC_ARG_ENABLE([doc],
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2016 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
#include "video.h"
|
||||
|
||||
static turbo_t turbostate;
|
||||
static turbo_t turbotoggle;
|
||||
|
||||
extern Emulator emulator;
|
||||
|
||||
void nst_input_init() {
|
||||
// Initialize input
|
||||
char controller[32];
|
||||
|
||||
for (int i = 0; i < NUMGAMEPADS; i++) {
|
||||
Input(emulator).AutoSelectController(i);
|
||||
|
||||
switch(Input(emulator).GetConnectedController(i)) {
|
||||
case Input::UNCONNECTED:
|
||||
snprintf(controller, sizeof(controller), "%s", "Unconnected");
|
||||
break;
|
||||
case Input::PAD1:
|
||||
case Input::PAD2:
|
||||
case Input::PAD3:
|
||||
case Input::PAD4:
|
||||
snprintf(controller, sizeof(controller), "%s", "Standard Pad");
|
||||
break;
|
||||
case Input::ZAPPER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Zapper");
|
||||
break;
|
||||
case Input::PADDLE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Arkanoid Paddle");
|
||||
break;
|
||||
case Input::POWERPAD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Power Pad");
|
||||
break;
|
||||
case Input::POWERGLOVE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Power Glove");
|
||||
break;
|
||||
case Input::MOUSE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Mouse");
|
||||
break;
|
||||
case Input::ROB:
|
||||
snprintf(controller, sizeof(controller), "%s", "R.O.B.");
|
||||
break;
|
||||
case Input::FAMILYTRAINER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Family Trainer");
|
||||
break;
|
||||
case Input::FAMILYKEYBOARD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Family Keyboard");
|
||||
break;
|
||||
case Input::SUBORKEYBOARD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Subor Keyboard");
|
||||
break;
|
||||
case Input::DOREMIKKOKEYBOARD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Doremikko Keyboard");
|
||||
break;
|
||||
case Input::HORITRACK:
|
||||
snprintf(controller, sizeof(controller), "%s", "Hori Track");
|
||||
break;
|
||||
case Input::PACHINKO:
|
||||
snprintf(controller, sizeof(controller), "%s", "Pachinko");
|
||||
break;
|
||||
case Input::OEKAKIDSTABLET:
|
||||
snprintf(controller, sizeof(controller), "%s", "Oeka Kids Tablet");
|
||||
break;
|
||||
case Input::KONAMIHYPERSHOT:
|
||||
snprintf(controller, sizeof(controller), "%s", "Konami Hypershot");
|
||||
break;
|
||||
case Input::BANDAIHYPERSHOT:
|
||||
snprintf(controller, sizeof(controller), "%s", "Bandai Hypershot");
|
||||
break;
|
||||
case Input::CRAZYCLIMBER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Crazy Climber");
|
||||
break;
|
||||
case Input::MAHJONG:
|
||||
snprintf(controller, sizeof(controller), "%s", "Mahjong");
|
||||
break;
|
||||
case Input::EXCITINGBOXING:
|
||||
snprintf(controller, sizeof(controller), "%s", "Exciting Boxing");
|
||||
break;
|
||||
case Input::TOPRIDER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Top Rider");
|
||||
break;
|
||||
case Input::POKKUNMOGURAA:
|
||||
snprintf(controller, sizeof(controller), "%s", "Pokkun Moguraa");
|
||||
break;
|
||||
case Input::PARTYTAP:
|
||||
snprintf(controller, sizeof(controller), "%s", "PartyTap");
|
||||
break;
|
||||
case Input::TURBOFILE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Turbo File");
|
||||
break;
|
||||
case Input::BARCODEWORLD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Barcode World");
|
||||
break;
|
||||
default:
|
||||
snprintf(controller, sizeof(controller), "%s", "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Port %d: %s\n", i + 1, controller);
|
||||
}
|
||||
}
|
||||
|
||||
void nst_input_inject(Input::Controllers *controllers, nesinput_t input) {
|
||||
// Insert the input signal into the NES
|
||||
if(controllers == NULL) { return; }
|
||||
|
||||
if (input.pressed) {
|
||||
controllers->pad[input.player].buttons |= input.nescode;
|
||||
|
||||
if (input.turboa) { input.player == 0 ? turbostate.p1a = true : turbostate.p2a = true; }
|
||||
if (input.turbob) { input.player == 0 ? turbostate.p1b = true : turbostate.p2b = true; }
|
||||
}
|
||||
else {
|
||||
controllers->pad[input.player].buttons &= ~input.nescode;
|
||||
|
||||
if (input.turboa) { input.player == 0 ? turbostate.p1a = false : turbostate.p2a = false; }
|
||||
if (input.turbob) { input.player == 0 ? turbostate.p1b = false : turbostate.p2b = false; }
|
||||
}
|
||||
}
|
||||
|
||||
void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y) {
|
||||
// Insert input signal for Zappers
|
||||
if(controllers == NULL) { return; }
|
||||
|
||||
double xaspect;
|
||||
double yaspect;
|
||||
|
||||
if (s) {
|
||||
// Get X coords
|
||||
if (conf.video_filter == 1) { // NTSC
|
||||
xaspect = (double)(Video::Output::WIDTH) / (double)(Video::Output::NTSC_WIDTH / 2);
|
||||
}
|
||||
else if (conf.video_tv_aspect) {
|
||||
xaspect = (double)(Video::Output::WIDTH) / (double)(TV_WIDTH);
|
||||
}
|
||||
else { xaspect = 1.0; }
|
||||
|
||||
dimensions_t rendersize = nst_video_get_dimensions_render();
|
||||
dimensions_t screensize = nst_video_get_dimensions_screen();
|
||||
|
||||
// Calculate fullscreen X coords
|
||||
if (conf.video_fullscreen) {
|
||||
if (conf.video_stretch_aspect) {
|
||||
xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(screensize.w);
|
||||
}
|
||||
else {
|
||||
// Remove the same amount of pixels as the black area to the left of the screen
|
||||
x -= screensize.w / 2.0f - rendersize.w / 2.0f;
|
||||
xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(rendersize.w);
|
||||
}
|
||||
}
|
||||
controllers->zapper.x = (int)(x * xaspect) / conf.video_scale_factor;
|
||||
|
||||
// Get Y coords
|
||||
if (conf.video_unmask_overscan) {
|
||||
controllers->zapper.y = y / conf.video_scale_factor;
|
||||
}
|
||||
else {
|
||||
controllers->zapper.y = (y + OVERSCAN_TOP * conf.video_scale_factor) / conf.video_scale_factor;
|
||||
}
|
||||
|
||||
// Calculate fullscreen Y coords
|
||||
if (conf.video_fullscreen) {
|
||||
yaspect = (double)(conf.video_scale_factor * Video::Output::HEIGHT) / (double)(screensize.h);
|
||||
controllers->zapper.y = (y * yaspect) / conf.video_scale_factor;
|
||||
}
|
||||
|
||||
// Offscreen
|
||||
if (b != 1) { controllers->zapper.x = ~1U; }
|
||||
|
||||
controllers->zapper.fire = true;
|
||||
}
|
||||
else { controllers->zapper.fire = false; }
|
||||
}
|
||||
|
||||
void nst_input_turbo_init() {
|
||||
// Initialize the turbo button states
|
||||
turbostate.p1a = turbotoggle.p1a = 0;
|
||||
turbostate.p1b = turbotoggle.p1b = 0;
|
||||
turbostate.p2a = turbotoggle.p2a = 0;
|
||||
turbostate.p2b = turbotoggle.p2b = 0;
|
||||
}
|
||||
|
||||
void nst_input_turbo_pulse(Input::Controllers *controllers) {
|
||||
// Pulse the turbo buttons if they're pressed
|
||||
if (turbostate.p1a) {
|
||||
turbotoggle.p1a++;
|
||||
if (turbotoggle.p1a >= conf.timing_turbopulse) {
|
||||
turbotoggle.p1a = 0;
|
||||
controllers->pad[0].buttons &= ~Input::Controllers::Pad::A;
|
||||
}
|
||||
else { controllers->pad[0].buttons |= Input::Controllers::Pad::A; }
|
||||
}
|
||||
|
||||
if (turbostate.p1b) {
|
||||
turbotoggle.p1b++;
|
||||
if (turbotoggle.p1b >= conf.timing_turbopulse) {
|
||||
turbotoggle.p1b = 0;
|
||||
controllers->pad[0].buttons &= ~Input::Controllers::Pad::B;
|
||||
}
|
||||
else { controllers->pad[0].buttons |= Input::Controllers::Pad::B; }
|
||||
}
|
||||
|
||||
if (turbostate.p2a) {
|
||||
turbotoggle.p2a++;
|
||||
if (turbotoggle.p2a >= conf.timing_turbopulse) {
|
||||
turbotoggle.p2a = 0;
|
||||
controllers->pad[1].buttons &= ~Input::Controllers::Pad::A;
|
||||
}
|
||||
else { controllers->pad[1].buttons |= Input::Controllers::Pad::A; }
|
||||
}
|
||||
|
||||
if (turbostate.p2b) {
|
||||
turbotoggle.p2b++;
|
||||
if (turbotoggle.p2b >= conf.timing_turbopulse) {
|
||||
turbotoggle.p2b = 0;
|
||||
controllers->pad[1].buttons &= ~Input::Controllers::Pad::B;
|
||||
}
|
||||
else { controllers->pad[1].buttons |= Input::Controllers::Pad::B; }
|
||||
}
|
||||
}
|
||||
|
||||
int nst_input_zapper_present() {
|
||||
// Check if a Zapper is presently connected
|
||||
if (Input(emulator).GetConnectedController(0) == Input::ZAPPER ||
|
||||
Input(emulator).GetConnectedController(1) == Input::ZAPPER) {
|
||||
return 1;
|
||||
}
|
||||
else { return 0; }
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef _INPUT_H_
|
||||
#define _INPUT_H_
|
||||
|
||||
#define NUMGAMEPADS 2
|
||||
#define NUMBUTTONS 10
|
||||
|
||||
#include "core/api/NstApiInput.hpp"
|
||||
|
||||
using namespace Nes::Api;
|
||||
|
||||
typedef struct {
|
||||
unsigned char player;
|
||||
unsigned char nescode;
|
||||
unsigned char pressed;
|
||||
unsigned char turboa;
|
||||
unsigned char turbob;
|
||||
} nesinput_t;
|
||||
|
||||
typedef struct {
|
||||
int p1a;
|
||||
int p1b;
|
||||
int p2a;
|
||||
int p2b;
|
||||
} turbo_t;
|
||||
|
||||
void nst_input_init();
|
||||
|
||||
void nst_input_inject(Input::Controllers *controllers, nesinput_t input);
|
||||
void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y);
|
||||
|
||||
void nst_input_turbo_init();
|
||||
void nst_input_turbo_pulse(Input::Controllers *controllers);
|
||||
|
||||
int nst_input_zapper_present();
|
||||
|
||||
int input_configure_item(int pnum, int bnum, int type);
|
||||
#endif
|
|
@ -1,23 +1,23 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2012-2017 R. Danbrook
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
|
@ -52,7 +52,7 @@ void audio_set_speed(int speed) {
|
|||
|
||||
void audio_queue() {
|
||||
while ((bufsamples + bufsize) >= EBUFSIZE) { SDL_Delay(1); }
|
||||
|
||||
|
||||
SDL_LockAudioDevice(dev);
|
||||
for (int i = 0; i < bufsize; i++) {
|
||||
extbuf[bufend] = intbuf[i];
|
||||
|
@ -90,9 +90,9 @@ void audio_init_sdl() {
|
|||
spec.samples = 512;
|
||||
spec.userdata = 0;
|
||||
spec.callback = audio_cb;
|
||||
|
||||
|
||||
bufsize = channels * (conf.audio_sample_rate / framerate);
|
||||
|
||||
|
||||
dev = SDL_OpenAudioDevice(NULL, 0, &spec, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Error opening audio device.\n");
|
||||
|
@ -100,7 +100,7 @@ void audio_init_sdl() {
|
|||
else {
|
||||
fprintf(stderr, "Audio: SDL - %dHz %d-bit, %d channel(s)\n", spec.freq, 16, spec.channels);
|
||||
}
|
||||
|
||||
|
||||
SDL_PauseAudioDevice(dev, 1); // Setting to 0 unpauses
|
||||
}
|
||||
|
||||
|
@ -129,15 +129,15 @@ void audio_unpause() {
|
|||
void audio_set_params(Sound::Output *soundoutput) {
|
||||
// Set audio parameters
|
||||
Sound sound(emulator);
|
||||
|
||||
|
||||
sound.SetSampleBits(16);
|
||||
sound.SetSampleRate(conf.audio_sample_rate);
|
||||
|
||||
|
||||
sound.SetSpeaker(conf.audio_stereo ? Sound::SPEAKER_STEREO : Sound::SPEAKER_MONO);
|
||||
sound.SetSpeed(Sound::DEFAULT_SPEED);
|
||||
|
||||
|
||||
audio_adj_volume();
|
||||
|
||||
|
||||
soundoutput->samples[0] = intbuf;
|
||||
soundoutput->length[0] = conf.audio_sample_rate / framerate;
|
||||
soundoutput->samples[1] = NULL;
|
||||
|
@ -159,6 +159,6 @@ void audio_adj_volume() {
|
|||
sound.SetVolume(Sound::CHANNEL_VRC7, conf.audio_vol_vrc7);
|
||||
sound.SetVolume(Sound::CHANNEL_N163, conf.audio_vol_n163);
|
||||
sound.SetVolume(Sound::CHANNEL_S5B, conf.audio_vol_s5b);
|
||||
|
||||
|
||||
if (conf.audio_volume == 0) { memset(intbuf, 0, sizeof(intbuf)); }
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2012-2018 R. Danbrook
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
@ -32,35 +32,35 @@ void nst_cheats_init(const char *cheatpath) {
|
|||
// Initialize cheat engine
|
||||
Cheats cheats(emulator);
|
||||
Xml xml;
|
||||
|
||||
|
||||
cheats.ClearCodes();
|
||||
|
||||
|
||||
std::ifstream cheatfile(cheatpath, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
|
||||
if (cheatfile.is_open()) {
|
||||
xml.Read(cheatfile);
|
||||
|
||||
|
||||
if (xml.GetRoot().IsType(L"cheats")) {
|
||||
|
||||
|
||||
Xml::Node root(xml.GetRoot());
|
||||
Xml::Node node(root.GetFirstChild());
|
||||
|
||||
|
||||
for (int i = 0; i < root.NumChildren(L"cheat"); i++) {
|
||||
|
||||
|
||||
if (node.GetAttribute(L"enabled").IsValue(L"1")) {
|
||||
|
||||
|
||||
if (node.GetChild(L"genie")) { // Game Genie
|
||||
nst_cheats_code_gg_add(node.GetChild(L"genie").GetValue());
|
||||
}
|
||||
|
||||
|
||||
else if (node.GetChild(L"rocky")) { // Pro Action Rocky
|
||||
nst_cheats_code_par_add(node.GetChild(L"rocky").GetValue());
|
||||
}
|
||||
|
||||
|
||||
else if (node.GetChild(L"address")) { // Raw
|
||||
nst_cheats_code_raw_add(node);
|
||||
}
|
||||
|
||||
|
||||
//fprintf(stderr, "Cheat: %ls\n", node.GetChild(L"description").GetValue());
|
||||
}
|
||||
node = node.GetNextSibling();
|
||||
|
@ -74,13 +74,13 @@ void nst_cheats_init(const char *cheatpath) {
|
|||
// List the active cheats
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
|
||||
char gg[9];
|
||||
|
||||
|
||||
for (int i = 0; i < cheats.NumCodes(); i++) {
|
||||
cheats.GetCode(i, code);
|
||||
cheats.GameGenieEncode(code, gg);
|
||||
|
||||
|
||||
fprintf(stderr, "Cheat: %s\n", gg);
|
||||
}
|
||||
}*/
|
||||
|
@ -89,10 +89,10 @@ void nst_cheats_code_gg_add(const wchar_t *data) {
|
|||
// Add a Game Genie code
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
|
||||
char gg[9];
|
||||
wcstombs(gg, data, sizeof(gg));
|
||||
|
||||
|
||||
cheats.GameGenieDecode(gg, code);
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
|
@ -101,10 +101,10 @@ void nst_cheats_code_par_add(const wchar_t *data) {
|
|||
// Add a Pro Action Rocky code
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
|
||||
char par[9];
|
||||
wcstombs(par, data, sizeof(par));
|
||||
|
||||
|
||||
cheats.ProActionRockyDecode(par, code);
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
|
@ -113,9 +113,9 @@ void nst_cheats_code_raw_add(Xml::Node node) {
|
|||
// Add a Raw code
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
|
||||
code.useCompare = false;
|
||||
|
||||
|
||||
code.address = node.GetChild(L"address").GetUnsignedValue();
|
||||
if (node.GetChild(L"value")) {
|
||||
code.value = node.GetChild(L"value").GetUnsignedValue();
|
||||
|
@ -132,18 +132,18 @@ void nst_dip_handle(const char *dippath) {
|
|||
// Handle the DIP switch file
|
||||
DipSwitches dipswitches(emulator);
|
||||
Xml xml;
|
||||
|
||||
|
||||
std::ifstream dipfile(dippath, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
|
||||
if (dipfile.is_open()) {
|
||||
xml.Read(dipfile);
|
||||
|
||||
|
||||
if (xml.GetRoot().IsType(L"dipswitches")) {
|
||||
Xml::Node root(xml.GetRoot());
|
||||
Xml::Node node(root.GetFirstChild());
|
||||
|
||||
|
||||
for (int i = 0; i < root.NumChildren(L"dip"); i++) {
|
||||
|
||||
|
||||
if (node.GetChild(L"value")) {
|
||||
dipswitches.SetValue(i, node.GetChild(L"value").GetUnsignedValue());
|
||||
}
|
||||
|
@ -154,34 +154,34 @@ void nst_dip_handle(const char *dippath) {
|
|||
}
|
||||
else {
|
||||
Xml::Node root(xml.GetRoot());
|
||||
|
||||
|
||||
root = xml.Create(L"dipswitches");
|
||||
root.AddAttribute(L"version", L"1.0");
|
||||
|
||||
|
||||
wchar_t wbuf[32];
|
||||
char buf[2];
|
||||
|
||||
|
||||
int numdips = dipswitches.NumDips();
|
||||
|
||||
|
||||
if (numdips > 0) {
|
||||
for (int i = 0; i < numdips; i++) {
|
||||
Xml::Node node(root.AddChild(L"dip"));
|
||||
|
||||
|
||||
mbstowcs(wbuf, dipswitches.GetDipName(i), sizeof(wbuf));
|
||||
node.AddChild(L"description", wbuf);
|
||||
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", dipswitches.GetValue(i));
|
||||
mbstowcs(wbuf, buf, sizeof(buf));
|
||||
node.AddChild(L"value", wbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::ofstream dipout(dippath, std::ifstream::out|std::ifstream::binary);
|
||||
|
||||
if (dipout.is_open()) {
|
||||
xml.Write(root, dipout);
|
||||
}
|
||||
|
||||
|
||||
dipout.close();
|
||||
}
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2012-2016 R. Danbrook
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -82,28 +82,28 @@ void cli_handle_command(int argc, char *argv[]) {
|
|||
{"version", no_argument, 0, 'v'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
int option_index = 0;
|
||||
|
||||
|
||||
c = getopt_long(argc, argv, "defhl:mnopqrs:tuvw",
|
||||
long_options, &option_index);
|
||||
|
||||
|
||||
if (c == -1) { break; }
|
||||
|
||||
|
||||
switch(c) {
|
||||
case 'f':
|
||||
conf.video_fullscreen = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'w':
|
||||
conf.video_fullscreen = false;
|
||||
break;
|
||||
|
||||
|
||||
case 'h':
|
||||
cli_show_usage();
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
|
||||
case 'l':
|
||||
optint = atoi(optarg);
|
||||
if (optint < 6) {
|
||||
|
@ -113,23 +113,23 @@ void cli_handle_command(int argc, char *argv[]) {
|
|||
cli_error("Error: Invalid filter");
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'm':
|
||||
conf.video_unmask_overscan = false;
|
||||
break;
|
||||
|
||||
|
||||
case 'n':
|
||||
conf.video_unmask_overscan = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'o':
|
||||
conf.video_stretch_aspect = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'p':
|
||||
conf.video_stretch_aspect = false;
|
||||
break;
|
||||
|
||||
|
||||
case 's':
|
||||
optint = atoi(optarg);
|
||||
if (optint < 5 && optint != 0) {
|
||||
|
@ -139,28 +139,28 @@ void cli_handle_command(int argc, char *argv[]) {
|
|||
cli_error("Error: Invalid scale factor");
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 't':
|
||||
conf.video_tv_aspect = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'r':
|
||||
conf.video_tv_aspect = false;
|
||||
break;
|
||||
|
||||
|
||||
case 'u':
|
||||
conf.video_unlimited_sprites = true;
|
||||
break;
|
||||
|
||||
|
||||
case 'q':
|
||||
conf.video_unlimited_sprites = false;
|
||||
break;
|
||||
|
||||
|
||||
case 'v':
|
||||
cli_show_version();
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
cli_error("Error: Invalid option");
|
||||
break;
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2012-2016 R. Danbrook
|
||||
* Copyright (C) 2018-2018 Phil Smith
|
||||
*
|
||||
|
@ -8,17 +8,17 @@
|
|||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -45,10 +45,10 @@ void config_file_read(const char *nstdir) {
|
|||
|
||||
void config_file_write(const char *nstdir) {
|
||||
// Write the config file
|
||||
|
||||
|
||||
char confpath[256];
|
||||
snprintf(confpath, sizeof(confpath), "%snestopia.conf", nstdir);
|
||||
|
||||
|
||||
FILE *fp = fopen(confpath, "w");
|
||||
if (fp != NULL) {
|
||||
// Video
|
||||
|
@ -87,11 +87,9 @@ void config_file_write(const char *nstdir) {
|
|||
fprintf(fp, "unlimited_sprites=%d\n", conf.video_unlimited_sprites);
|
||||
fprintf(fp, "xbr_pixel_blending=%d\n", conf.video_xbr_pixel_blending);
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
|
||||
// Audio
|
||||
fprintf(fp, "[audio]\n");
|
||||
fprintf(fp, "; 0=SDL, 1=libao, 2=jack\n");
|
||||
fprintf(fp, "api=%d\n\n", conf.audio_api);
|
||||
fprintf(fp, "; Valid values are 1 and 0.\n");
|
||||
fprintf(fp, "stereo=%d\n\n", conf.audio_stereo);
|
||||
fprintf(fp, "; Valid values are 11025, 22050, 44100, 48000, and 96000.\n");
|
||||
|
@ -110,7 +108,7 @@ void config_file_write(const char *nstdir) {
|
|||
fprintf(fp, "vol_n163=%d\n", conf.audio_vol_n163);
|
||||
fprintf(fp, "vol_s5b=%d\n", conf.audio_vol_s5b);
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
|
||||
// Timing
|
||||
fprintf(fp, "[timing]\n");
|
||||
fprintf(fp, "; Base speed for NTSC in Frames per Second.\n");
|
||||
|
@ -120,7 +118,7 @@ void config_file_write(const char *nstdir) {
|
|||
fprintf(fp, "; Pulse turbo buttons every n frames. Minimum value is 2.\n");
|
||||
fprintf(fp, "turbopulse=%d\n", conf.timing_turbopulse);
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
|
||||
// Misc
|
||||
fprintf(fp, "[misc]\n");
|
||||
fprintf(fp, "; 0=Auto, 1=NTSC, 2=PAL, 3=Famicom, 4=Dendy\n");
|
||||
|
@ -147,7 +145,7 @@ void config_file_write(const char *nstdir) {
|
|||
}
|
||||
|
||||
void config_set_default() {
|
||||
|
||||
|
||||
// Video
|
||||
conf.video_filter = 0;
|
||||
conf.video_scale_factor = 2;
|
||||
|
@ -171,9 +169,8 @@ void config_set_default() {
|
|||
conf.video_stretch_aspect = false;
|
||||
conf.video_unlimited_sprites = false;
|
||||
conf.video_xbr_pixel_blending = false;
|
||||
|
||||
|
||||
// Audio
|
||||
conf.audio_api = 0;
|
||||
conf.audio_stereo = false;
|
||||
conf.audio_sample_rate = 48000;
|
||||
conf.audio_volume = 85;
|
||||
|
@ -188,12 +185,12 @@ void config_set_default() {
|
|||
conf.audio_vol_vrc7 = 85;
|
||||
conf.audio_vol_n163 = 85;
|
||||
conf.audio_vol_s5b = 85;
|
||||
|
||||
|
||||
// Timing
|
||||
conf.timing_speed = 60;
|
||||
conf.timing_ffspeed = 3;
|
||||
conf.timing_turbopulse = 3;
|
||||
|
||||
|
||||
// Misc
|
||||
conf.misc_default_system = 0;
|
||||
conf.misc_soft_patching = true;
|
||||
|
@ -211,7 +208,7 @@ void config_set_default() {
|
|||
static int config_match(void* user, const char* section, const char* name, const char* value) {
|
||||
// Match values from config file and populate live config
|
||||
settings_t* pconfig = (settings_t*)user;
|
||||
|
||||
|
||||
// Video
|
||||
if (MATCH("video", "filter")) { pconfig->video_filter = atoi(value); }
|
||||
else if (MATCH("video", "scale_factor")) { pconfig->video_scale_factor = atoi(value); }
|
||||
|
@ -235,9 +232,8 @@ static int config_match(void* user, const char* section, const char* name, const
|
|||
else if (MATCH("video", "stretch_aspect")) { pconfig->video_stretch_aspect = atoi(value); }
|
||||
else if (MATCH("video", "unlimited_sprites")) { pconfig->video_unlimited_sprites = atoi(value); }
|
||||
else if (MATCH("video", "xbr_pixel_blending")) { pconfig->video_xbr_pixel_blending = atoi(value); }
|
||||
|
||||
|
||||
// Audio
|
||||
else if (MATCH("audio", "api")) { pconfig->audio_api = atoi(value); }
|
||||
else if (MATCH("audio", "stereo")) { pconfig->audio_stereo = atoi(value); }
|
||||
else if (MATCH("audio", "sample_rate")) { pconfig->audio_sample_rate = atoi(value); }
|
||||
else if (MATCH("audio", "volume")) { pconfig->audio_volume = atoi(value); }
|
||||
|
@ -252,12 +248,12 @@ static int config_match(void* user, const char* section, const char* name, const
|
|||
else if (MATCH("audio", "vol_vrc7")) { pconfig->audio_vol_vrc7 = atoi(value); }
|
||||
else if (MATCH("audio", "vol_n163")) { pconfig->audio_vol_n163 = atoi(value); }
|
||||
else if (MATCH("audio", "vol_s5b")) { pconfig->audio_vol_s5b = atoi(value); }
|
||||
|
||||
|
||||
// Timing
|
||||
else if (MATCH("timing", "speed")) { pconfig->timing_speed = atoi(value); }
|
||||
else if (MATCH("timing", "ffspeed")) { pconfig->timing_ffspeed = atoi(value); }
|
||||
else if (MATCH("timing", "turbopulse")) { pconfig->timing_turbopulse = atoi(value); }
|
||||
|
||||
|
||||
// Misc
|
||||
else if (MATCH("misc", "default_system")) { pconfig->misc_default_system = atoi(value); }
|
||||
else if (MATCH("misc", "soft_patching")) { pconfig->misc_soft_patching = atoi(value); }
|
|
@ -2,7 +2,7 @@
|
|||
#define _CONFIG_H_
|
||||
|
||||
typedef struct {
|
||||
|
||||
|
||||
// Video
|
||||
int video_filter;
|
||||
int video_scale_factor;
|
||||
|
@ -26,9 +26,8 @@ typedef struct {
|
|||
bool video_stretch_aspect;
|
||||
bool video_unlimited_sprites;
|
||||
bool video_xbr_pixel_blending;
|
||||
|
||||
|
||||
// Audio
|
||||
int audio_api;
|
||||
bool audio_stereo;
|
||||
int audio_sample_rate;
|
||||
int audio_volume;
|
||||
|
@ -43,12 +42,12 @@ typedef struct {
|
|||
int audio_vol_vrc7;
|
||||
int audio_vol_n163;
|
||||
int audio_vol_s5b;
|
||||
|
||||
|
||||
// Timing
|
||||
int timing_speed;
|
||||
int timing_ffspeed;
|
||||
int timing_turbopulse;
|
||||
|
||||
|
||||
// Misc
|
||||
int misc_default_system;
|
||||
bool misc_soft_patching;
|
536
source/fltkui/fltkui.cpp
Normal file
536
source/fltkui/fltkui.cpp
Normal file
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2021 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Menu_Bar.H>
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
#include <FL/Fl_PNG_Image.H>
|
||||
#include <FL/Fl_Gl_Window.H>
|
||||
#include <FL/gl.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "cli.h"
|
||||
#include "config.h"
|
||||
#include "audio.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
|
||||
#include "fltkui.h"
|
||||
#include "fltkui_archive.h"
|
||||
#include "fltkui_config.h"
|
||||
|
||||
#define MBARHEIGHT 24
|
||||
|
||||
static NstWindow *nstwin;
|
||||
static Fl_Menu_Bar *menubar;
|
||||
static NstGlArea *glarea;
|
||||
static NstConfWindow *confwin;
|
||||
|
||||
Fl_Color NstGreen = 0x255f6500;
|
||||
Fl_Color NstPurple = 0x5f578700;
|
||||
Fl_Color NstRed = 0xb51e2c00;
|
||||
Fl_Color NstBlueGrey = 0x383c4a00;
|
||||
Fl_Color NstLightGrey = 0xd3dae300;
|
||||
|
||||
extern Input::Controllers *cNstPads;
|
||||
extern nstpaths_t nstpaths;
|
||||
|
||||
extern bool (*nst_archive_select)(const char*, char*, size_t);
|
||||
|
||||
static void fltkui_config(Fl_Widget* w, void* userdata) {
|
||||
confwin->show();
|
||||
}
|
||||
|
||||
static void fltkui_rom_open(Fl_Widget* w, void* userdata) {
|
||||
// Create native chooser
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Select a ROM");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_FILE);
|
||||
fc.filter("NES Games\t*.{nes,unf,fds,zip,7z,gz,bz2,xz}");
|
||||
|
||||
// Show file chooser
|
||||
switch (fc.show()) {
|
||||
case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break;
|
||||
case 1: break; // Cancel
|
||||
default:
|
||||
if (fc.filename()) {
|
||||
int loaded = nst_load(fc.filename());
|
||||
nstwin->label(nstpaths.gamename);
|
||||
if (loaded) { nst_play(); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fltkui_movie_load(Fl_Widget* w, void* userdata) {
|
||||
// Create native chooser
|
||||
if (!nst_playing()) { return; }
|
||||
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Select a Movie");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_FILE);
|
||||
fc.directory((const char*)nstpaths.nstdir);
|
||||
fc.filter("Nestopia Movies\t*.nsv");
|
||||
|
||||
// Show file chooser
|
||||
switch (fc.show()) {
|
||||
case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break;
|
||||
case 1: break; // Cancel
|
||||
default:
|
||||
if (fc.filename()) {
|
||||
nst_movie_load(fc.filename());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fltkui_movie_save(Fl_Widget* w, void* userdata) {
|
||||
// Create native chooser
|
||||
if (!nst_playing()) { return; }
|
||||
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Save Movie");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
|
||||
fc.directory((const char*)nstpaths.nstdir);
|
||||
fc.filter("Nestopia Moviess\t*.nsv");
|
||||
fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT);
|
||||
|
||||
// Show file chooser
|
||||
if (fc.show()) { return; }
|
||||
|
||||
nst_movie_save(fc.filename());
|
||||
}
|
||||
|
||||
static void fltkui_movie_stop(Fl_Widget* w, void* userdata) {
|
||||
nst_movie_stop();
|
||||
}
|
||||
|
||||
static void fltkui_state_load(Fl_Widget* w, void* userdata) {
|
||||
// Create native chooser
|
||||
if (!nst_playing()) { return; }
|
||||
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Load State");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_FILE);
|
||||
fc.directory((const char*)nstpaths.statepath);
|
||||
fc.filter("Nestopia States\t*.nst");
|
||||
|
||||
// Show file chooser
|
||||
switch (fc.show()) {
|
||||
case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break;
|
||||
case 1: break; // Cancel
|
||||
default:
|
||||
if (fc.filename()) {
|
||||
nst_state_load(fc.filename());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fltkui_state_save(Fl_Widget* w, void* userdata) {
|
||||
// Create native chooser
|
||||
if (!nst_playing()) { return; }
|
||||
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Save State");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
|
||||
fc.directory((const char*)nstpaths.statepath);
|
||||
fc.filter("Nestopia States\t*.nst");
|
||||
fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT);
|
||||
|
||||
// Show file chooser
|
||||
if (fc.show()) { return; }
|
||||
|
||||
nst_state_save(fc.filename());
|
||||
}
|
||||
|
||||
static void fltkui_screenshot(Fl_Widget* w, void* userdata) {
|
||||
// Create native chooser
|
||||
if (!nst_playing()) { return; }
|
||||
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Save Screenshot");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
|
||||
fc.directory((const char*)nstpaths.nstdir);
|
||||
fc.filter("PNG Screenshots\t*.png");
|
||||
fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT);
|
||||
|
||||
// Show file chooser
|
||||
if (fc.show()) { return; }
|
||||
|
||||
video_screenshot(fc.filename());
|
||||
}
|
||||
|
||||
static void fltkui_palette_open(Fl_Widget* w, void* userdata) {
|
||||
// Create native chooser
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Select a Palette");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_FILE);
|
||||
fc.filter("NES Palettes\t*.pal");
|
||||
|
||||
// Show file chooser
|
||||
switch (fc.show()) {
|
||||
case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break;
|
||||
case 1: break; // Cancel
|
||||
default:
|
||||
if (fc.filename()) {
|
||||
nst_palette_load(fc.filename());
|
||||
nst_palette_save();
|
||||
conf.video_palette_mode = 2;
|
||||
video_init();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fltkui_state_qload(Fl_Widget* w, void* userdata) {
|
||||
nst_state_quickload(atoi((const char*)userdata));
|
||||
}
|
||||
|
||||
static void fltkui_state_qsave(Fl_Widget* w, void* userdata) {
|
||||
nst_state_quicksave(atoi((const char*)userdata));
|
||||
}
|
||||
|
||||
static void fltkui_pause(Fl_Widget* w, void* userdata) {
|
||||
if (nst_playing()) {
|
||||
nst_pause();
|
||||
}
|
||||
else {
|
||||
nst_play();
|
||||
}
|
||||
}
|
||||
|
||||
static void fltkui_reset(Fl_Widget* w, void* userdata) {
|
||||
nst_reset(atoi((const char*)userdata));
|
||||
}
|
||||
|
||||
void fltkui_resize() {
|
||||
video_set_dimensions();
|
||||
dimensions_t rendersize = nst_video_get_dimensions_render();
|
||||
nstwin->size(rendersize.w, rendersize.h + MBARHEIGHT);
|
||||
menubar->resize(0, 0, nstwin->w(), MBARHEIGHT);
|
||||
glarea->resize(0, 24, rendersize.w, rendersize.h);
|
||||
nst_video_set_dimensions_screen(rendersize);
|
||||
video_init();
|
||||
}
|
||||
|
||||
void fltkui_fullscreen(Fl_Widget* w, void* userdata) {
|
||||
if (!nst_playing()) { return; }
|
||||
|
||||
conf.video_fullscreen ^= 1;
|
||||
|
||||
if (conf.video_fullscreen) {
|
||||
int x, y, w, h;
|
||||
Fl::screen_xywh(x, y, w, h);
|
||||
menubar->hide();
|
||||
nstwin->fullscreen();
|
||||
dimensions_t scrdim = {w, h};
|
||||
nstwin->resize(0, 0, scrdim.w, scrdim.h);
|
||||
glarea->resize(0, 0, scrdim.w, scrdim.h);
|
||||
nst_video_set_dimensions_screen(scrdim);
|
||||
video_init();
|
||||
}
|
||||
else {
|
||||
video_set_dimensions();
|
||||
dimensions_t rendersize = nst_video_get_dimensions_render();
|
||||
nstwin->fullscreen_off();
|
||||
nstwin->size(rendersize.w, rendersize.h + MBARHEIGHT);
|
||||
menubar->show();
|
||||
menubar->resize(0, 0, nstwin->w(), MBARHEIGHT);
|
||||
glarea->resize(0, 24, rendersize.w, rendersize.h);
|
||||
nst_video_set_dimensions_screen(rendersize);
|
||||
video_init();
|
||||
}
|
||||
}
|
||||
|
||||
static void fltkui_fds_flip(Fl_Widget* w, void* userdata) {
|
||||
nst_fds_flip();
|
||||
}
|
||||
|
||||
static void fltkui_fds_switch(Fl_Widget* w, void* userdata) {
|
||||
nst_fds_switch();
|
||||
}
|
||||
|
||||
static void fltkui_about_close(Fl_Widget* w, void* userdata) {
|
||||
Fl_Window *about = (Fl_Window*)userdata;
|
||||
about->hide();
|
||||
}
|
||||
|
||||
static void fltkui_about(Fl_Widget* w, void* userdata) {
|
||||
Fl_Window about(460, 440);
|
||||
Fl_Box iconbox(166, 16, 128, 128);
|
||||
|
||||
Fl_Box text0(0, 144, 460, 24, "Nestopia UE");
|
||||
text0.labelfont(FL_BOLD);
|
||||
|
||||
Fl_Box text1(0, 166, 460, 24, "1.51.0");
|
||||
|
||||
Fl_Box text2(0, 208, 460, 24, "Cycle-Accurate Nintendo Entertainment System Emulator");
|
||||
|
||||
Fl_Box text3(0, 256, 460, 24, "FLTK Frontend\n(c) 2012-2021, R. Danbrook\n(c) 2007-2008, R. Belmont");
|
||||
text3.labelsize(10);
|
||||
|
||||
Fl_Box text4(0, 320, 460, 24, "Nestopia Emulator\n(c) 2020-2021, Rupert Carmichael\n(c) 2012-2020, Nestopia UE Contributors\n(c) 2003-2008, Martin Freij");
|
||||
text4.labelsize(10);
|
||||
|
||||
Fl_Box text5(0, 360, 460, 24, "Icon based on drawing by Trollekop");
|
||||
text5.labelsize(10);
|
||||
|
||||
Fl_PNG_Image nsticon("nestopia.png");
|
||||
iconbox.image(nsticon);
|
||||
|
||||
Fl_Button close(360, 400, 80, 24, "&Close");
|
||||
close.callback(fltkui_about_close, (void*)&about);
|
||||
|
||||
about.set_modal();
|
||||
about.show();
|
||||
while (about.shown()) { Fl::wait(); }
|
||||
}
|
||||
|
||||
static void quit_cb(Fl_Widget* w, void* userdata) {
|
||||
nstwin->hide();
|
||||
}
|
||||
|
||||
// this is used to stop Esc from exiting the program:
|
||||
int handle(int e) {
|
||||
return (e == FL_SHORTCUT); // eat all keystrokes
|
||||
}
|
||||
|
||||
int NstWindow::handle(int e) {
|
||||
switch (e) { case FL_KEYDOWN: case FL_KEYUP: fltkui_input_process_key(e); break; }
|
||||
return Fl_Double_Window::handle(e);
|
||||
}
|
||||
|
||||
int NstGlArea::handle(int e) {
|
||||
if (nst_input_zapper_present()) {
|
||||
switch (e) {
|
||||
case FL_ENTER:
|
||||
cursor(conf.misc_disable_cursor_special ? FL_CURSOR_NONE : FL_CURSOR_CROSS);
|
||||
break;
|
||||
case FL_LEAVE:
|
||||
cursor(FL_CURSOR_DEFAULT);
|
||||
break;
|
||||
case FL_PUSH:
|
||||
nst_input_inject_mouse(cNstPads, Fl::event_button(), 1, Fl::event_x(), Fl::event_y());
|
||||
break;
|
||||
case FL_RELEASE:
|
||||
nst_input_inject_mouse(cNstPads, Fl::event_button(), 0, Fl::event_x(), Fl::event_y());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (e == FL_ENTER && conf.misc_disable_cursor) { cursor(FL_CURSOR_NONE); }
|
||||
else if (e == FL_LEAVE) { cursor(FL_CURSOR_DEFAULT); }
|
||||
|
||||
return Fl_Gl_Window::handle(e);
|
||||
}
|
||||
|
||||
static Fl_Menu_Item menutable[] = {
|
||||
{"&File", 0, 0, 0, FL_SUBMENU},
|
||||
{"&Open", FL_ALT + 'o', fltkui_rom_open, 0, FL_MENU_DIVIDER},
|
||||
{"Load State...", 0, fltkui_state_load, 0, 0},
|
||||
{"Save State...", 0, fltkui_state_save, 0, FL_MENU_DIVIDER},
|
||||
{"Quick Load", 0, 0, 0, FL_SUBMENU},
|
||||
{"Slot 0", 0, fltkui_state_qload, (void*)"0", 0},
|
||||
{"Slot 1", 0, fltkui_state_qload, (void*)"1", 0},
|
||||
{"Slot 2", 0, fltkui_state_qload, (void*)"2", 0},
|
||||
{"Slot 3", 0, fltkui_state_qload, (void*)"3", 0},
|
||||
{"Slot 4", 0, fltkui_state_qload, (void*)"4", 0},
|
||||
{0},
|
||||
{"Quick Save", 0, 0, 0, FL_SUBMENU|FL_MENU_DIVIDER},
|
||||
{"Slot 0", 0, fltkui_state_qsave, (void*)"0", 0},
|
||||
{"Slot 1", 0, fltkui_state_qsave, (void*)"1", 0},
|
||||
{"Slot 2", 0, fltkui_state_qsave, (void*)"2", 0},
|
||||
{"Slot 3", 0, fltkui_state_qsave, (void*)"3", 0},
|
||||
{"Slot 4", 0, fltkui_state_qsave, (void*)"4", 0},
|
||||
{0},
|
||||
{"Open Palette...", 0, fltkui_palette_open, 0, FL_MENU_DIVIDER},
|
||||
{"Screenshot...", 0, fltkui_screenshot, 0, FL_MENU_DIVIDER},
|
||||
{"Load Movie...", 0, fltkui_movie_load, 0, 0},
|
||||
{"Record Movie...", 0, fltkui_movie_save, 0, 0},
|
||||
{"Stop Movie", 0, fltkui_movie_stop, 0, FL_MENU_DIVIDER},
|
||||
{"&Quit", FL_ALT + 'q', quit_cb},
|
||||
{0}, // End File
|
||||
{"&Emulator", 0, 0, 0, FL_SUBMENU},
|
||||
{"Pause/Play", 0, fltkui_pause, 0, FL_MENU_DIVIDER},
|
||||
{"Reset (Soft)", 0, fltkui_reset, (void*)"0", 0},
|
||||
{"Reset (Hard)", 0, fltkui_reset, (void*)"1", FL_MENU_DIVIDER},
|
||||
{"Fullscreen", 0, fltkui_fullscreen, 0, FL_MENU_DIVIDER},
|
||||
{"Flip Disk", 0, fltkui_fds_flip, 0, 0},
|
||||
{"Switch Disk", 0, fltkui_fds_switch, 0, FL_MENU_DIVIDER},
|
||||
//{"Cheats...", 0, 0, 0, FL_MENU_DIVIDER},
|
||||
{"Configuration...", 0, fltkui_config, 0},
|
||||
{0}, // End Emulator
|
||||
{"&Help", 0, 0, 0, FL_SUBMENU},
|
||||
{"About", 0, fltkui_about, 0, 0},
|
||||
{0}, // End Help
|
||||
{0} // End Menu
|
||||
};
|
||||
|
||||
void makenstwin(const char *name) {
|
||||
video_set_dimensions();
|
||||
dimensions_t rendersize = nst_video_get_dimensions_render();
|
||||
|
||||
// Configuration Window
|
||||
Fl::add_handler(handle);
|
||||
confwin = new NstConfWindow(400, 400, "Configuration");
|
||||
confwin->populate();
|
||||
|
||||
// Main Window
|
||||
nstwin = new NstWindow(rendersize.w, rendersize.h + MBARHEIGHT, name);
|
||||
nstwin->color(FL_BLACK);
|
||||
nstwin->xclass("nestopia");
|
||||
|
||||
// Menu Bar
|
||||
menubar = new Fl_Menu_Bar(0, 0, nstwin->w(), MBARHEIGHT);
|
||||
menubar->box(FL_FLAT_BOX);
|
||||
menubar->menu(menutable);
|
||||
|
||||
glarea = new NstGlArea(0, MBARHEIGHT, nstwin->w(), nstwin->h() - MBARHEIGHT);
|
||||
glarea->color(FL_BLACK);
|
||||
|
||||
nstwin->resizable(glarea);
|
||||
nstwin->resizable(nstwin);
|
||||
nstwin->end();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Set up directories
|
||||
nst_set_dirs();
|
||||
|
||||
// Set default config options
|
||||
config_set_default();
|
||||
|
||||
// Read the config file and override defaults
|
||||
config_file_read(nstpaths.nstconfdir);
|
||||
|
||||
// Handle command line arguments
|
||||
cli_handle_command(argc, argv);
|
||||
|
||||
// Set the video dimensions
|
||||
video_set_dimensions();
|
||||
|
||||
// Set up callbacks
|
||||
nst_set_callbacks();
|
||||
|
||||
// Initialize SDL Audio and Joystick
|
||||
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) {
|
||||
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set archive handler function pointer
|
||||
nst_archive_select = &fltkui_archive_select;
|
||||
|
||||
// Detect and set up Joysticks
|
||||
nstsdl_input_joysticks_detect();
|
||||
nstsdl_input_conf_defaults();
|
||||
nstsdl_input_conf_read();
|
||||
|
||||
// Initialize and load FDS BIOS and NstDatabase.xml
|
||||
nst_fds_bios_load();
|
||||
nst_db_load();
|
||||
|
||||
makenstwin(argv[0]);
|
||||
nstwin->label("Nestopia UE");
|
||||
nstwin->show();
|
||||
menubar->show();
|
||||
glarea->make_current();
|
||||
glarea->show();
|
||||
|
||||
Fl::check();
|
||||
|
||||
// Load a rom from the command line
|
||||
if (argc > 1 && argv[argc - 1][0] != '-') {
|
||||
int loaded = nst_load(argv[argc - 1]);
|
||||
if (loaded) { nst_play(); }
|
||||
else { exit(1); }
|
||||
nstwin->label(nstpaths.gamename);
|
||||
}
|
||||
else if (conf.video_fullscreen) {
|
||||
conf.video_fullscreen = 0;
|
||||
}
|
||||
|
||||
if (conf.video_fullscreen) {
|
||||
conf.video_fullscreen = 0;
|
||||
fltkui_fullscreen(NULL, NULL);
|
||||
}
|
||||
|
||||
video_init();
|
||||
|
||||
while (true) {
|
||||
glarea->redraw();
|
||||
|
||||
if (nstwin->visible() && !Fl::check()) {
|
||||
break;
|
||||
}
|
||||
else if (!nstwin->shown() && confwin->shown()) {
|
||||
break;
|
||||
}
|
||||
else if (!Fl::wait()) {
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_JOYHATMOTION:
|
||||
case SDL_JOYAXISMOTION:
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
nstsdl_input_process(cNstPads, event);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
nst_emuloop();
|
||||
glarea->redraw();
|
||||
}
|
||||
|
||||
// Remove the cartridge and shut down the NES
|
||||
nst_unload();
|
||||
|
||||
// Unload the FDS BIOS, NstDatabase.xml, and the custom palette
|
||||
nst_db_unload();
|
||||
nst_fds_bios_unload();
|
||||
nst_palette_unload();
|
||||
|
||||
// Deinitialize audio
|
||||
audio_deinit();
|
||||
|
||||
// Deinitialize joysticks
|
||||
nstsdl_input_joysticks_close();
|
||||
|
||||
// Write the input config file
|
||||
nstsdl_input_conf_write();
|
||||
|
||||
// Write the config file
|
||||
config_file_write(nstpaths.nstconfdir);
|
||||
|
||||
return 0;
|
||||
}
|
33
source/fltkui/fltkui.h
Normal file
33
source/fltkui/fltkui.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
class NstWindow : public Fl_Double_Window {
|
||||
private:
|
||||
int handle(int e);
|
||||
|
||||
public:
|
||||
NstWindow(int w, int h, const char* t = 0) : Fl_Double_Window(w, h, t) { }
|
||||
virtual ~NstWindow() { }
|
||||
};
|
||||
|
||||
class NstGlArea : public Fl_Gl_Window {
|
||||
private:
|
||||
void draw() { nst_ogl_render(); }
|
||||
int handle(int e);
|
||||
|
||||
public:
|
||||
NstGlArea(int x, int y, int w, int h, const char *l = 0) : Fl_Gl_Window(x, y, w, h, l) {
|
||||
box(FL_DOWN_FRAME);
|
||||
}
|
||||
};
|
||||
|
||||
extern Fl_Color NstGreen;
|
||||
extern Fl_Color NstPurple;
|
||||
extern Fl_Color NstRed;
|
||||
extern Fl_Color NstBlueGrey;
|
||||
extern Fl_Color NstLightGrey;
|
||||
|
||||
void fltkui_resize();
|
||||
void fltkui_fullscreen(Fl_Widget* w, void* userdata);
|
||||
|
||||
#endif
|
125
source/fltkui/fltkui_archive.cpp
Normal file
125
source/fltkui/fltkui_archive.cpp
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2021 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Select_Browser.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "fltkui_archive.h"
|
||||
|
||||
static Fl_Double_Window *window;
|
||||
static Fl_Select_Browser *browser;
|
||||
static char *romfile = NULL;
|
||||
|
||||
static void fltkui_archive_ok(Fl_Widget *w, long) {
|
||||
window->hide();
|
||||
}
|
||||
|
||||
static void fltkui_archive_cancel(Fl_Widget *w, long) {
|
||||
snprintf(romfile, 256, "%s", "");
|
||||
window->hide();
|
||||
}
|
||||
|
||||
static void fltkui_archive_setfile(Fl_Widget *w, long) {
|
||||
int r = ((Fl_Browser*)w)->value();
|
||||
if (r) {
|
||||
snprintf(romfile, 256, "%s", ((Fl_Browser*)w)->text(r));
|
||||
if (Fl::event_clicks()) { window->hide(); }
|
||||
}
|
||||
else {
|
||||
snprintf(romfile, 256, "%s", "");
|
||||
}
|
||||
}
|
||||
|
||||
bool fltkui_archive_select(const char *filename, char *reqfile, size_t reqsize) {
|
||||
// Select a filename to pull out of the archive
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
int r, numarchives = 0;
|
||||
|
||||
a = archive_read_new();
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
r = archive_read_open_filename(a, filename, 10240);
|
||||
|
||||
// Test if it's actually an archive
|
||||
if (r != ARCHIVE_OK) {
|
||||
r = archive_read_free(a);
|
||||
return false;
|
||||
}
|
||||
// If it is an archive, handle it
|
||||
else {
|
||||
if (window) { delete window; }
|
||||
|
||||
window = new Fl_Double_Window(420, 260, "Load from Archive");
|
||||
browser = new Fl_Select_Browser(0, 0, window->w(), 200, 0);
|
||||
browser->type(FL_HOLD_BROWSER);
|
||||
browser->callback(fltkui_archive_setfile, 0);
|
||||
Fl_Button btncancel(260, 220, 80, 24, "&Cancel");
|
||||
btncancel.callback(fltkui_archive_cancel, 0);
|
||||
Fl_Button btnok(350, 220, 40, 24, "&OK");
|
||||
btnok.callback(fltkui_archive_ok, 0);
|
||||
|
||||
romfile = reqfile;
|
||||
|
||||
// Fill the treestore with the filenames
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||
const char *currentfile = archive_entry_pathname(entry);
|
||||
if (nst_archive_checkext(currentfile)) {
|
||||
browser->add(currentfile);
|
||||
numarchives++;
|
||||
snprintf(reqfile, reqsize, "%s", currentfile);
|
||||
}
|
||||
archive_read_data_skip(a);
|
||||
}
|
||||
|
||||
// Free the archive
|
||||
r = archive_read_free(a);
|
||||
|
||||
// If there are no valid files in the archive, return
|
||||
if (numarchives == 0) { return false; }
|
||||
// If there's only one file, don't bring up the selector
|
||||
else if (numarchives == 1) { return true; }
|
||||
|
||||
browser->select(1);
|
||||
snprintf(romfile, 256, "%s", browser->text(1));
|
||||
|
||||
window->resizable(browser);
|
||||
window->show();
|
||||
window->set_modal();
|
||||
window->show();
|
||||
while (window->shown()) { Fl::wait(); }
|
||||
|
||||
if (strlen(romfile)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
6
source/fltkui/fltkui_archive.h
Normal file
6
source/fltkui/fltkui_archive.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _FLTKUI_ARCHIVE_H_
|
||||
#define _FLTKUI_ARCHIVE_H_
|
||||
|
||||
bool fltkui_archive_select(const char *filename, char *reqfile, size_t reqsize);
|
||||
|
||||
#endif
|
666
source/fltkui/fltkui_config.cpp
Normal file
666
source/fltkui/fltkui_config.cpp
Normal file
|
@ -0,0 +1,666 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2021 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Gl_Window.H>
|
||||
#include <FL/Fl_Tabs.H>
|
||||
#include <FL/Fl_Choice.H>
|
||||
#include <FL/Fl_Check_Button.H>
|
||||
#include <FL/Fl_Hor_Value_Slider.H>
|
||||
#include <FL/Fl_Dial.H>
|
||||
#include <FL/Fl_Output.H>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "config.h"
|
||||
#include "audio.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
|
||||
#include "fltkui.h"
|
||||
#include "fltkui_config.h"
|
||||
|
||||
static const char *icfg_labels[10] = {
|
||||
"Press Key For: Up",
|
||||
"Press Key For: Down",
|
||||
"Press Key For: Left",
|
||||
"Press Key For: Right",
|
||||
"Press Key For: Select",
|
||||
"Press Key For: Start",
|
||||
"Press Key For: A",
|
||||
"Press Key For: B",
|
||||
"Press Key For: Turbo A",
|
||||
"Press Key For: Turbo B"
|
||||
};
|
||||
|
||||
NstInputConfWindow *icfg;
|
||||
|
||||
static Fl_Dial *dial_vall, *dial_vsq1, *dial_vsq2, *dial_vtri, *dial_vnoise, *dial_vdpcm,
|
||||
*dial_vfds, *dial_vmmc5, *dial_vvrc6, *dial_vvrc7, *dial_vn163, *dial_vs5b;
|
||||
|
||||
extern inputsettings_t inputconf;
|
||||
|
||||
static void cb_filter(Fl_Widget *w, long) {
|
||||
conf.video_filter = ((Fl_Choice*)w)->value();
|
||||
fltkui_resize();
|
||||
}
|
||||
|
||||
static void cb_scale(Fl_Widget *w, long) {
|
||||
conf.video_scale_factor = ((Fl_Choice*)w)->value() + 1;
|
||||
fltkui_resize();
|
||||
}
|
||||
|
||||
static void cb_ntscmode(Fl_Widget *w, long) {
|
||||
conf.video_ntsc_mode = ((Fl_Choice*)w)->value();
|
||||
fltkui_resize();
|
||||
}
|
||||
|
||||
static void cb_xbrrounding(Fl_Widget *w, long) {
|
||||
conf.video_xbr_corner_rounding = ((Fl_Choice*)w)->value();
|
||||
video_init();
|
||||
video_toggle_filterupdate();
|
||||
}
|
||||
|
||||
static void cb_palettemode(Fl_Widget *w, long) {
|
||||
conf.video_palette_mode = ((Fl_Choice*)w)->value();
|
||||
video_init();
|
||||
}
|
||||
|
||||
static void cb_decoder(Fl_Widget *w, long) {
|
||||
conf.video_decoder = ((Fl_Choice*)w)->value();
|
||||
video_init();
|
||||
}
|
||||
|
||||
static void cb_brightness(Fl_Widget *w, long) {
|
||||
conf.video_brightness = ((Fl_Valuator*)w)->value();
|
||||
video_init();
|
||||
}
|
||||
|
||||
static void cb_saturation(Fl_Widget *w, long) {
|
||||
conf.video_saturation = ((Fl_Valuator*)w)->value();
|
||||
video_init();
|
||||
}
|
||||
|
||||
static void cb_contrast(Fl_Widget *w, long) {
|
||||
conf.video_contrast = ((Fl_Valuator*)w)->value();
|
||||
video_init();
|
||||
}
|
||||
|
||||
static void cb_hue(Fl_Widget *w, long) {
|
||||
conf.video_hue = ((Fl_Valuator*)w)->value();
|
||||
video_init();
|
||||
}
|
||||
|
||||
static void cb_xbrpixblend(Fl_Widget *w, long) {
|
||||
conf.video_xbr_pixel_blending = ((Fl_Check_Button*)w)->value();
|
||||
video_init();
|
||||
video_toggle_filterupdate();
|
||||
}
|
||||
|
||||
static void cb_linearfilter(Fl_Widget *w, long) {
|
||||
conf.video_linear_filter = ((Fl_Check_Button*)w)->value();
|
||||
video_init();
|
||||
}
|
||||
|
||||
static void cb_tvaspect(Fl_Widget *w, long) {
|
||||
conf.video_tv_aspect = ((Fl_Check_Button*)w)->value();
|
||||
fltkui_resize();
|
||||
}
|
||||
|
||||
static void cb_unmask_overscan(Fl_Widget *w, long) {
|
||||
conf.video_unmask_overscan = ((Fl_Check_Button*)w)->value();
|
||||
fltkui_resize();
|
||||
}
|
||||
|
||||
static void cb_unlimited_sprites(Fl_Widget *w, long) {
|
||||
conf.video_unlimited_sprites = ((Fl_Check_Button*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_samplerate(Fl_Widget *w, long) {
|
||||
switch (((Fl_Choice*)w)->value()) {
|
||||
case 0: conf.audio_sample_rate = 11025; break;
|
||||
case 1: conf.audio_sample_rate = 22050; break;
|
||||
case 2: conf.audio_sample_rate = 44100; break;
|
||||
case 3: conf.audio_sample_rate = 48000; break;
|
||||
case 4: conf.audio_sample_rate = 96000; break;
|
||||
default: conf.audio_sample_rate = 48000; break;
|
||||
}
|
||||
|
||||
if (nst_playing()) {
|
||||
nst_pause();
|
||||
nst_play();
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_dials() {
|
||||
dial_vall->value(conf.audio_volume);
|
||||
dial_vsq1->value(conf.audio_vol_sq1);
|
||||
dial_vsq2->value(conf.audio_vol_sq2);
|
||||
dial_vtri->value(conf.audio_vol_tri);
|
||||
dial_vnoise->value(conf.audio_vol_noise);
|
||||
dial_vdpcm->value(conf.audio_vol_dpcm);
|
||||
dial_vfds->value(conf.audio_vol_fds);
|
||||
dial_vmmc5->value(conf.audio_vol_mmc5);
|
||||
dial_vvrc6->value(conf.audio_vol_vrc6);
|
||||
dial_vvrc7->value(conf.audio_vol_vrc7);
|
||||
dial_vn163->value(conf.audio_vol_n163);
|
||||
dial_vs5b->value(conf.audio_vol_s5b);
|
||||
}
|
||||
|
||||
static void cb_volume(Fl_Widget *w, long adj) {
|
||||
Fl_Dial *dial = (Fl_Dial*)w;
|
||||
|
||||
switch (adj) {
|
||||
case 0:
|
||||
conf.audio_volume = (int)dial->value();
|
||||
conf.audio_vol_sq1 = conf.audio_vol_sq2 = conf.audio_vol_tri = conf.audio_vol_noise =
|
||||
conf.audio_vol_dpcm = conf.audio_vol_fds = conf.audio_vol_mmc5 = conf.audio_vol_vrc6 =
|
||||
conf.audio_vol_vrc7 = conf.audio_vol_n163 = conf.audio_vol_s5b = conf.audio_volume;
|
||||
break;
|
||||
case 1: conf.audio_vol_sq1 = (int)dial->value(); break;
|
||||
case 2: conf.audio_vol_sq2 = (int)dial->value(); break;
|
||||
case 3: conf.audio_vol_tri = (int)dial->value(); break;
|
||||
case 4: conf.audio_vol_noise = (int)dial->value(); break;
|
||||
case 5: conf.audio_vol_dpcm = (int)dial->value(); break;
|
||||
case 6: conf.audio_vol_fds = (int)dial->value(); break;
|
||||
case 7: conf.audio_vol_mmc5 = (int)dial->value(); break;
|
||||
case 8: conf.audio_vol_vrc6 = (int)dial->value(); break;
|
||||
case 9: conf.audio_vol_vrc7 = (int)dial->value(); break;
|
||||
case 10: conf.audio_vol_n163 = (int)dial->value(); break;
|
||||
case 11: conf.audio_vol_s5b = (int)dial->value(); break;
|
||||
}
|
||||
|
||||
audio_adj_volume();
|
||||
cb_dials();
|
||||
|
||||
}
|
||||
|
||||
static void cb_stereo(Fl_Widget *w, long) {
|
||||
conf.audio_stereo = ((Fl_Check_Button*)w)->value();
|
||||
|
||||
if (nst_playing()) {
|
||||
nst_pause();
|
||||
nst_play();
|
||||
}
|
||||
}
|
||||
|
||||
int NstInputConfWindow::handle(int e) {
|
||||
switch (e) {
|
||||
case FL_KEYUP:
|
||||
fltkui_input_conf_set(Fl::event_key(), player, btn);
|
||||
this->hide();
|
||||
this->set_non_modal();
|
||||
break;
|
||||
}
|
||||
|
||||
return Fl_Double_Window::handle(e);
|
||||
}
|
||||
|
||||
static void cb_icfg(Fl_Widget *w, long btn) {
|
||||
icfg->set_modal();
|
||||
icfg->btn = btn;
|
||||
icfg->text->label(icfg_labels[btn]);
|
||||
icfg->show();
|
||||
|
||||
if (icfg->device == 1) {
|
||||
nstsdl_input_conf_button(icfg->player, btn);
|
||||
icfg->hide();
|
||||
icfg->set_non_modal();
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_player(Fl_Widget *w, long) {
|
||||
icfg->player = ((Fl_Choice*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_idevice(Fl_Widget *w, long) {
|
||||
icfg->device = ((Fl_Choice*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_turbopulse(Fl_Widget *w, long) {
|
||||
conf.timing_turbopulse = ((Fl_Valuator*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_default_system(Fl_Widget *w, long) {
|
||||
conf.misc_default_system = ((Fl_Choice*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_power_state(Fl_Widget *w, long) {
|
||||
conf.misc_power_state = ((Fl_Choice*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_ffspeed(Fl_Widget *w, long) {
|
||||
conf.timing_ffspeed = ((Fl_Valuator*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_soft_patching(Fl_Widget *w, long) {
|
||||
conf.misc_soft_patching = ((Fl_Check_Button*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_genie_distortion(Fl_Widget *w, long) {
|
||||
conf.misc_genie_distortion = ((Fl_Check_Button*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_disable_cursor(Fl_Widget *w, long) {
|
||||
conf.misc_disable_cursor = ((Fl_Check_Button*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_disable_cursor_special(Fl_Widget *w, long) {
|
||||
conf.misc_disable_cursor_special = ((Fl_Check_Button*)w)->value();
|
||||
}
|
||||
|
||||
static void cb_ok(Fl_Widget *w, long) {
|
||||
w->parent()->hide();
|
||||
}
|
||||
|
||||
void NstConfWindow::populate() {
|
||||
Fl_Tabs *tabs = new Fl_Tabs(10, 5, 380, 360);
|
||||
|
||||
Fl_Group *vtab = new Fl_Group(10, 30, 380, 360, "&Video");
|
||||
|
||||
Fl_Choice *ch_filter = new Fl_Choice(20, 55, 160, 25, "Filter");
|
||||
ch_filter->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_filter->add("None");
|
||||
ch_filter->add("NTSC");
|
||||
ch_filter->add("xBR");
|
||||
ch_filter->add("HqX");
|
||||
ch_filter->add("2XSaI");
|
||||
ch_filter->add("ScaleX");
|
||||
ch_filter->value(conf.video_filter);
|
||||
ch_filter->callback(cb_filter);
|
||||
|
||||
Fl_Choice *ch_scale = new Fl_Choice(200, 55, 160, 25, "Scale Factor");
|
||||
ch_scale->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_scale->add("1x");
|
||||
ch_scale->add("2x");
|
||||
ch_scale->add("3x");
|
||||
ch_scale->add("4x");
|
||||
ch_scale->add("5x");
|
||||
ch_scale->add("6x");
|
||||
ch_scale->add("7x");
|
||||
ch_scale->add("8x");
|
||||
ch_scale->value(conf.video_scale_factor - 1);
|
||||
ch_scale->callback(cb_scale);
|
||||
|
||||
Fl_Choice *ch_ntscmode = new Fl_Choice(20, 105, 160, 25, "NTSC Mode");
|
||||
ch_ntscmode->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_ntscmode->add("Composite");
|
||||
ch_ntscmode->add("S-Video");
|
||||
ch_ntscmode->add("RGB");
|
||||
ch_ntscmode->add("Monochrome");
|
||||
ch_ntscmode->add("Custom");
|
||||
ch_ntscmode->value(conf.video_ntsc_mode);
|
||||
ch_ntscmode->callback(cb_ntscmode);
|
||||
|
||||
Fl_Choice *ch_xbrrounding = new Fl_Choice(200, 105, 160, 25, "xBR Corner Rounding");
|
||||
ch_xbrrounding->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_xbrrounding->add("None");
|
||||
ch_xbrrounding->add("Some");
|
||||
ch_xbrrounding->add("All");
|
||||
ch_xbrrounding->value(conf.video_xbr_corner_rounding);
|
||||
ch_xbrrounding->callback(cb_xbrrounding);
|
||||
|
||||
Fl_Choice *ch_palettemode = new Fl_Choice(20, 155, 160, 25, "Palette Mode");
|
||||
ch_palettemode->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_palettemode->add("YUV");
|
||||
ch_palettemode->add("RGB");
|
||||
ch_palettemode->add("Custom");
|
||||
ch_palettemode->value(conf.video_palette_mode);
|
||||
ch_palettemode->callback(cb_palettemode);
|
||||
|
||||
Fl_Choice *ch_decoder = new Fl_Choice(200, 155, 160, 25, "YUV Decoder");
|
||||
ch_decoder->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_decoder->add("Consumer");
|
||||
ch_decoder->add("Canonical");
|
||||
ch_decoder->add("Alternative");
|
||||
ch_decoder->value(conf.video_decoder);
|
||||
ch_decoder->callback(cb_decoder);
|
||||
|
||||
Fl_Hor_Value_Slider *sld_brightness = new Fl_Hor_Value_Slider(20, 210, 160, 25, "Brightness");
|
||||
sld_brightness->align(FL_ALIGN_TOP_LEFT);
|
||||
sld_brightness->bounds(-100, 100);
|
||||
sld_brightness->box(FL_FLAT_BOX);
|
||||
sld_brightness->callback(cb_brightness);
|
||||
sld_brightness->step(1);
|
||||
sld_brightness->selection_color(NstGreen);
|
||||
sld_brightness->type(FL_HOR_NICE_SLIDER);
|
||||
sld_brightness->value(conf.video_brightness);
|
||||
|
||||
Fl_Hor_Value_Slider *sld_saturation = new Fl_Hor_Value_Slider(20, 250, 160, 25, "Saturation");
|
||||
sld_saturation->align(FL_ALIGN_TOP_LEFT);
|
||||
sld_saturation->bounds(-100, 100);
|
||||
sld_saturation->box(FL_FLAT_BOX);
|
||||
sld_saturation->callback(cb_saturation);
|
||||
sld_saturation->step(1);
|
||||
sld_saturation->selection_color(NstGreen);
|
||||
sld_saturation->type(FL_HOR_NICE_SLIDER);
|
||||
sld_saturation->value(conf.video_saturation);
|
||||
|
||||
Fl_Hor_Value_Slider *sld_contrast = new Fl_Hor_Value_Slider(20, 290, 160, 25, "Contrast");
|
||||
sld_contrast->align(FL_ALIGN_TOP_LEFT);
|
||||
sld_contrast->bounds(-100, 100);
|
||||
sld_contrast->box(FL_FLAT_BOX);
|
||||
sld_contrast->callback(cb_contrast);
|
||||
sld_contrast->step(1);
|
||||
sld_contrast->selection_color(NstGreen);
|
||||
sld_contrast->type(FL_HOR_NICE_SLIDER);
|
||||
sld_contrast->value(conf.video_contrast);
|
||||
|
||||
Fl_Hor_Value_Slider *sld_hue = new Fl_Hor_Value_Slider(20, 330, 160, 25, "Hue");
|
||||
sld_hue->align(FL_ALIGN_TOP_LEFT);
|
||||
sld_hue->bounds(-45, 45);
|
||||
sld_hue->box(FL_FLAT_BOX);
|
||||
sld_hue->callback(cb_hue);
|
||||
sld_hue->step(1);
|
||||
sld_hue->selection_color(NstGreen);
|
||||
sld_hue->type(FL_HOR_NICE_SLIDER);
|
||||
sld_hue->value(conf.video_hue);
|
||||
|
||||
Fl_Check_Button *chk_xbrpixblend = new Fl_Check_Button(200, 210, 160, 25, "xBR Pixel Blending");
|
||||
chk_xbrpixblend->value(conf.video_xbr_pixel_blending);
|
||||
chk_xbrpixblend->callback(cb_xbrpixblend);
|
||||
|
||||
Fl_Check_Button *chk_linearfilter = new Fl_Check_Button(200, 235, 160, 25, "Linear Filter");
|
||||
chk_linearfilter->value(conf.video_linear_filter);
|
||||
chk_linearfilter->callback(cb_linearfilter);
|
||||
|
||||
Fl_Check_Button *chk_tvaspect = new Fl_Check_Button(200, 260, 160, 25, "TV Aspect Ratio");
|
||||
chk_tvaspect->value(conf.video_tv_aspect);
|
||||
chk_tvaspect->callback(cb_tvaspect);
|
||||
|
||||
Fl_Check_Button *chk_unmask_overscan = new Fl_Check_Button(200, 285, 160, 25, "Unmask Overscan");
|
||||
chk_unmask_overscan->value(conf.video_unmask_overscan);
|
||||
chk_unmask_overscan->callback(cb_unmask_overscan);
|
||||
|
||||
Fl_Check_Button *chk_unlimited_sprites = new Fl_Check_Button(200, 310, 160, 25, "Unlimited Sprites");
|
||||
chk_unlimited_sprites->value(conf.video_unlimited_sprites);
|
||||
chk_unlimited_sprites->callback(cb_unlimited_sprites);
|
||||
|
||||
vtab->end();
|
||||
|
||||
Fl_Group *atab = new Fl_Group(10, 30, 380, 360, "&Audio");
|
||||
|
||||
Fl_Choice *ch_samplerate = new Fl_Choice(20, 55, 160, 25, "Sample Rate");
|
||||
ch_samplerate->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_samplerate->add("11025Hz");
|
||||
ch_samplerate->add("22050Hz");
|
||||
ch_samplerate->add("44100Hz");
|
||||
ch_samplerate->add("48000Hz");
|
||||
ch_samplerate->add("96000Hz");
|
||||
switch (conf.audio_sample_rate) {
|
||||
case 11025: ch_samplerate->value(0); break;
|
||||
case 22050: ch_samplerate->value(1); break;
|
||||
case 44100: ch_samplerate->value(2); break;
|
||||
case 48000: ch_samplerate->value(3); break;
|
||||
case 96000: ch_samplerate->value(4); break;
|
||||
default: ch_samplerate->value(3); break;
|
||||
}
|
||||
ch_samplerate->callback(cb_samplerate);
|
||||
|
||||
Fl_Check_Button *chk_stereo = new Fl_Check_Button(200, 55, 160, 25, "Stereo");
|
||||
chk_stereo->value(conf.audio_stereo);
|
||||
chk_stereo->callback(cb_stereo);
|
||||
|
||||
dial_vall = new Fl_Dial(20, 100, 100, 100, "All");
|
||||
dial_vall->bounds(0, 100);
|
||||
dial_vall->step(1);
|
||||
dial_vall->color(NstPurple);
|
||||
dial_vall->selection_color(NstGreen);
|
||||
dial_vall->callback(cb_volume, 0);
|
||||
dial_vall->value(conf.audio_volume);
|
||||
|
||||
dial_vsq1 = new Fl_Dial(130, 115, 40, 40, "SQ1");
|
||||
dial_vsq1->bounds(0, 100);
|
||||
dial_vsq1->step(1);
|
||||
dial_vsq1->color(NstGreen);
|
||||
dial_vsq1->selection_color(NstPurple);
|
||||
dial_vsq1->callback(cb_volume, 1);
|
||||
dial_vsq1->value(conf.audio_vol_sq1);
|
||||
|
||||
dial_vsq2 = new Fl_Dial(180, 115, 40, 40, "SQ2");
|
||||
dial_vsq2->bounds(0, 100);
|
||||
dial_vsq2->step(1);
|
||||
dial_vsq2->color(NstGreen);
|
||||
dial_vsq2->selection_color(NstPurple);
|
||||
dial_vsq2->callback(cb_volume, 2);
|
||||
dial_vsq2->value(conf.audio_vol_sq2);
|
||||
|
||||
dial_vtri = new Fl_Dial(230, 115, 40, 40, "TRI");
|
||||
dial_vtri->bounds(0, 100);
|
||||
dial_vtri->step(1);
|
||||
dial_vtri->color(NstGreen);
|
||||
dial_vtri->selection_color(NstPurple);
|
||||
dial_vtri->callback(cb_volume, 3);
|
||||
dial_vtri->value(conf.audio_vol_tri);
|
||||
|
||||
dial_vnoise = new Fl_Dial(280, 115, 40, 40, "NOISE");
|
||||
dial_vnoise->bounds(0, 100);
|
||||
dial_vnoise->step(1);
|
||||
dial_vnoise->color(NstGreen);
|
||||
dial_vnoise->selection_color(NstPurple);
|
||||
dial_vnoise->callback(cb_volume, 4);
|
||||
dial_vnoise->value(conf.audio_vol_noise);
|
||||
|
||||
dial_vdpcm = new Fl_Dial(330, 115, 40, 40, "DPCM");
|
||||
dial_vdpcm->bounds(0, 100);
|
||||
dial_vdpcm->step(1);
|
||||
dial_vdpcm->color(NstGreen);
|
||||
dial_vdpcm->selection_color(NstPurple);
|
||||
dial_vdpcm->callback(cb_volume, 5);
|
||||
dial_vdpcm->value(conf.audio_vol_dpcm);
|
||||
|
||||
dial_vfds = new Fl_Dial(80, 225, 40, 40, "FDS");
|
||||
dial_vfds->bounds(0, 100);
|
||||
dial_vfds->step(1);
|
||||
dial_vfds->color(NstGreen);
|
||||
dial_vfds->selection_color(NstPurple);
|
||||
dial_vfds->callback(cb_volume, 6);
|
||||
dial_vfds->value(conf.audio_vol_fds);
|
||||
|
||||
dial_vmmc5 = new Fl_Dial(130, 225, 40, 40, "MMC5");
|
||||
dial_vmmc5->bounds(0, 100);
|
||||
dial_vmmc5->step(1);
|
||||
dial_vmmc5->color(NstGreen);
|
||||
dial_vmmc5->selection_color(NstPurple);
|
||||
dial_vmmc5->callback(cb_volume, 7);
|
||||
dial_vmmc5->value(conf.audio_vol_mmc5);
|
||||
|
||||
dial_vvrc6 = new Fl_Dial(180, 225, 40, 40, "VRC6");
|
||||
dial_vvrc6->bounds(0, 100);
|
||||
dial_vvrc6->step(1);
|
||||
dial_vvrc6->color(NstGreen);
|
||||
dial_vvrc6->selection_color(NstPurple);
|
||||
dial_vvrc6->callback(cb_volume, 8);
|
||||
dial_vvrc6->value(conf.audio_vol_vrc6);
|
||||
|
||||
dial_vvrc7 = new Fl_Dial(230, 225, 40, 40, "VRC7");
|
||||
dial_vvrc7->bounds(0, 100);
|
||||
dial_vvrc7->step(1);
|
||||
dial_vvrc7->color(NstGreen);
|
||||
dial_vvrc7->selection_color(NstPurple);
|
||||
dial_vvrc7->callback(cb_volume, 9);
|
||||
dial_vvrc7->value(conf.audio_vol_vrc7);
|
||||
|
||||
dial_vn163 = new Fl_Dial(280, 225, 40, 40, "N163");
|
||||
dial_vn163->bounds(0, 100);
|
||||
dial_vn163->step(1);
|
||||
dial_vn163->color(NstGreen);
|
||||
dial_vn163->selection_color(NstPurple);
|
||||
dial_vn163->callback(cb_volume, 10);
|
||||
dial_vn163->value(conf.audio_vol_n163);
|
||||
|
||||
dial_vs5b = new Fl_Dial(330, 225, 40, 40, "S5B");
|
||||
dial_vs5b->bounds(0, 100);
|
||||
dial_vs5b->step(1);
|
||||
dial_vs5b->color(NstGreen);
|
||||
dial_vs5b->selection_color(NstPurple);
|
||||
dial_vs5b->callback(cb_volume, 11);
|
||||
dial_vs5b->value(conf.audio_vol_s5b);
|
||||
|
||||
atab->end();
|
||||
|
||||
Fl_Group *itab = new Fl_Group(10, 30, 380, 360, "&Input");
|
||||
|
||||
Fl_Button *btn_icfg_u = new Fl_Button(70, 55, 30, 24, "U");
|
||||
btn_icfg_u->callback(cb_icfg, 0);
|
||||
btn_icfg_u->color(NstBlueGrey);
|
||||
btn_icfg_u->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_d = new Fl_Button(70, 115, 30, 24, "D");
|
||||
btn_icfg_d->callback(cb_icfg, 1);
|
||||
btn_icfg_d->color(NstBlueGrey);
|
||||
btn_icfg_d->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_l = new Fl_Button(30, 85, 30, 24, "L");
|
||||
btn_icfg_l->callback(cb_icfg, 2);
|
||||
btn_icfg_l->color(NstBlueGrey);
|
||||
btn_icfg_l->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_r = new Fl_Button(110, 85, 30, 24, "R");
|
||||
btn_icfg_r->callback(cb_icfg, 3);
|
||||
btn_icfg_r->color(NstBlueGrey);
|
||||
btn_icfg_r->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_slct = new Fl_Button(150, 85, 60, 24, "Select");
|
||||
btn_icfg_slct->callback(cb_icfg, 4);
|
||||
btn_icfg_slct->color(NstGreen);
|
||||
btn_icfg_slct->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_strt = new Fl_Button(220, 85, 60, 24, "Start");
|
||||
btn_icfg_strt->callback(cb_icfg, 5);
|
||||
btn_icfg_strt->color(NstGreen);
|
||||
btn_icfg_strt->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_a = new Fl_Button(330, 100, 30, 24, "A");
|
||||
btn_icfg_a->callback(cb_icfg, 6);
|
||||
btn_icfg_a->color(NstRed);
|
||||
btn_icfg_a->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_b = new Fl_Button(290, 100, 30, 24, "B");
|
||||
btn_icfg_b->callback(cb_icfg, 7);
|
||||
btn_icfg_b->color(NstRed);
|
||||
btn_icfg_b->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_ta = new Fl_Button(330, 65, 30, 24, "TA");
|
||||
btn_icfg_ta->callback(cb_icfg, 8);
|
||||
btn_icfg_ta->color(NstRed);
|
||||
btn_icfg_ta->labelcolor(NstLightGrey);
|
||||
|
||||
Fl_Button *btn_icfg_tb = new Fl_Button(290, 65, 30, 24, "TB");
|
||||
btn_icfg_tb->callback(cb_icfg, 9);
|
||||
btn_icfg_tb->color(NstRed);
|
||||
btn_icfg_tb->labelcolor(NstLightGrey);
|
||||
|
||||
icfg = new NstInputConfWindow(110, 55, 170, 24, "Input Config");
|
||||
icfg->color(NstPurple);
|
||||
icfg->hide();
|
||||
icfg->text = new Fl_Box(0, 0, 0, 24);
|
||||
icfg->text->align(FL_ALIGN_RIGHT);
|
||||
icfg->text->labelcolor(NstLightGrey);
|
||||
icfg->player = icfg->btn = icfg->device = 0;
|
||||
icfg->end();
|
||||
|
||||
Fl_Choice *ch_player = new Fl_Choice(20, 180, 160, 25, "Player");
|
||||
ch_player->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_player->add("Player 1");
|
||||
ch_player->add("Player 2");
|
||||
ch_player->value(0);
|
||||
ch_player->callback(cb_player);
|
||||
|
||||
Fl_Choice *ch_idevice = new Fl_Choice(20, 230, 160, 25, "Input Device");
|
||||
ch_idevice->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_idevice->add("Keyboard");
|
||||
ch_idevice->add("Joystick");
|
||||
ch_idevice->value(0);
|
||||
ch_idevice->callback(cb_idevice);
|
||||
|
||||
Fl_Hor_Value_Slider *sld_turbopulse = new Fl_Hor_Value_Slider(200, 180, 160, 25, "Turbo Pulse");
|
||||
sld_turbopulse->align(FL_ALIGN_TOP_LEFT);
|
||||
sld_turbopulse->bounds(2, 9);
|
||||
sld_turbopulse->box(FL_FLAT_BOX);
|
||||
sld_turbopulse->callback(cb_turbopulse);
|
||||
sld_turbopulse->step(1);
|
||||
sld_turbopulse->selection_color(NstGreen);
|
||||
sld_turbopulse->type(FL_HOR_NICE_SLIDER);
|
||||
sld_turbopulse->value(conf.timing_turbopulse);
|
||||
|
||||
itab->end();
|
||||
|
||||
Fl_Group *mtab = new Fl_Group(10, 30, 380, 360, "&Misc");
|
||||
|
||||
Fl_Choice *ch_default_system = new Fl_Choice(20, 55, 160, 25, "Default System");
|
||||
ch_default_system->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_default_system->add("Auto");
|
||||
ch_default_system->add("NTSC");
|
||||
ch_default_system->add("PAL");
|
||||
ch_default_system->add("Famicom");
|
||||
ch_default_system->add("Dendy");
|
||||
ch_default_system->value(conf.misc_default_system);
|
||||
ch_default_system->callback(cb_default_system);
|
||||
|
||||
Fl_Choice *ch_power_state = new Fl_Choice(20, 105, 160, 25, "RAM Power-on State");
|
||||
ch_power_state->align(FL_ALIGN_TOP_LEFT);
|
||||
ch_power_state->add("0x00");
|
||||
ch_power_state->add("0xFF");
|
||||
ch_power_state->add("Random");
|
||||
ch_power_state->value(conf.misc_power_state);
|
||||
ch_power_state->callback(cb_power_state);
|
||||
|
||||
Fl_Hor_Value_Slider *sld_ffspeed = new Fl_Hor_Value_Slider(20, 160, 160, 25, "Fast-Forward Speed");
|
||||
sld_ffspeed->align(FL_ALIGN_TOP_LEFT);
|
||||
sld_ffspeed->bounds(1, 8);
|
||||
sld_ffspeed->box(FL_FLAT_BOX);
|
||||
sld_ffspeed->callback(cb_ffspeed);
|
||||
sld_ffspeed->step(1);
|
||||
sld_ffspeed->selection_color(NstGreen);
|
||||
sld_ffspeed->type(FL_HOR_NICE_SLIDER);
|
||||
sld_ffspeed->value(conf.timing_ffspeed);
|
||||
|
||||
Fl_Check_Button *chk_soft_patching = new Fl_Check_Button(200, 55, 185, 25, "Auto Soft Patching");
|
||||
chk_soft_patching->value(conf.misc_soft_patching);
|
||||
chk_soft_patching->callback(cb_soft_patching);
|
||||
|
||||
Fl_Check_Button *chk_genie_distortion = new Fl_Check_Button(200, 80, 185, 25, "Genie Sound Distortion");
|
||||
chk_genie_distortion->value(conf.misc_genie_distortion);
|
||||
chk_genie_distortion->callback(cb_genie_distortion);
|
||||
|
||||
Fl_Check_Button *chk_disable_cursor = new Fl_Check_Button(200, 105, 185, 25, "Disable Cursor");
|
||||
chk_disable_cursor->value(conf.misc_disable_cursor);
|
||||
chk_disable_cursor->callback(cb_disable_cursor);
|
||||
|
||||
Fl_Check_Button *chk_disable_cursor_special = new Fl_Check_Button(200, 130, 185, 25, "Disable Special Cursor");
|
||||
chk_disable_cursor_special->value(conf.misc_disable_cursor_special);
|
||||
chk_disable_cursor_special->callback(cb_disable_cursor_special);
|
||||
|
||||
mtab->end();
|
||||
|
||||
tabs->end();
|
||||
|
||||
Fl_Button *btn_ok = new Fl_Button(350, 370, 40, 24, "&OK");
|
||||
btn_ok->callback(cb_ok, 0);
|
||||
this->end();
|
||||
}
|
31
source/fltkui/fltkui_config.h
Normal file
31
source/fltkui/fltkui_config.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef _FLTKUI_CONFIG_H_
|
||||
#define _FLTKUI_CONFIG_H_
|
||||
|
||||
class NstConfWindow : public Fl_Double_Window {
|
||||
private:
|
||||
bool icfg_running;
|
||||
|
||||
public:
|
||||
NstConfWindow(int w, int h, const char* t) : Fl_Double_Window(w, h, t) { }
|
||||
virtual ~NstConfWindow() { }
|
||||
|
||||
void populate();
|
||||
};
|
||||
|
||||
class NstInputConfWindow : public Fl_Double_Window {
|
||||
private:
|
||||
int handle(int e);
|
||||
|
||||
public:
|
||||
NstInputConfWindow(int x, int y, int w, int h, const char* t) : Fl_Double_Window(x, y, w, h, t) {
|
||||
box(FL_DOWN_BOX);
|
||||
}
|
||||
virtual ~NstInputConfWindow() { }
|
||||
|
||||
Fl_Box *text;
|
||||
int btn;
|
||||
int player;
|
||||
int device; // Keyboard or Joystick
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,42 +1,55 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2018 R. Danbrook
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2012-2016 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Gl_Window.H>
|
||||
|
||||
#include <SDL.h>
|
||||
#include "gtkui/gtkui.h"
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "video.h"
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
|
||||
#include "video.h"
|
||||
#include "ini.h"
|
||||
|
||||
#include "sdlinput.h"
|
||||
#include "fltkui.h"
|
||||
|
||||
static SDL_Joystick *joystick;
|
||||
gamepad_t player[NUMGAMEPADS];
|
||||
static inputsettings_t inputconf;
|
||||
inputsettings_t inputconf;
|
||||
static char inputconfpath[256];
|
||||
|
||||
static turbo_t turbostate;
|
||||
static turbo_t turbotoggle;
|
||||
|
||||
extern Emulator emulator;
|
||||
extern nstpaths_t nstpaths;
|
||||
|
||||
extern Emulator emulator;
|
||||
extern Input::Controllers *cNstPads;
|
||||
|
||||
extern int drawtext;
|
||||
|
||||
static unsigned char nescodes[TOTALBUTTONS] = {
|
||||
|
@ -62,22 +75,241 @@ static unsigned char nescodes[TOTALBUTTONS] = {
|
|||
Input::Controllers::Pad::B
|
||||
};
|
||||
|
||||
extern Emulator emulator;
|
||||
extern nstpaths_t nstpaths;
|
||||
void nst_input_init() {
|
||||
// Initialize input
|
||||
char controller[32];
|
||||
|
||||
for (int i = 0; i < NUMGAMEPADS; i++) {
|
||||
Input(emulator).AutoSelectController(i);
|
||||
|
||||
switch(Input(emulator).GetConnectedController(i)) {
|
||||
case Input::UNCONNECTED:
|
||||
snprintf(controller, sizeof(controller), "%s", "Unconnected");
|
||||
break;
|
||||
case Input::PAD1:
|
||||
case Input::PAD2:
|
||||
case Input::PAD3:
|
||||
case Input::PAD4:
|
||||
snprintf(controller, sizeof(controller), "%s", "Standard Pad");
|
||||
break;
|
||||
case Input::ZAPPER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Zapper");
|
||||
break;
|
||||
case Input::PADDLE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Arkanoid Paddle");
|
||||
break;
|
||||
case Input::POWERPAD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Power Pad");
|
||||
break;
|
||||
case Input::POWERGLOVE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Power Glove");
|
||||
break;
|
||||
case Input::MOUSE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Mouse");
|
||||
break;
|
||||
case Input::ROB:
|
||||
snprintf(controller, sizeof(controller), "%s", "R.O.B.");
|
||||
break;
|
||||
case Input::FAMILYTRAINER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Family Trainer");
|
||||
break;
|
||||
case Input::FAMILYKEYBOARD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Family Keyboard");
|
||||
break;
|
||||
case Input::SUBORKEYBOARD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Subor Keyboard");
|
||||
break;
|
||||
case Input::DOREMIKKOKEYBOARD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Doremikko Keyboard");
|
||||
break;
|
||||
case Input::HORITRACK:
|
||||
snprintf(controller, sizeof(controller), "%s", "Hori Track");
|
||||
break;
|
||||
case Input::PACHINKO:
|
||||
snprintf(controller, sizeof(controller), "%s", "Pachinko");
|
||||
break;
|
||||
case Input::OEKAKIDSTABLET:
|
||||
snprintf(controller, sizeof(controller), "%s", "Oeka Kids Tablet");
|
||||
break;
|
||||
case Input::KONAMIHYPERSHOT:
|
||||
snprintf(controller, sizeof(controller), "%s", "Konami Hypershot");
|
||||
break;
|
||||
case Input::BANDAIHYPERSHOT:
|
||||
snprintf(controller, sizeof(controller), "%s", "Bandai Hypershot");
|
||||
break;
|
||||
case Input::CRAZYCLIMBER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Crazy Climber");
|
||||
break;
|
||||
case Input::MAHJONG:
|
||||
snprintf(controller, sizeof(controller), "%s", "Mahjong");
|
||||
break;
|
||||
case Input::EXCITINGBOXING:
|
||||
snprintf(controller, sizeof(controller), "%s", "Exciting Boxing");
|
||||
break;
|
||||
case Input::TOPRIDER:
|
||||
snprintf(controller, sizeof(controller), "%s", "Top Rider");
|
||||
break;
|
||||
case Input::POKKUNMOGURAA:
|
||||
snprintf(controller, sizeof(controller), "%s", "Pokkun Moguraa");
|
||||
break;
|
||||
case Input::PARTYTAP:
|
||||
snprintf(controller, sizeof(controller), "%s", "PartyTap");
|
||||
break;
|
||||
case Input::TURBOFILE:
|
||||
snprintf(controller, sizeof(controller), "%s", "Turbo File");
|
||||
break;
|
||||
case Input::BARCODEWORLD:
|
||||
snprintf(controller, sizeof(controller), "%s", "Barcode World");
|
||||
break;
|
||||
default:
|
||||
snprintf(controller, sizeof(controller), "%s", "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Port %d: %s\n", i + 1, controller);
|
||||
}
|
||||
}
|
||||
|
||||
void nst_input_inject(Input::Controllers *controllers, nesinput_t input) {
|
||||
// Insert the input signal into the NES
|
||||
if(controllers == NULL) { return; }
|
||||
|
||||
if (input.pressed) {
|
||||
controllers->pad[input.player].buttons |= input.nescode;
|
||||
|
||||
if (input.turboa) { input.player == 0 ? turbostate.p1a = true : turbostate.p2a = true; }
|
||||
if (input.turbob) { input.player == 0 ? turbostate.p1b = true : turbostate.p2b = true; }
|
||||
}
|
||||
else {
|
||||
controllers->pad[input.player].buttons &= ~input.nescode;
|
||||
|
||||
if (input.turboa) { input.player == 0 ? turbostate.p1a = false : turbostate.p2a = false; }
|
||||
if (input.turbob) { input.player == 0 ? turbostate.p1b = false : turbostate.p2b = false; }
|
||||
}
|
||||
}
|
||||
|
||||
void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y) {
|
||||
// Insert input signal for Zappers
|
||||
if(controllers == NULL) { return; }
|
||||
|
||||
double xaspect;
|
||||
double yaspect;
|
||||
|
||||
if (s) {
|
||||
// Get X coords
|
||||
if (conf.video_filter == 1) { // NTSC
|
||||
xaspect = (double)(Video::Output::WIDTH) / (double)(Video::Output::NTSC_WIDTH / 2);
|
||||
}
|
||||
else if (conf.video_tv_aspect) {
|
||||
xaspect = (double)(Video::Output::WIDTH) / (double)(TV_WIDTH);
|
||||
}
|
||||
else { xaspect = 1.0; }
|
||||
|
||||
dimensions_t rendersize = nst_video_get_dimensions_render();
|
||||
dimensions_t screensize = nst_video_get_dimensions_screen();
|
||||
|
||||
// Calculate fullscreen X coords
|
||||
if (conf.video_fullscreen) {
|
||||
if (conf.video_stretch_aspect) {
|
||||
xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(screensize.w);
|
||||
}
|
||||
else {
|
||||
// Remove the same amount of pixels as the black area to the left of the screen
|
||||
x -= screensize.w / 2.0f - rendersize.w / 2.0f;
|
||||
xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(rendersize.w);
|
||||
}
|
||||
}
|
||||
controllers->zapper.x = (int)(x * xaspect) / conf.video_scale_factor;
|
||||
|
||||
// Get Y coords
|
||||
if (conf.video_unmask_overscan) {
|
||||
controllers->zapper.y = y / conf.video_scale_factor;
|
||||
}
|
||||
else {
|
||||
controllers->zapper.y = (y + OVERSCAN_TOP * conf.video_scale_factor) / conf.video_scale_factor;
|
||||
}
|
||||
|
||||
// Calculate fullscreen Y coords
|
||||
if (conf.video_fullscreen) {
|
||||
yaspect = (double)(conf.video_scale_factor * Video::Output::HEIGHT) / (double)(screensize.h);
|
||||
controllers->zapper.y = (y * yaspect) / conf.video_scale_factor;
|
||||
}
|
||||
|
||||
// Offscreen
|
||||
if (b != 1) { controllers->zapper.x = ~1U; }
|
||||
|
||||
controllers->zapper.fire = true;
|
||||
}
|
||||
else { controllers->zapper.fire = false; }
|
||||
}
|
||||
|
||||
void nst_input_turbo_init() {
|
||||
// Initialize the turbo button states
|
||||
turbostate.p1a = turbotoggle.p1a = 0;
|
||||
turbostate.p1b = turbotoggle.p1b = 0;
|
||||
turbostate.p2a = turbotoggle.p2a = 0;
|
||||
turbostate.p2b = turbotoggle.p2b = 0;
|
||||
}
|
||||
|
||||
void nst_input_turbo_pulse(Input::Controllers *controllers) {
|
||||
// Pulse the turbo buttons if they're pressed
|
||||
if (turbostate.p1a) {
|
||||
turbotoggle.p1a++;
|
||||
if (turbotoggle.p1a >= conf.timing_turbopulse) {
|
||||
turbotoggle.p1a = 0;
|
||||
controllers->pad[0].buttons &= ~Input::Controllers::Pad::A;
|
||||
}
|
||||
else { controllers->pad[0].buttons |= Input::Controllers::Pad::A; }
|
||||
}
|
||||
|
||||
if (turbostate.p1b) {
|
||||
turbotoggle.p1b++;
|
||||
if (turbotoggle.p1b >= conf.timing_turbopulse) {
|
||||
turbotoggle.p1b = 0;
|
||||
controllers->pad[0].buttons &= ~Input::Controllers::Pad::B;
|
||||
}
|
||||
else { controllers->pad[0].buttons |= Input::Controllers::Pad::B; }
|
||||
}
|
||||
|
||||
if (turbostate.p2a) {
|
||||
turbotoggle.p2a++;
|
||||
if (turbotoggle.p2a >= conf.timing_turbopulse) {
|
||||
turbotoggle.p2a = 0;
|
||||
controllers->pad[1].buttons &= ~Input::Controllers::Pad::A;
|
||||
}
|
||||
else { controllers->pad[1].buttons |= Input::Controllers::Pad::A; }
|
||||
}
|
||||
|
||||
if (turbostate.p2b) {
|
||||
turbotoggle.p2b++;
|
||||
if (turbotoggle.p2b >= conf.timing_turbopulse) {
|
||||
turbotoggle.p2b = 0;
|
||||
controllers->pad[1].buttons &= ~Input::Controllers::Pad::B;
|
||||
}
|
||||
else { controllers->pad[1].buttons |= Input::Controllers::Pad::B; }
|
||||
}
|
||||
}
|
||||
|
||||
int nst_input_zapper_present() {
|
||||
// Check if a Zapper is presently connected
|
||||
if (Input(emulator).GetConnectedController(0) == Input::ZAPPER ||
|
||||
Input(emulator).GetConnectedController(1) == Input::ZAPPER) {
|
||||
return 1;
|
||||
}
|
||||
else { return 0; }
|
||||
}
|
||||
|
||||
void nstsdl_input_joysticks_detect() {
|
||||
// Initialize any joysticks
|
||||
fprintf(stderr, "%i joystick(s) found:\n", SDL_NumJoysticks());
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDL_NumJoysticks(); i++) {
|
||||
|
||||
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
||||
joystick = SDL_JoystickOpen(i);
|
||||
printf("%s\n", SDL_JoystickName(joystick));
|
||||
}
|
||||
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||
|
||||
|
||||
nst_input_turbo_init();
|
||||
}
|
||||
|
||||
|
@ -94,25 +326,25 @@ int nstsdl_input_checksign(int axisvalue) {
|
|||
void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event event) {
|
||||
// Match NES buttons to joystick input
|
||||
int j;
|
||||
|
||||
|
||||
nesinput_t input, reverseinput;
|
||||
|
||||
|
||||
input.nescode = 0x00;
|
||||
input.player = 0;
|
||||
input.pressed = 0;
|
||||
input.turboa = 0;
|
||||
input.turbob = 0;
|
||||
|
||||
|
||||
// This is for releasing opposing directions
|
||||
reverseinput.nescode = 0x00;
|
||||
reverseinput.player = 0;
|
||||
reverseinput.pressed = 0;
|
||||
|
||||
|
||||
SDL_Event buttons[TOTALBUTTONS] = {
|
||||
player[0].ju, player[0].jd, player[0].jl, player[0].jr,
|
||||
player[0].jselect, player[0].jstart, player[0].ja, player[0].jb,
|
||||
player[0].jta, player[0].jtb,
|
||||
|
||||
|
||||
player[1].ju, player[1].jd, player[1].jl, player[1].jr,
|
||||
player[1].jselect, player[1].jstart, player[1].ja, player[1].jb,
|
||||
player[1].jta, player[1].jtb
|
||||
|
@ -137,7 +369,7 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even
|
|||
}
|
||||
}
|
||||
input.pressed = event.jbutton.state;
|
||||
|
||||
|
||||
// Rewind
|
||||
if (event.jbutton.button == rw[0].jbutton.button && event.jbutton.which == rw[0].jbutton.which) { nst_set_rewind(0); }
|
||||
if (event.jbutton.button == rw[1].jbutton.button && event.jbutton.which == rw[1].jbutton.which) { nst_set_rewind(1); }
|
||||
|
@ -149,10 +381,10 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even
|
|||
case SDL_JOYHATMOTION:
|
||||
unsigned char hu, hd, hl, hr;
|
||||
hu = hd = hl = hr = 0;
|
||||
|
||||
|
||||
// Start a loop to check if input matches
|
||||
for (j = 0; j < TOTALBUTTONS; j++) {
|
||||
|
||||
|
||||
// Read value of each hat direction on current hat
|
||||
if (buttons[j].type == event.type
|
||||
&& buttons[j].jhat.which == event.jhat.which
|
||||
|
@ -164,9 +396,9 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even
|
|||
else if (buttons[j].jhat.value == SDL_HAT_DOWN) { hd = nescodes[j]; }
|
||||
else if (buttons[j].jhat.value == SDL_HAT_LEFT) { hl = nescodes[j]; }
|
||||
else if (buttons[j].jhat.value == SDL_HAT_RIGHT) { hr = nescodes[j]; }
|
||||
|
||||
|
||||
input.pressed = 1;
|
||||
|
||||
|
||||
// Make sure opposing hat positions are turned off
|
||||
switch(event.jhat.value) {
|
||||
case SDL_HAT_UP:
|
||||
|
@ -212,7 +444,7 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even
|
|||
// Handle axis input
|
||||
case SDL_JOYAXISMOTION:
|
||||
for (j = 0; j < TOTALBUTTONS; j++) {
|
||||
|
||||
|
||||
int nvalue = nstsdl_input_checksign(event.jaxis.value);
|
||||
|
||||
if (buttons[j].jaxis.axis == event.jaxis.axis
|
||||
|
@ -221,7 +453,7 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even
|
|||
&& buttons[j].jaxis.value == nvalue) {
|
||||
|
||||
if (j >= NUMBUTTONS) { input.player = reverseinput.player = 1; }
|
||||
|
||||
|
||||
input.nescode = nescodes[j];
|
||||
}
|
||||
|
||||
|
@ -229,23 +461,50 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even
|
|||
&& buttons[j].jaxis.which == event.jaxis.which
|
||||
&& buttons[j].jaxis.type == event.jaxis.type
|
||||
&& buttons[j].jaxis.value == !nvalue) {
|
||||
|
||||
|
||||
reverseinput.nescode = nescodes[j];
|
||||
}
|
||||
|
||||
if (abs(event.jaxis.value) > DEADZONE) { input.pressed = 1; }
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
nst_input_inject(controllers, reverseinput);
|
||||
nst_input_inject(controllers, input);
|
||||
}
|
||||
|
||||
void nstsdl_input_conf_defaults() {
|
||||
// Set default input config
|
||||
|
||||
inputconf.qsave1 = FL_F + 5;
|
||||
inputconf.qsave2 = FL_F + 6;
|
||||
inputconf.qload1 = FL_F + 7;
|
||||
inputconf.qload2 = FL_F + 8;
|
||||
inputconf.screenshot = FL_F + 9;
|
||||
inputconf.fdsflip = FL_F + 3;
|
||||
inputconf.fdsswitch = FL_F + 4;
|
||||
inputconf.insertcoin1 = FL_F + 1;
|
||||
inputconf.insertcoin2 = FL_F + 2;
|
||||
inputconf.reset = FL_F + 12;
|
||||
inputconf.ffspeed = '`';
|
||||
inputconf.rwstart = FL_BackSpace;
|
||||
inputconf.rwstop = '\\';
|
||||
inputconf.fullscreen = 'f';
|
||||
|
||||
player[0].u = FL_Up;
|
||||
player[0].d = FL_Down;
|
||||
player[0].l = FL_Left;
|
||||
player[0].r = FL_Right;
|
||||
player[0].select = FL_Shift_R;
|
||||
player[0].start = FL_Enter;
|
||||
player[0].a = 'z';
|
||||
player[0].b = 'a';
|
||||
player[0].ta = 'x';
|
||||
player[0].tb = 's';
|
||||
|
||||
player[0].ju = nstsdl_input_translate_string("j0h01");
|
||||
player[0].jd = nstsdl_input_translate_string("j0h04");
|
||||
player[0].jl = nstsdl_input_translate_string("j0h08");
|
||||
|
@ -256,12 +515,23 @@ void nstsdl_input_conf_defaults() {
|
|||
player[0].jb = nstsdl_input_translate_string("j0b0");
|
||||
player[0].jta = nstsdl_input_translate_string("j0b2");
|
||||
player[0].jtb = nstsdl_input_translate_string("j0b3");
|
||||
|
||||
|
||||
player[0].rwstart = nstsdl_input_translate_string("j0b4");
|
||||
player[0].rwstop = nstsdl_input_translate_string("j0b5");
|
||||
player[0].softreset = nstsdl_input_translate_string("j0b99");
|
||||
player[0].hardreset = nstsdl_input_translate_string("j0b99");
|
||||
|
||||
|
||||
player[1].u = 'i';
|
||||
player[1].d = 'j';
|
||||
player[1].l = 'k';
|
||||
player[1].r = 'l';
|
||||
player[1].select = FL_Shift_L;
|
||||
player[1].start = FL_Control_L;
|
||||
player[1].a = 'm';
|
||||
player[1].b = 'n';
|
||||
player[1].ta = 'b';
|
||||
player[1].tb = 'v';
|
||||
|
||||
player[1].ju = nstsdl_input_translate_string("j1h01");
|
||||
player[1].jd = nstsdl_input_translate_string("j1h04");
|
||||
player[1].jl = nstsdl_input_translate_string("j1h08");
|
||||
|
@ -274,80 +544,78 @@ void nstsdl_input_conf_defaults() {
|
|||
player[1].jtb = nstsdl_input_translate_string("j1b3");
|
||||
}
|
||||
|
||||
void nstsdl_input_conf_set(SDL_Event event, int type, int pnum, int counter) {
|
||||
void fltkui_input_conf_set(int kval, int pnum, int bnum) {
|
||||
// Set an input item to what was requested by configuration process
|
||||
if (type == 0) { // Keyboard
|
||||
switch(counter) {
|
||||
case 0: player[pnum].u = event.key.keysym.scancode; break;
|
||||
case 1: player[pnum].d = event.key.keysym.scancode; break;
|
||||
case 2: player[pnum].l = event.key.keysym.scancode; break;
|
||||
case 3: player[pnum].r = event.key.keysym.scancode; break;
|
||||
case 4: player[pnum].select = event.key.keysym.scancode; break;
|
||||
case 5: player[pnum].start = event.key.keysym.scancode; break;
|
||||
case 6: player[pnum].a = event.key.keysym.scancode; break;
|
||||
case 7: player[pnum].b = event.key.keysym.scancode; break;
|
||||
case 8: player[pnum].ta = event.key.keysym.scancode; break;
|
||||
case 9: player[pnum].tb = event.key.keysym.scancode; break;
|
||||
default: break;
|
||||
}
|
||||
switch (bnum) {
|
||||
case 0: player[pnum].u = kval; break;
|
||||
case 1: player[pnum].d = kval; break;
|
||||
case 2: player[pnum].l = kval; break;
|
||||
case 3: player[pnum].r = kval; break;
|
||||
case 4: player[pnum].select = kval; break;
|
||||
case 5: player[pnum].start = kval; break;
|
||||
case 6: player[pnum].a = kval; break;
|
||||
case 7: player[pnum].b = kval; break;
|
||||
case 8: player[pnum].ta = kval; break;
|
||||
case 9: player[pnum].tb = kval; break;
|
||||
default: break;
|
||||
}
|
||||
else if (type == 1) { // Joystick
|
||||
switch(counter) {
|
||||
case 0: player[pnum].ju = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 1: player[pnum].jd = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 2: player[pnum].jl = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 3: player[pnum].jr = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 4: player[pnum].jselect = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 5: player[pnum].jstart = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 6: player[pnum].ja = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 7: player[pnum].jb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 8: player[pnum].jta = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 9: player[pnum].jtb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void nstsdl_input_conf_set(SDL_Event event, int pnum, int bnum) {
|
||||
// Set an input item to what was requested by configuration process
|
||||
switch (bnum) {
|
||||
case 0: player[pnum].ju = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 1: player[pnum].jd = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 2: player[pnum].jl = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 3: player[pnum].jr = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 4: player[pnum].jselect = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 5: player[pnum].jstart = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 6: player[pnum].ja = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 7: player[pnum].jb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 8: player[pnum].jta = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
case 9: player[pnum].jtb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static int nstsdl_input_config_match(void* user, const char* section, const char* name, const char* value) {
|
||||
// Match values from input config file and populate live config
|
||||
inputsettings_t* pconfig = (inputsettings_t*)user;
|
||||
|
||||
|
||||
// User Interface
|
||||
if (MATCH("ui", "qsave1")) { pconfig->qsave1 = strdup(value); }
|
||||
else if (MATCH("ui", "qsave2")) { pconfig->qsave2 = strdup(value); }
|
||||
else if (MATCH("ui", "qload1")) { pconfig->qload1 = strdup(value); }
|
||||
else if (MATCH("ui", "qload2")) { pconfig->qload2 = strdup(value); }
|
||||
|
||||
else if (MATCH("ui", "screenshot")) { pconfig->screenshot = strdup(value); }
|
||||
|
||||
else if (MATCH("ui", "fdsflip")) { pconfig->fdsflip = strdup(value); }
|
||||
else if (MATCH("ui", "fdsswitch")) { pconfig->fdsswitch = strdup(value); }
|
||||
|
||||
else if (MATCH("ui", "insertcoin1")) { pconfig->insertcoin1 = strdup(value); }
|
||||
else if (MATCH("ui", "insertcoin2")) { pconfig->insertcoin2 = strdup(value); }
|
||||
|
||||
else if (MATCH("ui", "reset")) { pconfig->reset = strdup(value); }
|
||||
|
||||
else if (MATCH("ui", "ffspeed")) { pconfig->ffspeed = strdup(value); }
|
||||
else if (MATCH("ui", "rwstart")) { pconfig->rwstart = strdup(value); }
|
||||
else if (MATCH("ui", "rwstop")) { pconfig->rwstop = strdup(value); }
|
||||
|
||||
else if (MATCH("ui", "fullscreen")) { pconfig->fullscreen = strdup(value); }
|
||||
else if (MATCH("ui", "filter")) { pconfig->filter = strdup(value); }
|
||||
else if (MATCH("ui", "scalefactor")) { pconfig->scalefactor = strdup(value); }
|
||||
|
||||
if (MATCH("ui", "qsave1")) { pconfig->qsave1 = atoi(value); }
|
||||
else if (MATCH("ui", "qsave2")) { pconfig->qsave2 = atoi(value); }
|
||||
else if (MATCH("ui", "qload1")) { pconfig->qload1 = atoi(value); }
|
||||
else if (MATCH("ui", "qload2")) { pconfig->qload2 = atoi(value); }
|
||||
|
||||
else if (MATCH("ui", "screenshot")) { pconfig->screenshot = atoi(value); }
|
||||
|
||||
else if (MATCH("ui", "fdsflip")) { pconfig->fdsflip = atoi(value); }
|
||||
else if (MATCH("ui", "fdsswitch")) { pconfig->fdsswitch = atoi(value); }
|
||||
|
||||
else if (MATCH("ui", "insertcoin1")) { pconfig->insertcoin1 = atoi(value); }
|
||||
else if (MATCH("ui", "insertcoin2")) { pconfig->insertcoin2 = atoi(value); }
|
||||
|
||||
else if (MATCH("ui", "reset")) { pconfig->reset = atoi(value); }
|
||||
|
||||
else if (MATCH("ui", "ffspeed")) { pconfig->ffspeed = atoi(value); }
|
||||
else if (MATCH("ui", "rwstart")) { pconfig->rwstart = atoi(value); }
|
||||
else if (MATCH("ui", "rwstop")) { pconfig->rwstop = atoi(value); }
|
||||
|
||||
else if (MATCH("ui", "fullscreen")) { pconfig->fullscreen = atoi(value); }
|
||||
|
||||
// Player 1
|
||||
else if (MATCH("gamepad1", "kb_u")) { pconfig->kb_p1u = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_d")) { pconfig->kb_p1d = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_l")) { pconfig->kb_p1l = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_r")) { pconfig->kb_p1r = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_select")) { pconfig->kb_p1select = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_start")) { pconfig->kb_p1start = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_a")) { pconfig->kb_p1a = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_b")) { pconfig->kb_p1b = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_ta")) { pconfig->kb_p1ta = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_tb")) { pconfig->kb_p1tb = strdup(value); }
|
||||
|
||||
else if (MATCH("gamepad1", "kb_u")) { pconfig->kb_p1u = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_d")) { pconfig->kb_p1d = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_l")) { pconfig->kb_p1l = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_r")) { pconfig->kb_p1r = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_select")) { pconfig->kb_p1select = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_start")) { pconfig->kb_p1start = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_a")) { pconfig->kb_p1a = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_b")) { pconfig->kb_p1b = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_ta")) { pconfig->kb_p1ta = atoi(value); }
|
||||
else if (MATCH("gamepad1", "kb_tb")) { pconfig->kb_p1tb = atoi(value); }
|
||||
|
||||
else if (MATCH("gamepad1", "js_u")) { pconfig->js_p1u = strdup(value); }
|
||||
else if (MATCH("gamepad1", "js_d")) { pconfig->js_p1d = strdup(value); }
|
||||
else if (MATCH("gamepad1", "js_l")) { pconfig->js_p1l = strdup(value); }
|
||||
|
@ -358,7 +626,7 @@ static int nstsdl_input_config_match(void* user, const char* section, const char
|
|||
else if (MATCH("gamepad1", "js_b")) { pconfig->js_p1b = strdup(value); }
|
||||
else if (MATCH("gamepad1", "js_ta")) { pconfig->js_p1ta = strdup(value); }
|
||||
else if (MATCH("gamepad1", "js_tb")) { pconfig->js_p1tb = strdup(value); }
|
||||
|
||||
|
||||
else if (MATCH("gamepad1", "js_rwstart")) { pconfig->js_rwstart = strdup(value); }
|
||||
else if (MATCH("gamepad1", "js_rwstop")) { pconfig->js_rwstop = strdup(value); }
|
||||
|
||||
|
@ -366,17 +634,17 @@ static int nstsdl_input_config_match(void* user, const char* section, const char
|
|||
else if (MATCH("gamepad1", "js_hardreset")) { pconfig->js_hardreset = strdup(value); }
|
||||
|
||||
// Player 2
|
||||
else if (MATCH("gamepad2", "kb_u")) { pconfig->kb_p2u = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_d")) { pconfig->kb_p2d = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_l")) { pconfig->kb_p2l = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_r")) { pconfig->kb_p2r = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_select")) { pconfig->kb_p2select = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_start")) { pconfig->kb_p2start = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_a")) { pconfig->kb_p2a = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_b")) { pconfig->kb_p2b = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_ta")) { pconfig->kb_p2ta = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_tb")) { pconfig->kb_p2tb = strdup(value); }
|
||||
|
||||
else if (MATCH("gamepad2", "kb_u")) { pconfig->kb_p2u = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_d")) { pconfig->kb_p2d = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_l")) { pconfig->kb_p2l = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_r")) { pconfig->kb_p2r = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_select")) { pconfig->kb_p2select = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_start")) { pconfig->kb_p2start = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_a")) { pconfig->kb_p2a = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_b")) { pconfig->kb_p2b = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_ta")) { pconfig->kb_p2ta = atoi(value); }
|
||||
else if (MATCH("gamepad2", "kb_tb")) { pconfig->kb_p2tb = atoi(value); }
|
||||
|
||||
else if (MATCH("gamepad2", "js_u")) { pconfig->js_p2u = strdup(value); }
|
||||
else if (MATCH("gamepad2", "js_d")) { pconfig->js_p2d = strdup(value); }
|
||||
else if (MATCH("gamepad2", "js_l")) { pconfig->js_p2l = strdup(value); }
|
||||
|
@ -387,19 +655,30 @@ static int nstsdl_input_config_match(void* user, const char* section, const char
|
|||
else if (MATCH("gamepad2", "js_b")) { pconfig->js_p2b = strdup(value); }
|
||||
else if (MATCH("gamepad2", "js_ta")) { pconfig->js_p2ta = strdup(value); }
|
||||
else if (MATCH("gamepad2", "js_tb")) { pconfig->js_p2tb = strdup(value); }
|
||||
|
||||
|
||||
else { return 0; }
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void nstsdl_input_conf_read() {
|
||||
// Read the input config file
|
||||
snprintf(inputconfpath, sizeof(inputconfpath), "%sinput.conf", nstpaths.nstconfdir);
|
||||
|
||||
|
||||
if (ini_parse(inputconfpath, nstsdl_input_config_match, &inputconf) < 0) {
|
||||
fprintf(stderr, "Failed to load input config file %s: Using defaults.\n", inputconfpath);
|
||||
}
|
||||
else { // Map the input settings from the config file
|
||||
player[0].u = inputconf.kb_p1u;
|
||||
player[0].d = inputconf.kb_p1d;
|
||||
player[0].l = inputconf.kb_p1l;
|
||||
player[0].r = inputconf.kb_p1r;
|
||||
player[0].select = inputconf.kb_p1select;
|
||||
player[0].start = inputconf.kb_p1start;
|
||||
player[0].a = inputconf.kb_p1a;
|
||||
player[0].b = inputconf.kb_p1b;
|
||||
player[0].ta = inputconf.kb_p1ta;
|
||||
player[0].tb = inputconf.kb_p1tb;
|
||||
|
||||
player[0].ju = nstsdl_input_translate_string(inputconf.js_p1u);
|
||||
player[0].jd = nstsdl_input_translate_string(inputconf.js_p1d);
|
||||
player[0].jl = nstsdl_input_translate_string(inputconf.js_p1l);
|
||||
|
@ -410,7 +689,7 @@ void nstsdl_input_conf_read() {
|
|||
player[0].jb = nstsdl_input_translate_string(inputconf.js_p1b);
|
||||
player[0].jta = nstsdl_input_translate_string(inputconf.js_p1ta);
|
||||
player[0].jtb = nstsdl_input_translate_string(inputconf.js_p1tb);
|
||||
|
||||
|
||||
if (inputconf.js_rwstart) { player[0].rwstart = nstsdl_input_translate_string(inputconf.js_rwstart); }
|
||||
if (inputconf.js_rwstop) { player[0].rwstop = nstsdl_input_translate_string(inputconf.js_rwstop); }
|
||||
|
||||
|
@ -418,6 +697,17 @@ void nstsdl_input_conf_read() {
|
|||
if (inputconf.js_hardreset) { player[0].hardreset = nstsdl_input_translate_string(inputconf.js_hardreset); }
|
||||
|
||||
// Player 2
|
||||
player[1].u = inputconf.kb_p2u;
|
||||
player[1].d = inputconf.kb_p2d;
|
||||
player[1].l = inputconf.kb_p2l;
|
||||
player[1].r = inputconf.kb_p2r;
|
||||
player[1].select = inputconf.kb_p2select;
|
||||
player[1].start = inputconf.kb_p2start;
|
||||
player[1].a = inputconf.kb_p2a;
|
||||
player[1].b = inputconf.kb_p2b;
|
||||
player[1].ta = inputconf.kb_p2ta;
|
||||
player[1].tb = inputconf.kb_p2tb;
|
||||
|
||||
player[1].ju = nstsdl_input_translate_string(inputconf.js_p2u);
|
||||
player[1].jd = nstsdl_input_translate_string(inputconf.js_p2d);
|
||||
player[1].jl = nstsdl_input_translate_string(inputconf.js_p2l);
|
||||
|
@ -435,13 +725,39 @@ void nstsdl_input_conf_write() {
|
|||
// Write out the input configuration file
|
||||
FILE *fp = fopen(inputconfpath, "w");
|
||||
if (fp != NULL) {
|
||||
fprintf(fp, "; Nestopia UE SDL Input Configuration File\n\n");
|
||||
fprintf(fp, "; Nestopia UE Input Configuration File\n\n");
|
||||
fprintf(fp, "; Possible values for joystick input:\n; j[joystick number][a|b|h][button/hat/axis number][1/0 = +/- (axes only)]\n");
|
||||
fprintf(fp, "; Example: j0b3 = joystick 0, button 3. j1a11 = joystick 1, axis 1 +\n\n");
|
||||
fprintf(fp, "; Press Ctrl or Shift + [player number] to configure input in-game.\n; Ctrl for Keyboard, Shift for Joystick.\n");
|
||||
fprintf(fp, "; Example: Shift + 1 for Joystick input for Player 1\n\n");
|
||||
|
||||
|
||||
fprintf(fp, "[ui]\n");
|
||||
fprintf(fp, "qsave1=%d\n", inputconf.qsave1);
|
||||
fprintf(fp, "qsave2=%d\n", inputconf.qsave2);
|
||||
fprintf(fp, "qload1=%d\n", inputconf.qload1);
|
||||
fprintf(fp, "qload2=%d\n", inputconf.qload2);
|
||||
fprintf(fp, "screenshot=%d\n", inputconf.screenshot);
|
||||
fprintf(fp, "fdsflip=%d\n", inputconf.fdsflip);
|
||||
fprintf(fp, "fdsswitch=%d\n", inputconf.fdsswitch);
|
||||
fprintf(fp, "insertcoin1=%d\n", inputconf.insertcoin1);
|
||||
fprintf(fp, "insertcoin2=%d\n", inputconf.insertcoin2);
|
||||
fprintf(fp, "reset=%d\n", inputconf.reset);
|
||||
fprintf(fp, "ffspeed=%d\n", inputconf.ffspeed);
|
||||
fprintf(fp, "rwstart=%d\n", inputconf.rwstart);
|
||||
fprintf(fp, "rwstop=%d\n", inputconf.rwstop);
|
||||
fprintf(fp, "fullscreen=%d\n", inputconf.fullscreen);
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
fprintf(fp, "[gamepad1]\n");
|
||||
fprintf(fp, "kb_u=%d\n", player[0].u);
|
||||
fprintf(fp, "kb_d=%d\n", player[0].d);
|
||||
fprintf(fp, "kb_l=%d\n", player[0].l);
|
||||
fprintf(fp, "kb_r=%d\n", player[0].r);
|
||||
fprintf(fp, "kb_select=%d\n", player[0].select);
|
||||
fprintf(fp, "kb_start=%d\n", player[0].start);
|
||||
fprintf(fp, "kb_a=%d\n", player[0].a);
|
||||
fprintf(fp, "kb_b=%d\n", player[0].b);
|
||||
fprintf(fp, "kb_ta=%d\n", player[0].ta);
|
||||
fprintf(fp, "kb_tb=%d\n", player[0].tb);
|
||||
|
||||
fprintf(fp, "js_u=%s\n", nstsdl_input_translate_event(player[0].ju));
|
||||
fprintf(fp, "js_d=%s\n", nstsdl_input_translate_event(player[0].jd));
|
||||
fprintf(fp, "js_l=%s\n", nstsdl_input_translate_event(player[0].jl));
|
||||
|
@ -452,14 +768,25 @@ void nstsdl_input_conf_write() {
|
|||
fprintf(fp, "js_b=%s\n", nstsdl_input_translate_event(player[0].jb));
|
||||
fprintf(fp, "js_ta=%s\n", nstsdl_input_translate_event(player[0].jta));
|
||||
fprintf(fp, "js_tb=%s\n", nstsdl_input_translate_event(player[0].jtb));
|
||||
|
||||
|
||||
fprintf(fp, "js_rwstart=%s\n", nstsdl_input_translate_event(player[0].rwstart));
|
||||
fprintf(fp, "js_rwstop=%s\n", nstsdl_input_translate_event(player[0].rwstop));
|
||||
fprintf(fp, "js_softreset=%s\n", nstsdl_input_translate_event(player[0].softreset));
|
||||
fprintf(fp, "js_hardreset=%s\n", nstsdl_input_translate_event(player[0].hardreset));
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
|
||||
fprintf(fp, "[gamepad2]\n");
|
||||
fprintf(fp, "kb_u=%d\n", player[1].u);
|
||||
fprintf(fp, "kb_d=%d\n", player[1].d);
|
||||
fprintf(fp, "kb_l=%d\n", player[1].l);
|
||||
fprintf(fp, "kb_r=%d\n", player[1].r);
|
||||
fprintf(fp, "kb_select=%d\n", player[1].select);
|
||||
fprintf(fp, "kb_start=%d\n", player[1].start);
|
||||
fprintf(fp, "kb_a=%d\n", player[1].a);
|
||||
fprintf(fp, "kb_b=%d\n", player[1].b);
|
||||
fprintf(fp, "kb_ta=%d\n", player[1].ta);
|
||||
fprintf(fp, "kb_tb=%d\n", player[1].tb);
|
||||
|
||||
fprintf(fp, "js_u=%s\n", nstsdl_input_translate_event(player[1].ju));
|
||||
fprintf(fp, "js_d=%s\n", nstsdl_input_translate_event(player[1].jd));
|
||||
fprintf(fp, "js_l=%s\n", nstsdl_input_translate_event(player[1].jl));
|
||||
|
@ -470,8 +797,7 @@ void nstsdl_input_conf_write() {
|
|||
fprintf(fp, "js_b=%s\n", nstsdl_input_translate_event(player[1].jb));
|
||||
fprintf(fp, "js_ta=%s\n", nstsdl_input_translate_event(player[1].jta));
|
||||
fprintf(fp, "js_tb=%s\n", nstsdl_input_translate_event(player[1].jtb));
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
@ -492,16 +818,16 @@ void nstsdl_input_process(Input::Controllers *controllers, SDL_Event event) {
|
|||
char* nstsdl_input_translate_event(SDL_Event event) {
|
||||
// Translate an SDL_Event to an inputcode
|
||||
static char inputcode[6];
|
||||
|
||||
|
||||
switch(event.type) {
|
||||
case SDL_JOYAXISMOTION:
|
||||
sprintf(inputcode, "j%da%d%d", event.jaxis.which, event.jaxis.axis, nstsdl_input_checksign(event.jaxis.value));
|
||||
break;
|
||||
|
||||
|
||||
case SDL_JOYHATMOTION:
|
||||
sprintf(inputcode, "j%dh%d%d", event.jhat.which, event.jhat.hat, event.jhat.value);
|
||||
break;
|
||||
|
||||
|
||||
case SDL_JOYBUTTONUP:
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
sprintf(inputcode, "j%db%d", event.jbutton.which, event.jbutton.button);
|
||||
|
@ -513,7 +839,7 @@ char* nstsdl_input_translate_event(SDL_Event event) {
|
|||
SDL_Event nstsdl_input_translate_string(const char *string) {
|
||||
// Translate an inputcode to an SDL_Event
|
||||
SDL_Event event;
|
||||
|
||||
|
||||
int type, axis, value;
|
||||
|
||||
int which = 0, whichdigits = 0;
|
||||
|
@ -530,7 +856,7 @@ SDL_Event nstsdl_input_translate_string(const char *string) {
|
|||
for (int i = 1; i <= whichdigits; i++) {
|
||||
which += (string[i] - '0') * (pow (10, (whichdigits - i)));
|
||||
}
|
||||
|
||||
|
||||
if ((unsigned char)string[whichdigits + 1] == 0x61) { // Axis
|
||||
axis = string[whichdigits + 2] - '0';
|
||||
value = string[whichdigits + 3] - '0';
|
||||
|
@ -547,7 +873,7 @@ SDL_Event nstsdl_input_translate_string(const char *string) {
|
|||
event.type = SDL_JOYBUTTONDOWN;
|
||||
event.jbutton.which = which;
|
||||
event.jbutton.button = value;
|
||||
|
||||
|
||||
}
|
||||
else if ((unsigned char)string[whichdigits + 1] == 0x68) { // Hat
|
||||
axis = string[whichdigits + 2] - '0';
|
||||
|
@ -560,7 +886,7 @@ SDL_Event nstsdl_input_translate_string(const char *string) {
|
|||
else {
|
||||
fprintf(stderr, "Malformed inputcode: %s\n", string);
|
||||
}
|
||||
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@ -568,10 +894,10 @@ void nstsdl_input_conf_button(int pnum, int bnum) {
|
|||
// Configure Inputs for single Joystick Buttons
|
||||
SDL_Event event, eventbuf;
|
||||
int axis = 0, axisnoise = 0, confrunning = 1;
|
||||
|
||||
|
||||
if (SDL_NumJoysticks() == 0) { return; }
|
||||
|
||||
while (confrunning) {
|
||||
while (gtk_events_pending()) { gtk_main_iteration(); }
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_JOYAXISMOTION) {
|
||||
if (abs(event.jaxis.value) >= DEADZONE) {
|
||||
|
@ -580,21 +906,66 @@ void nstsdl_input_conf_button(int pnum, int bnum) {
|
|||
axis = event.jaxis.axis;
|
||||
}
|
||||
else if (abs(event.jaxis.value) < DEADZONE && axisnoise && event.jaxis.axis == axis) {
|
||||
nstsdl_input_conf_set(eventbuf, 1, pnum, bnum);
|
||||
nstsdl_input_conf_set(eventbuf, pnum, bnum);
|
||||
axisnoise = 0;
|
||||
confrunning = 0;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_JOYHATMOTION) {
|
||||
if (event.jhat.value != SDL_HAT_CENTERED) {
|
||||
nstsdl_input_conf_set(event, 1, pnum, bnum);
|
||||
nstsdl_input_conf_set(event, pnum, bnum);
|
||||
confrunning = 0;
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_JOYBUTTONDOWN) {
|
||||
nstsdl_input_conf_set(event, 1, pnum, bnum);
|
||||
nstsdl_input_conf_set(event, pnum, bnum);
|
||||
confrunning = 0;
|
||||
}
|
||||
}
|
||||
SDL_Delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
void fltkui_input_process_key(int e) {
|
||||
nesinput_t input;
|
||||
|
||||
input.nescode = input.player = input.pressed = input.turboa = input.turbob = 0;
|
||||
|
||||
if (e == FL_KEYDOWN) {
|
||||
input.pressed = 1;
|
||||
if (Fl::event_key() == '`') nst_timing_set_ffspeed();
|
||||
else if (Fl::event_key() == inputconf.qsave1) nst_state_quicksave(0);
|
||||
else if (Fl::event_key() == inputconf.qsave2) nst_state_quicksave(1);
|
||||
else if (Fl::event_key() == inputconf.qload1) nst_state_quickload(0);
|
||||
else if (Fl::event_key() == inputconf.qload2) nst_state_quickload(1);
|
||||
else if (Fl::event_key() == inputconf.screenshot) { video_screenshot(NULL); }
|
||||
else if (Fl::event_key() == inputconf.fdsflip) { nst_fds_flip(); }
|
||||
else if (Fl::event_key() == inputconf.fdsswitch) { nst_fds_switch(); }
|
||||
else if (Fl::event_key() == inputconf.insertcoin1) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_1; }
|
||||
else if (Fl::event_key() == inputconf.insertcoin2) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_2; }
|
||||
else if (Fl::event_key() == inputconf.reset) { nst_reset(0); }
|
||||
else if (Fl::event_key() == inputconf.rwstart) { nst_set_rewind(0); }
|
||||
else if (Fl::event_key() == inputconf.rwstop) { nst_set_rewind(1); }
|
||||
else if (Fl::event_key() == ' ') { cNstPads->pad[1].mic = 0x04; }
|
||||
}
|
||||
else {
|
||||
if (Fl::event_key() == inputconf.ffspeed) nst_timing_set_default();
|
||||
else if (Fl::event_key() == inputconf.fullscreen) fltkui_fullscreen(NULL, NULL);
|
||||
else if (Fl::event_key() == ' ') { cNstPads->pad[1].mic = 0x00; }
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMGAMEPADS; i++) {
|
||||
if (Fl::event_key() == player[i].u) { input.player = i; input.nescode = Input::Controllers::Pad::UP; }
|
||||
else if (Fl::event_key() == player[i].d) { input.player = i; input.nescode = Input::Controllers::Pad::DOWN; }
|
||||
else if (Fl::event_key() == player[i].l) { input.player = i; input.nescode = Input::Controllers::Pad::LEFT; }
|
||||
else if (Fl::event_key() == player[i].r) { input.player = i; input.nescode = Input::Controllers::Pad::RIGHT; }
|
||||
else if (Fl::event_key() == player[i].select) { input.player = i; input.nescode = Input::Controllers::Pad::SELECT; }
|
||||
else if (Fl::event_key() == player[i].start) { input.player = i; input.nescode = Input::Controllers::Pad::START; }
|
||||
else if (Fl::event_key() == player[i].a) { input.player = i; input.nescode = Input::Controllers::Pad::A; }
|
||||
else if (Fl::event_key() == player[i].b) { input.player = i; input.nescode = Input::Controllers::Pad::B; }
|
||||
else if (Fl::event_key() == player[i].ta) { input.player = i; input.turboa = 1; input.nescode = Input::Controllers::Pad::A; }
|
||||
else if (Fl::event_key() == player[i].tb) { input.player = i; input.turbob = 1; input.nescode = Input::Controllers::Pad::B; }
|
||||
}
|
||||
|
||||
nst_input_inject(cNstPads, input);
|
||||
}
|
|
@ -1,23 +1,25 @@
|
|||
#ifndef _SDLINPUT_H_
|
||||
#define _SDLINPUT_H_
|
||||
#ifndef _INPUT_H_
|
||||
#define _INPUT_H_
|
||||
|
||||
#define NUMGAMEPADS 2
|
||||
#define NUMBUTTONS 10
|
||||
#define TOTALBUTTONS (NUMGAMEPADS*NUMBUTTONS)
|
||||
#define DEADZONE (32768/3)
|
||||
|
||||
#include "core/api/NstApiInput.hpp"
|
||||
|
||||
typedef struct {
|
||||
SDL_Scancode u;
|
||||
SDL_Scancode d;
|
||||
SDL_Scancode l;
|
||||
SDL_Scancode r;
|
||||
SDL_Scancode select;
|
||||
SDL_Scancode start;
|
||||
SDL_Scancode a;
|
||||
SDL_Scancode b;
|
||||
SDL_Scancode ta;
|
||||
SDL_Scancode tb;
|
||||
|
||||
int u;
|
||||
int d;
|
||||
int l;
|
||||
int r;
|
||||
int select;
|
||||
int start;
|
||||
int a;
|
||||
int b;
|
||||
int ta;
|
||||
int tb;
|
||||
|
||||
SDL_Event ju;
|
||||
SDL_Event jd;
|
||||
SDL_Event jl;
|
||||
|
@ -36,41 +38,39 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
// User Interface
|
||||
char *qsave1;
|
||||
char *qsave2;
|
||||
char *qload1;
|
||||
char *qload2;
|
||||
|
||||
char *screenshot;
|
||||
|
||||
char *fdsflip;
|
||||
char *fdsswitch;
|
||||
|
||||
char *insertcoin1;
|
||||
char *insertcoin2;
|
||||
|
||||
char *reset;
|
||||
|
||||
char *ffspeed;
|
||||
char *rwstart;
|
||||
char *rwstop;
|
||||
|
||||
char *fullscreen;
|
||||
char *filter;
|
||||
char *scalefactor;
|
||||
|
||||
int qsave1;
|
||||
int qsave2;
|
||||
int qload1;
|
||||
int qload2;
|
||||
|
||||
int screenshot;
|
||||
|
||||
int fdsflip;
|
||||
int fdsswitch;
|
||||
|
||||
int insertcoin1;
|
||||
int insertcoin2;
|
||||
|
||||
int reset;
|
||||
|
||||
int ffspeed;
|
||||
int rwstart;
|
||||
int rwstop;
|
||||
|
||||
int fullscreen;
|
||||
|
||||
// Player 1
|
||||
char *kb_p1u;
|
||||
char *kb_p1d;
|
||||
char *kb_p1l;
|
||||
char *kb_p1r;
|
||||
char *kb_p1select;
|
||||
char *kb_p1start;
|
||||
char *kb_p1a;
|
||||
char *kb_p1b;
|
||||
char *kb_p1ta;
|
||||
char *kb_p1tb;
|
||||
|
||||
int kb_p1u;
|
||||
int kb_p1d;
|
||||
int kb_p1l;
|
||||
int kb_p1r;
|
||||
int kb_p1select;
|
||||
int kb_p1start;
|
||||
int kb_p1a;
|
||||
int kb_p1b;
|
||||
int kb_p1ta;
|
||||
int kb_p1tb;
|
||||
|
||||
char *js_p1u;
|
||||
char *js_p1d;
|
||||
char *js_p1l;
|
||||
|
@ -81,7 +81,7 @@ typedef struct {
|
|||
char *js_p1b;
|
||||
char *js_p1ta;
|
||||
char *js_p1tb;
|
||||
|
||||
|
||||
char *js_rwstart;
|
||||
char *js_rwstop;
|
||||
|
||||
|
@ -89,17 +89,17 @@ typedef struct {
|
|||
char *js_hardreset;
|
||||
|
||||
// Player 2
|
||||
char *kb_p2u;
|
||||
char *kb_p2d;
|
||||
char *kb_p2l;
|
||||
char *kb_p2r;
|
||||
char *kb_p2select;
|
||||
char *kb_p2start;
|
||||
char *kb_p2a;
|
||||
char *kb_p2b;
|
||||
char *kb_p2ta;
|
||||
char *kb_p2tb;
|
||||
|
||||
int kb_p2u;
|
||||
int kb_p2d;
|
||||
int kb_p2l;
|
||||
int kb_p2r;
|
||||
int kb_p2select;
|
||||
int kb_p2start;
|
||||
int kb_p2a;
|
||||
int kb_p2b;
|
||||
int kb_p2ta;
|
||||
int kb_p2tb;
|
||||
|
||||
char *js_p2u;
|
||||
char *js_p2d;
|
||||
char *js_p2l;
|
||||
|
@ -112,11 +112,39 @@ typedef struct {
|
|||
char *js_p2tb;
|
||||
} inputsettings_t;
|
||||
|
||||
using namespace Nes::Api;
|
||||
|
||||
typedef struct {
|
||||
unsigned char player;
|
||||
unsigned char nescode;
|
||||
unsigned char pressed;
|
||||
unsigned char turboa;
|
||||
unsigned char turbob;
|
||||
} nesinput_t;
|
||||
|
||||
typedef struct {
|
||||
int p1a;
|
||||
int p1b;
|
||||
int p2a;
|
||||
int p2b;
|
||||
} turbo_t;
|
||||
|
||||
void nst_input_init();
|
||||
|
||||
void nst_input_inject(Input::Controllers *controllers, nesinput_t input);
|
||||
void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y);
|
||||
|
||||
void nst_input_turbo_init();
|
||||
void nst_input_turbo_pulse(Input::Controllers *controllers);
|
||||
|
||||
int nst_input_zapper_present();
|
||||
|
||||
int input_configure_item(int pnum, int bnum, int type);
|
||||
|
||||
void nstsdl_input_conf(int type, int pnum);
|
||||
void nstsdl_input_conf_button(int pnum, int bnum);
|
||||
void nstsdl_input_conf_defaults();
|
||||
void nstsdl_input_conf_set(SDL_Event event, int type, int pnum, int counter);
|
||||
void nstsdl_input_conf_set(SDL_Event event, int pnum, int bnum);
|
||||
void nstsdl_input_conf_read();
|
||||
void nstsdl_input_conf_write();
|
||||
|
||||
|
@ -131,4 +159,6 @@ void nstsdl_input_process(Input::Controllers *controllers, SDL_Event event);
|
|||
char* nstsdl_input_translate_event(SDL_Event event);
|
||||
SDL_Event nstsdl_input_translate_string(const char *string);
|
||||
|
||||
void fltkui_input_conf_set(int kval, int pnum, int bnum);
|
||||
void fltkui_input_process_key(int e);
|
||||
#endif
|
|
@ -1,25 +1,25 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2007-2008 R. Belmont
|
||||
* Copyright (C) 2012-2018 R. Danbrook
|
||||
* Copyright (C) 2012-2021 R. Danbrook
|
||||
* Copyright (C) 2018-2018 Phil Smith
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
@ -37,6 +37,8 @@
|
|||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
// Nst Common
|
||||
#include "nstcommon.h"
|
||||
#include "config.h"
|
||||
|
@ -73,7 +75,7 @@ bool (*nst_archive_select)(const char*, char*, size_t);
|
|||
|
||||
static bool NST_CALLBACK nst_cb_videolock(void* userData, Video::Output& video) {
|
||||
video.pitch = video_lock_screen(video.pixels);
|
||||
return true; // true=lock success, false=lock failed (Nestopia will carry on but skip video)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void NST_CALLBACK nst_cb_videounlock(void* userData, Video::Output& video) {
|
||||
|
@ -115,7 +117,7 @@ static void NST_CALLBACK nst_cb_file(void *userData, User::File& file) {
|
|||
unsigned char *compbuffer;
|
||||
int compsize, compoffset;
|
||||
char *filename;
|
||||
|
||||
|
||||
switch (file.GetAction()) {
|
||||
case User::File::LOAD_ROM:
|
||||
// Nothing here for now
|
||||
|
@ -132,13 +134,13 @@ static void NST_CALLBACK nst_cb_file(void *userData, User::File& file) {
|
|||
case User::File::LOAD_EEPROM: // used by some Bandai games, can be treated the same as battery files
|
||||
case User::File::LOAD_TAPE: // for loading Famicom cassette tapes
|
||||
case User::File::LOAD_TURBOFILE: // for loading turbofile data
|
||||
{
|
||||
{
|
||||
std::ifstream batteryFile(nstpaths.savename, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
|
||||
if (batteryFile.is_open()) { file.SetContent(batteryFile); }
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case User::File::SAVE_BATTERY: // save battery data to a file
|
||||
case User::File::SAVE_EEPROM: // can be treated the same as battery files
|
||||
case User::File::SAVE_TAPE: // for saving Famicom cassette tapes
|
||||
|
@ -160,7 +162,7 @@ static void NST_CALLBACK nst_cb_file(void *userData, User::File& file) {
|
|||
char fdsname[512];
|
||||
|
||||
snprintf(fdsname, sizeof(fdsname), "%s.ups", nstpaths.fdssave);
|
||||
|
||||
|
||||
std::ifstream batteryFile( fdsname, std::ifstream::in|std::ifstream::binary );
|
||||
|
||||
// no ups, look for ips
|
||||
|
@ -232,12 +234,12 @@ bool nst_archive_select_file(const char *filename, char *reqfile, size_t reqsize
|
|||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
int r, numarchives = 0;
|
||||
|
||||
|
||||
a = archive_read_new();
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
r = archive_read_open_filename(a, filename, 10240);
|
||||
|
||||
|
||||
// Test if it's actually an archive
|
||||
if (r != ARCHIVE_OK) {
|
||||
r = archive_read_free(a);
|
||||
|
@ -257,7 +259,7 @@ bool nst_archive_select_file(const char *filename, char *reqfile, size_t reqsize
|
|||
}
|
||||
// Free the archive
|
||||
r = archive_read_free(a);
|
||||
|
||||
|
||||
// If there are no valid files in the archive, return
|
||||
if (numarchives == 0) { return false; }
|
||||
else { return true; }
|
||||
|
@ -271,18 +273,18 @@ bool nst_archive_open(const char *filename, char **rom, int *romsize, const char
|
|||
struct archive_entry *entry;
|
||||
int r;
|
||||
int64_t entrysize;
|
||||
|
||||
|
||||
a = archive_read_new();
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
r = archive_read_open_filename(a, filename, 10240);
|
||||
|
||||
|
||||
// Test if it's actually an archive
|
||||
if (r != ARCHIVE_OK) {
|
||||
r = archive_read_free(a);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Scan through the archive for files
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||
char *rombuf;
|
||||
|
@ -327,28 +329,28 @@ void nst_db_load() {
|
|||
// Try to open the database file
|
||||
snprintf(dbpath, sizeof(dbpath), "%sNstDatabase.xml", nstpaths.nstdir);
|
||||
nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
|
||||
if (nstdb->is_open()) {
|
||||
database.Load(*nstdb);
|
||||
database.Enable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If it fails, try looking in the data directory
|
||||
snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", DATADIR);
|
||||
snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", ".");
|
||||
nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
|
||||
if (nstdb->is_open()) {
|
||||
database.Load(*nstdb);
|
||||
database.Enable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If that fails, try looking in the working directory
|
||||
char *pwd = getenv("PWD");
|
||||
snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", pwd);
|
||||
nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
|
||||
if (nstdb->is_open()) {
|
||||
database.Load(*nstdb);
|
||||
database.Enable(true);
|
||||
|
@ -368,19 +370,19 @@ void nst_db_unload() {
|
|||
void nst_dipswitch() {
|
||||
// Print DIP switch information and call handler
|
||||
DipSwitches dipswitches(emulator);
|
||||
|
||||
|
||||
int numdips = dipswitches.NumDips();
|
||||
|
||||
|
||||
if (numdips > 0) {
|
||||
for (int i = 0; i < numdips; i++) {
|
||||
fprintf(stderr, "%d: %s\n", i, dipswitches.GetDipName(i));
|
||||
int numvalues = dipswitches.NumValues(i);
|
||||
|
||||
|
||||
for (int j = 0; j < numvalues; j++) {
|
||||
fprintf(stderr, " %d: %s\n", j, dipswitches.GetValueName(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char dippath[512];
|
||||
snprintf(dippath, sizeof(dippath), "%s%s.dip", nstpaths.savedir, nstpaths.gamename);
|
||||
nst_dip_handle(dippath);
|
||||
|
@ -391,7 +393,7 @@ void nst_fds_bios_load() {
|
|||
// Load the Famicom Disk System BIOS
|
||||
Nes::Api::Fds fds(emulator);
|
||||
char biospath[512];
|
||||
|
||||
|
||||
if (fdsbios) { return; }
|
||||
|
||||
snprintf(biospath, sizeof(biospath), "%sdisksys.rom", nstpaths.nstdir);
|
||||
|
@ -418,7 +420,7 @@ void nst_fds_info() {
|
|||
const char* disk;
|
||||
const char* side;
|
||||
char textbuf[24];
|
||||
|
||||
|
||||
fds.GetCurrentDisk() == 0 ? disk = "1" : disk = "2";
|
||||
fds.GetCurrentDiskSide() == 0 ? side = "A" : side = "B";
|
||||
|
||||
|
@ -440,9 +442,9 @@ void nst_fds_flip() {
|
|||
void nst_fds_switch() {
|
||||
// Switches the FDS disk in multi-disk games
|
||||
Fds fds(emulator);
|
||||
|
||||
|
||||
int currentdisk = fds.GetCurrentDisk();
|
||||
|
||||
|
||||
// If it's a multi-disk game, eject and insert the other disk
|
||||
if (fds.GetNumDisks() > 1) {
|
||||
fds.EjectDisk();
|
||||
|
@ -451,11 +453,11 @@ void nst_fds_switch() {
|
|||
}
|
||||
}
|
||||
|
||||
void nst_movie_save(char *filename) {
|
||||
void nst_movie_save(const char *filename) {
|
||||
// Save/Record a movie
|
||||
Movie movie(emulator);
|
||||
|
||||
movierecfile = new std::fstream(filename, std::ifstream::out|std::ifstream::binary);
|
||||
|
||||
movierecfile = new std::fstream(filename, std::ifstream::out|std::ifstream::binary);
|
||||
|
||||
if (movierecfile->is_open()) {
|
||||
movie.Record((std::iostream&)*movierecfile, Nes::Api::Movie::CLEAN);
|
||||
|
@ -466,11 +468,11 @@ void nst_movie_save(char *filename) {
|
|||
}
|
||||
}
|
||||
|
||||
void nst_movie_load(char *filename) {
|
||||
void nst_movie_load(const char *filename) {
|
||||
// Load and play a movie
|
||||
Movie movie(emulator);
|
||||
|
||||
moviefile = new std::ifstream(filename, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
moviefile = new std::ifstream(filename, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
if (moviefile->is_open()) {
|
||||
movie.Play(*moviefile);
|
||||
|
@ -484,7 +486,7 @@ void nst_movie_load(char *filename) {
|
|||
void nst_movie_stop() {
|
||||
// Stop any movie that is playing or recording
|
||||
Movie movie(emulator);
|
||||
|
||||
|
||||
if (movie.IsPlaying() || movie.IsRecording()) {
|
||||
movie.Stop();
|
||||
movierecfile = NULL;
|
||||
|
@ -534,18 +536,18 @@ bool nst_playing() { return playing; }
|
|||
|
||||
void nst_palette_load(const char *filename) {
|
||||
// Load a custom palette
|
||||
|
||||
|
||||
FILE *file;
|
||||
long filesize; // File size in bytes
|
||||
size_t result;
|
||||
|
||||
|
||||
char custgamepalpath[512];
|
||||
snprintf(custgamepalpath, sizeof(custgamepalpath), "%s%s%s", nstpaths.nstdir, nstpaths.gamename, ".pal");
|
||||
|
||||
|
||||
// Try the game-specific palette first
|
||||
file = fopen(custgamepalpath, "rb");
|
||||
if (!file) { file = fopen(filename, "rb"); }
|
||||
|
||||
|
||||
// Then try the global custom palette
|
||||
if (!file) {
|
||||
if (conf.video_palette_mode == 2) {
|
||||
|
@ -554,17 +556,17 @@ void nst_palette_load(const char *filename) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
filesize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
|
||||
if (custompalette) { free(custompalette); }
|
||||
custompalette = malloc(filesize * sizeof(uint8_t));
|
||||
custpalsize = filesize * sizeof(uint8_t);
|
||||
|
||||
|
||||
result = fread(custompalette, sizeof(uint8_t), filesize, file);
|
||||
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
@ -572,14 +574,14 @@ void nst_palette_save() {
|
|||
// Save a custom palette
|
||||
FILE *file;
|
||||
void *custpalout;
|
||||
|
||||
|
||||
file = fopen(nstpaths.palettepath, "wb");
|
||||
if (!file) { return; }
|
||||
|
||||
|
||||
custpalout = malloc(custpalsize);
|
||||
|
||||
|
||||
memcpy(custpalout, custompalette, custpalsize);
|
||||
|
||||
|
||||
fwrite(custpalout, custpalsize, sizeof(uint8_t), file);
|
||||
fclose(file);
|
||||
free(custpalout);
|
||||
|
@ -602,30 +604,30 @@ bool nst_find_patch(char *patchname, unsigned int patchname_length, const char *
|
|||
// since copying into same string as the argument we don't want any overlap
|
||||
memmove(filedir, dirname(filedir), sizeof(filedir));
|
||||
filedir[sizeof(filedir) - 1] = '\0';
|
||||
|
||||
|
||||
if (!conf.misc_soft_patching) { return 0; }
|
||||
|
||||
|
||||
snprintf(patchname, patchname_length, "%s/%s.ips", filedir, nstpaths.gamename);
|
||||
|
||||
|
||||
if ((file = fopen(patchname, "rb")) != NULL) { fclose(file); return 1; }
|
||||
else {
|
||||
snprintf(patchname, patchname_length, "%s/%s.ups", filedir, nstpaths.gamename);
|
||||
if ((file = fopen(patchname, "rb")) != NULL) { fclose(file); return 1; }
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nst_set_callbacks() {
|
||||
// Set up the callbacks
|
||||
void *userData = (void*)0xDEADC0DE;
|
||||
|
||||
|
||||
Video::Output::lockCallback.Set(nst_cb_videolock, userData);
|
||||
Video::Output::unlockCallback.Set(nst_cb_videounlock, userData);
|
||||
|
||||
|
||||
Sound::Output::lockCallback.Set(nst_cb_soundlock, userData);
|
||||
Sound::Output::unlockCallback.Set(nst_cb_soundunlock, userData);
|
||||
|
||||
|
||||
User::fileIoCallback.Set(nst_cb_file, userData);
|
||||
User::logCallback.Set(nst_cb_log, userData);
|
||||
User::eventCallback.Set(nst_cb_event, userData);
|
||||
|
@ -640,11 +642,11 @@ void nst_set_dirs() {
|
|||
else {
|
||||
snprintf(nstpaths.nstconfdir, sizeof(nstpaths.nstconfdir), "%s/.config/nestopia/", getenv("HOME"));
|
||||
}
|
||||
|
||||
|
||||
if (mkdir(nstpaths.nstconfdir, 0755) && errno != EEXIST) {
|
||||
fprintf(stderr, "Failed to create %s: %d\n", nstpaths.nstconfdir, errno);
|
||||
}
|
||||
|
||||
|
||||
// create data directory if it doesn't exist
|
||||
if (getenv("XDG_DATA_HOME")) {
|
||||
snprintf(nstpaths.nstdir, sizeof(nstpaths.nstdir), "%s/nestopia/", getenv("XDG_DATA_HOME"));
|
||||
|
@ -652,15 +654,15 @@ void nst_set_dirs() {
|
|||
else {
|
||||
snprintf(nstpaths.nstdir, sizeof(nstpaths.nstdir), "%s/.local/share/nestopia/", getenv("HOME"));
|
||||
}
|
||||
|
||||
|
||||
if (mkdir(nstpaths.nstdir, 0755) && errno != EEXIST) {
|
||||
fprintf(stderr, "Failed to create %s: %d\n", nstpaths.nstdir, errno);
|
||||
}
|
||||
|
||||
|
||||
// create save and state directories if they don't exist
|
||||
char dirstr[256];
|
||||
snprintf(dirstr, sizeof(dirstr), "%ssave", nstpaths.nstdir);
|
||||
|
||||
|
||||
if (mkdir(dirstr, 0755) && errno != EEXIST) {
|
||||
fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno);
|
||||
}
|
||||
|
@ -669,22 +671,22 @@ void nst_set_dirs() {
|
|||
if (mkdir(dirstr, 0755) && errno != EEXIST) {
|
||||
fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno);
|
||||
}
|
||||
|
||||
|
||||
// create cheats directory if it doesn't exist
|
||||
snprintf(dirstr, sizeof(dirstr), "%scheats", nstpaths.nstdir);
|
||||
if (mkdir(dirstr, 0755) && errno != EEXIST) {
|
||||
fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno);
|
||||
}
|
||||
|
||||
|
||||
// create screenshots directory if it doesn't exist
|
||||
snprintf(dirstr, sizeof(dirstr), "%sscreenshots", nstpaths.nstdir);
|
||||
if (mkdir(dirstr, 0755) && errno != EEXIST) {
|
||||
fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno);
|
||||
}
|
||||
|
||||
|
||||
// Construct the custom palette path
|
||||
snprintf(nstpaths.palettepath, sizeof(nstpaths.palettepath), "%s%s", nstpaths.nstdir, "custom.pal");
|
||||
|
||||
|
||||
// Construct samples directory if it doesn't exist
|
||||
snprintf(dirstr, sizeof(dirstr), "%ssamples", nstpaths.nstdir);
|
||||
if (mkdir(dirstr, 0755) && errno != EEXIST) {
|
||||
|
@ -693,13 +695,13 @@ void nst_set_dirs() {
|
|||
}
|
||||
|
||||
void nst_set_paths(const char *filename) {
|
||||
|
||||
|
||||
// Set up the save directory
|
||||
snprintf(nstpaths.savedir, sizeof(nstpaths.savedir), "%ssave/", nstpaths.nstdir);
|
||||
|
||||
|
||||
// Copy the full file path to the savename variable
|
||||
snprintf(nstpaths.savename, sizeof(nstpaths.savename), "%s", filename);
|
||||
|
||||
|
||||
// strip the . and extention off the filename for saving
|
||||
for (int i = strlen(nstpaths.savename)-1; i > 0; i--) {
|
||||
if (nstpaths.savename[i] == '.') {
|
||||
|
@ -707,22 +709,22 @@ void nst_set_paths(const char *filename) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set up the sample directory
|
||||
snprintf(nstpaths.sampdir, sizeof(nstpaths.sampdir), "%ssamples/", nstpaths.nstdir);
|
||||
|
||||
|
||||
// Get the name of the game minus file path and extension
|
||||
snprintf(nstpaths.gamename, sizeof(nstpaths.gamename), "%s", basename(nstpaths.savename));
|
||||
|
||||
|
||||
// Construct save path
|
||||
snprintf(nstpaths.savename, sizeof(nstpaths.savename), "%s%s%s", nstpaths.savedir, nstpaths.gamename, ".sav");
|
||||
|
||||
// Construct path for FDS save patches
|
||||
snprintf(nstpaths.fdssave, sizeof(nstpaths.fdssave), "%s%s", nstpaths.savedir, nstpaths.gamename);
|
||||
|
||||
|
||||
// Construct the save state path
|
||||
snprintf(nstpaths.statepath, sizeof(nstpaths.statepath), "%sstate/%s", nstpaths.nstdir, nstpaths.gamename);
|
||||
|
||||
|
||||
// Construct the cheat path
|
||||
snprintf(nstpaths.cheatpath, sizeof(nstpaths.cheatpath), "%scheats/%s.xml", nstpaths.nstdir, nstpaths.gamename);
|
||||
}
|
||||
|
@ -731,7 +733,7 @@ void nst_set_region() {
|
|||
// Set the region
|
||||
Machine machine(emulator);
|
||||
Cartridge::Database database(emulator);
|
||||
|
||||
|
||||
/*if (database.IsLoaded()) {
|
||||
std::ifstream dbfile(filename, std::ios::in|std::ios::binary);
|
||||
Cartridge::Profile profile;
|
||||
|
@ -739,7 +741,7 @@ void nst_set_region() {
|
|||
dbentry = database.FindEntry(profile.hash, nst_default_system());
|
||||
printf("Mapper: %d\n", dbentry.GetMapper());
|
||||
}*/
|
||||
|
||||
|
||||
switch (conf.misc_default_system) {
|
||||
case 0: machine.SetMode(machine.GetDesiredMode()); break; // Auto
|
||||
case 1: machine.SetMode(Machine::NTSC); break; // NTSC
|
||||
|
@ -758,23 +760,23 @@ void nst_set_rewind(int direction) {
|
|||
}
|
||||
}
|
||||
|
||||
void nst_state_save(char *filename) {
|
||||
void nst_state_save(const char *filename) {
|
||||
// Save a state by filename
|
||||
Machine machine(emulator);
|
||||
|
||||
|
||||
std::ofstream statefile(filename, std::ifstream::out|std::ifstream::binary);
|
||||
|
||||
|
||||
if (statefile.is_open()) { machine.SaveState(statefile, Nes::Api::Machine::NO_COMPRESSION); }
|
||||
fprintf(stderr, "State Saved: %s\n", filename);
|
||||
nst_video_print("State Saved", 8, 212, 2, true);
|
||||
}
|
||||
|
||||
void nst_state_load(char *filename) {
|
||||
void nst_state_load(const char *filename) {
|
||||
// Load a state by filename
|
||||
Machine machine(emulator);
|
||||
|
||||
|
||||
std::ifstream statefile(filename, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
|
||||
if (statefile.is_open()) { machine.LoadState(statefile); }
|
||||
fprintf(stderr, "State Loaded: %s\n", filename);
|
||||
nst_video_print("State Loaded", 8, 212, 2, true);
|
||||
|
@ -782,6 +784,7 @@ void nst_state_load(char *filename) {
|
|||
|
||||
void nst_state_quicksave(int slot) {
|
||||
// Quick Save State
|
||||
if (!loaded) { return; }
|
||||
char slotpath[520];
|
||||
snprintf(slotpath, sizeof(slotpath), "%s_%d.nst", nstpaths.statepath, slot);
|
||||
nst_state_save(slotpath);
|
||||
|
@ -790,16 +793,17 @@ void nst_state_quicksave(int slot) {
|
|||
|
||||
void nst_state_quickload(int slot) {
|
||||
// Quick Load State
|
||||
if (!loaded) { return; }
|
||||
char slotpath[520];
|
||||
snprintf(slotpath, sizeof(slotpath), "%s_%d.nst", nstpaths.statepath, slot);
|
||||
|
||||
|
||||
struct stat qloadstat;
|
||||
if (stat(slotpath, &qloadstat) == -1) {
|
||||
fprintf(stderr, "No State to Load\n");
|
||||
nst_video_print("No State to Load", 8, 212, 2, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
nst_state_load(slotpath);
|
||||
}
|
||||
|
||||
|
@ -827,7 +831,7 @@ void nst_reset(bool hardreset) {
|
|||
Fds fds(emulator);
|
||||
machine.SetRamPowerState(conf.misc_power_state);
|
||||
machine.Reset(hardreset);
|
||||
|
||||
|
||||
// Set the FDS disk to defaults
|
||||
fds.EjectDisk();
|
||||
fds.InsertDisk(0, 0);
|
||||
|
@ -838,11 +842,11 @@ void nst_emuloop() {
|
|||
if (NES_SUCCEEDED(Rewinder(emulator).Enable(true))) {
|
||||
Rewinder(emulator).EnableSound(true);
|
||||
}
|
||||
|
||||
|
||||
if (playing) {
|
||||
// Pulse the turbo buttons
|
||||
nst_input_turbo_pulse(cNstPads);
|
||||
|
||||
|
||||
// Execute frames
|
||||
for (int i = 0; i < nst_timing_runframes(); i++) {
|
||||
emulator.Execute(cNstVideo, cNstSound, cNstPads);
|
||||
|
@ -853,7 +857,7 @@ void nst_emuloop() {
|
|||
void nst_unload() {
|
||||
// Remove the cartridge and shut down the NES
|
||||
Machine machine(emulator);
|
||||
|
||||
|
||||
// Power down the NES
|
||||
machine.Power(false);
|
||||
|
||||
|
@ -867,14 +871,14 @@ void nst_pause() {
|
|||
audio_pause();
|
||||
audio_deinit();
|
||||
}
|
||||
|
||||
|
||||
playing = false;
|
||||
}
|
||||
|
||||
void nst_play() {
|
||||
// Play the game
|
||||
if (playing) { return; }
|
||||
|
||||
|
||||
video_init();
|
||||
audio_init();
|
||||
nst_input_init();
|
||||
|
@ -884,16 +888,16 @@ void nst_play() {
|
|||
cNstVideo = new Video::Output;
|
||||
cNstSound = new Sound::Output;
|
||||
cNstPads = new Input::Controllers;
|
||||
|
||||
|
||||
audio_set_params(cNstSound);
|
||||
audio_unpause();
|
||||
|
||||
|
||||
if (nst_nsf()) {
|
||||
Nsf nsf(emulator);
|
||||
nsf.PlaySong();
|
||||
video_disp_nsf();
|
||||
}
|
||||
|
||||
|
||||
playing = true;
|
||||
}
|
||||
|
||||
|
@ -906,33 +910,33 @@ int nst_load(const char *filename) {
|
|||
char *rom;
|
||||
int romsize;
|
||||
char patchname[512];
|
||||
|
||||
|
||||
// Pause play before pulling out a cartridge
|
||||
if (playing) { nst_pause(); }
|
||||
|
||||
|
||||
// Pull out any inserted cartridges
|
||||
if (loaded) { nst_unload(); }
|
||||
nst_video_print_time("", false);
|
||||
|
||||
|
||||
// Check if the file is an archive and select the file within
|
||||
char reqfile[256]; // Requested file inside the archive
|
||||
if (nst_archive_select(filename, reqfile, sizeof(reqfile))) {
|
||||
// Extract the contents
|
||||
nst_archive_open(filename, &rom, &romsize, reqfile);
|
||||
|
||||
|
||||
// Convert the malloc'd char* to an istream
|
||||
std::string rombuf(rom, romsize);
|
||||
std::istringstream file(rombuf);
|
||||
free(rom);
|
||||
|
||||
|
||||
result = machine.Load(file, nst_default_system());
|
||||
}
|
||||
else { // Otherwise just load the file
|
||||
std::ifstream file(filename, std::ios::in|std::ios::binary);
|
||||
|
||||
|
||||
// Set the file paths
|
||||
nst_set_paths(filename);
|
||||
|
||||
|
||||
if (nst_find_patch(patchname, sizeof(patchname), filename)) { // Load with a patch if there is one
|
||||
std::ifstream pfile(patchname, std::ios::in|std::ios::binary);
|
||||
Machine::Patch patch(pfile, false);
|
||||
|
@ -940,7 +944,7 @@ int nst_load(const char *filename) {
|
|||
}
|
||||
else { result = machine.Load(file, nst_default_system()); }
|
||||
}
|
||||
|
||||
|
||||
if (NES_FAILED(result)) {
|
||||
char errorstring[32];
|
||||
switch (result) {
|
||||
|
@ -968,39 +972,39 @@ int nst_load(const char *filename) {
|
|||
snprintf(errorstring, sizeof(errorstring), "Error: %d", result);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fprintf(stderr, "%s\n", errorstring);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Deal with any DIP Switches
|
||||
nst_dipswitch();
|
||||
|
||||
|
||||
// Set the region
|
||||
nst_set_region();
|
||||
|
||||
|
||||
if (machine.Is(Machine::DISK)) {
|
||||
Fds fds(emulator);
|
||||
fds.InsertDisk(0, 0);
|
||||
nst_fds_info();
|
||||
}
|
||||
|
||||
|
||||
// Check if this is an NSF
|
||||
if (nst_nsf()) { nsf.StopSong(); }
|
||||
|
||||
|
||||
// Check if sound distortion should be enabled
|
||||
sound.SetGenie(conf.misc_genie_distortion);
|
||||
|
||||
|
||||
// Load the custom palette
|
||||
nst_palette_load(nstpaths.palettepath);
|
||||
|
||||
|
||||
// Set the RAM's power state
|
||||
machine.SetRamPowerState(conf.misc_power_state);
|
||||
|
||||
|
||||
// Power on
|
||||
machine.Power(true);
|
||||
|
||||
|
||||
loaded = 1;
|
||||
return loaded;
|
||||
}
|
|
@ -53,8 +53,8 @@ void nst_fds_flip();
|
|||
void nst_fds_switch();
|
||||
|
||||
// Movies
|
||||
void nst_movie_save(char *filename);
|
||||
void nst_movie_load(char *filename);
|
||||
void nst_movie_save(const char *filename);
|
||||
void nst_movie_load(const char *filename);
|
||||
void nst_movie_stop();
|
||||
|
||||
// NSF
|
||||
|
@ -87,8 +87,8 @@ void nst_set_region();
|
|||
void nst_set_rewind(int direction);
|
||||
|
||||
// States
|
||||
void nst_state_save(char *filename);
|
||||
void nst_state_load(char *filename);
|
||||
void nst_state_save(const char *filename);
|
||||
void nst_state_load(const char *filename);
|
||||
void nst_state_quicksave(int isvst);
|
||||
void nst_state_quickload(int isvst);
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2012-2018 R. Danbrook
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -25,10 +25,8 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _MINGW
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#endif
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "samples.h"
|
||||
|
@ -42,22 +40,22 @@ int nst_sample_load_file(const char* filepath) {
|
|||
FILE *file;
|
||||
long filesize; // File size in bytes
|
||||
size_t result;
|
||||
|
||||
|
||||
file = fopen(filepath, "rb");
|
||||
|
||||
|
||||
if (!file) { return 0; }
|
||||
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
filesize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
|
||||
wavfile = (uint8_t*)malloc(filesize * sizeof(uint8_t));
|
||||
|
||||
|
||||
if (wavfile == NULL) { return 0; }
|
||||
|
||||
|
||||
result = fread(wavfile, sizeof(uint8_t), filesize, file);
|
||||
if (result != filesize) { return 0; }
|
||||
|
||||
|
||||
fclose(file);
|
||||
return 1;
|
||||
}
|
||||
|
@ -68,18 +66,18 @@ int nst_sample_load_archive(const char* filename, const char* reqfile) {
|
|||
struct archive_entry *entry;
|
||||
int r;
|
||||
int64_t entrysize;
|
||||
|
||||
|
||||
a = archive_read_new();
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
r = archive_read_open_filename(a, filename, 10240);
|
||||
|
||||
|
||||
// Test if it's actually an archive
|
||||
if (r != ARCHIVE_OK) {
|
||||
r = archive_read_free(a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Scan through the archive for files
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||
const char *currentfile = archive_entry_pathname(entry);
|
||||
|
@ -108,7 +106,7 @@ int nst_sample_unload_file() {
|
|||
|
||||
void nst_sample_setcontent(User::File& file) {
|
||||
// Parse the .WAV header and load the sample into the emulator
|
||||
|
||||
|
||||
// Check to see if it has a valid header
|
||||
uint8_t fmt[4] = { 0x66, 0x6d, 0x74, 0x20};
|
||||
uint8_t subchunk2id[4] = { 0x64, 0x61, 0x74, 0x61};
|
||||
|
@ -116,7 +114,7 @@ void nst_sample_setcontent(User::File& file) {
|
|||
if (memcmp(&wavfile[0x08], "WAVE", 4) != 0) { return; }
|
||||
if (memcmp(&wavfile[0x0c], &fmt, 4) != 0) { return; }
|
||||
if (memcmp(&wavfile[0x24], &subchunk2id, 4) != 0) { return; }
|
||||
|
||||
|
||||
// Load the sample into the emulator
|
||||
uint8_t *dataptr = &wavfile[0x2c];
|
||||
uint32_t datasize = wavfile[0x2b] << 24 | wavfile[0x2a] << 16 | wavfile[0x29] << 8 | wavfile[0x28];
|
||||
|
@ -131,10 +129,10 @@ void nst_sample_load_samples(User::File& file, const char* sampgame) {
|
|||
// Load samples for the specific game
|
||||
char reqfile[16];
|
||||
char samppath[576];
|
||||
|
||||
|
||||
// Requested sample .wav file
|
||||
snprintf(reqfile, sizeof(reqfile), "%02d.wav", file.GetId());
|
||||
|
||||
|
||||
// Check if there's a MAME-style zip archive
|
||||
snprintf(samppath, sizeof(samppath), "%s%s.zip", nstpaths.sampdir, sampgame);
|
||||
if (nst_sample_load_archive(samppath, reqfile)) {
|
|
@ -1,28 +1,29 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2007-2008 R. Belmont
|
||||
* Copyright (C) 2012-2020 R. Danbrook
|
||||
*
|
||||
* Copyright (C) 2012-2021 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "core/api/NstApiEmulator.hpp"
|
||||
|
@ -30,6 +31,8 @@
|
|||
#include "core/api/NstApiVideo.hpp"
|
||||
#include "core/api/NstApiNsf.hpp"
|
||||
|
||||
#include <FL/gl.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "video.h"
|
||||
#include "config.h"
|
||||
|
@ -53,114 +56,41 @@ extern void *custompalette;
|
|||
extern nstpaths_t nstpaths;
|
||||
extern Emulator emulator;
|
||||
|
||||
// Shader sources
|
||||
const GLchar* vshader_src =
|
||||
"#version 150 core\n"
|
||||
"in vec2 position;"
|
||||
"in vec2 texcoord;"
|
||||
"out vec2 outcoord;"
|
||||
"void main() {"
|
||||
" outcoord = texcoord;"
|
||||
" gl_Position = vec4(position, 0.0, 1.0);"
|
||||
"}";
|
||||
|
||||
const GLchar* fshader_src =
|
||||
"#version 150 core\n"
|
||||
"in vec2 outcoord;"
|
||||
"out vec4 fragcolor;"
|
||||
"uniform sampler2D nestex;"
|
||||
"void main() {"
|
||||
" fragcolor = texture(nestex, outcoord);"
|
||||
"}";
|
||||
|
||||
GLuint vao;
|
||||
GLuint vbo;
|
||||
GLuint vshader;
|
||||
GLuint fshader;
|
||||
GLuint gl_shader_prog = 0;
|
||||
GLuint gl_texture_id = 0;
|
||||
|
||||
void nst_ogl_init() {
|
||||
// Initialize OpenGL
|
||||
|
||||
float vertices[] = {
|
||||
-1.0f, -1.0f, // Vertex 1 (X, Y)
|
||||
-1.0f, 1.0f, // Vertex 2 (X, Y)
|
||||
1.0f, -1.0f, // Vertex 3 (X, Y)
|
||||
1.0f, 1.0f, // Vertex 4 (X, Y)
|
||||
0.0, 1.0, // Texture 1 (X, Y)
|
||||
0.0, 0.0, // Texture 2 (X, Y)
|
||||
1.0, 1.0, // Texture 3 (X, Y)
|
||||
1.0, 0.0 // Texture 4 (X, Y)
|
||||
};
|
||||
|
||||
GLint status;
|
||||
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
glGenBuffers(1, &vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
vshader = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vshader, 1, &vshader_src, NULL);
|
||||
glCompileShader(vshader);
|
||||
|
||||
glGetShaderiv(vshader, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_FALSE) { fprintf(stderr, "Failed to compile vertex shader\n"); }
|
||||
|
||||
fshader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fshader, 1, &fshader_src, NULL);
|
||||
glCompileShader(fshader);
|
||||
|
||||
glGetShaderiv(fshader, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_FALSE) { fprintf(stderr, "Failed to compile fragment shader\n"); }
|
||||
|
||||
GLuint gl_shader_prog = glCreateProgram();
|
||||
glAttachShader(gl_shader_prog, vshader);
|
||||
glAttachShader(gl_shader_prog, fshader);
|
||||
|
||||
glLinkProgram(gl_shader_prog);
|
||||
|
||||
glValidateProgram(gl_shader_prog);
|
||||
glGetProgramiv(gl_shader_prog, GL_LINK_STATUS, &status);
|
||||
if (status == GL_FALSE) { fprintf(stderr, "Failed to link shader program\n"); }
|
||||
|
||||
glUseProgram(gl_shader_prog);
|
||||
|
||||
GLint posAttrib = glGetAttribLocation(gl_shader_prog, "position");
|
||||
glEnableVertexAttribArray(posAttrib);
|
||||
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
GLint texAttrib = glGetAttribLocation(gl_shader_prog, "texcoord");
|
||||
glEnableVertexAttribArray(texAttrib);
|
||||
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)(8 * sizeof(GLfloat)));
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glGenTextures(1, &gl_texture_id);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, gl_texture_id);
|
||||
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, conf.video_linear_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
|
||||
conf.video_fullscreen ?
|
||||
|
||||
conf.video_fullscreen ?
|
||||
glViewport(screensize.w / 2.0f - rendersize.w / 2.0f, 0, rendersize.w, rendersize.h) :
|
||||
glViewport(0, 0, rendersize.w, rendersize.h);
|
||||
|
||||
glUniform1i(glGetUniformLocation(gl_shader_prog, "nestex"), 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_TEXTURE_3D_EXT);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, rendersize.w * conf.video_scale_factor, rendersize.h * conf.video_scale_factor, 0.0, -1.0, 1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void nst_ogl_deinit() {
|
||||
// Deinitialize OpenGL
|
||||
if (gl_texture_id) { glDeleteTextures(1, &gl_texture_id); }
|
||||
if (gl_shader_prog) { glDeleteProgram(gl_shader_prog); }
|
||||
if (vshader) { glDeleteShader(vshader); }
|
||||
if (fshader) { glDeleteShader(fshader); }
|
||||
if (vao) { glDeleteVertexArrays(1, &vao); }
|
||||
if (vbo) { glDeleteBuffers(1, &vbo); }
|
||||
if (gl_texture_id) {
|
||||
glDeleteTextures(1, &gl_texture_id);
|
||||
}
|
||||
}
|
||||
|
||||
void nst_ogl_render() {
|
||||
|
@ -174,36 +104,42 @@ void nst_ogl_render() {
|
|||
GL_BGRA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
videobuf + overscan_offset);
|
||||
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(rendersize.w * conf.video_scale_factor, rendersize.h * conf.video_scale_factor);
|
||||
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(rendersize.w * conf.video_scale_factor, 0.0);
|
||||
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0, 0.0);
|
||||
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(0, rendersize.h * conf.video_scale_factor);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void nst_video_refresh() {
|
||||
// Refresh the video settings
|
||||
nst_ogl_deinit();
|
||||
|
||||
|
||||
nst_ogl_init();
|
||||
}
|
||||
|
||||
void video_init() {
|
||||
// Initialize video
|
||||
nst_ogl_deinit();
|
||||
|
||||
|
||||
video_set_dimensions();
|
||||
video_set_filter();
|
||||
|
||||
nst_ogl_init();
|
||||
|
||||
if (nst_nsf()) { video_clear_buffer(); video_disp_nsf(); }
|
||||
}
|
||||
|
||||
void video_toggle_filter() {
|
||||
conf.video_filter++;
|
||||
if (conf.video_filter > 5) { conf.video_filter = 0; }
|
||||
video_init();
|
||||
nst_video_refresh();
|
||||
nst_ogl_init();
|
||||
|
||||
if (nst_nsf()) { video_clear_buffer(); video_disp_nsf(); }
|
||||
}
|
||||
|
||||
void video_toggle_filterupdate() {
|
||||
|
@ -212,20 +148,13 @@ void video_toggle_filterupdate() {
|
|||
video.ClearFilterUpdateFlag();
|
||||
}
|
||||
|
||||
void video_toggle_scalefactor() {
|
||||
// Toggle video scale factor
|
||||
conf.video_scale_factor++;
|
||||
if (conf.video_scale_factor > 8) { conf.video_scale_factor = 1; }
|
||||
//video_init();
|
||||
}
|
||||
|
||||
void video_set_filter() {
|
||||
// Set the filter
|
||||
Video video(emulator);
|
||||
int scalefactor = conf.video_scale_factor;
|
||||
if (conf.video_scale_factor > 4) { scalefactor = 4; }
|
||||
if ((conf.video_scale_factor > 3) && (conf.video_filter == 5)) { scalefactor = 3; }
|
||||
|
||||
|
||||
switch(conf.video_filter) {
|
||||
case 0: // None
|
||||
filter = Video::RenderState::FILTER_NONE;
|
||||
|
@ -268,7 +197,7 @@ void video_set_filter() {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 4: // 2xSaI
|
||||
filter = Video::RenderState::FILTER_2XSAI;
|
||||
break;
|
||||
|
@ -288,52 +217,52 @@ void video_set_filter() {
|
|||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Set the sprite limit: false = enable sprite limit, true = disable sprite limit
|
||||
video.EnableUnlimSprites(conf.video_unlimited_sprites ? true : false);
|
||||
|
||||
|
||||
// Set Palette options
|
||||
switch (conf.video_palette_mode) {
|
||||
case 0: // YUV
|
||||
video.GetPalette().SetMode(Video::Palette::MODE_YUV);
|
||||
break;
|
||||
|
||||
|
||||
case 1: // RGB
|
||||
video.GetPalette().SetMode(Video::Palette::MODE_RGB);
|
||||
break;
|
||||
|
||||
|
||||
case 2: // Custom
|
||||
video.GetPalette().SetMode(Video::Palette::MODE_CUSTOM);
|
||||
video.GetPalette().SetCustom((const unsigned char (*)[3])custompalette, Video::Palette::EXT_PALETTE);
|
||||
break;
|
||||
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
// Set YUV Decoder/Picture options
|
||||
if (video.GetPalette().GetMode() == Video::Palette::MODE_YUV) {
|
||||
switch (conf.video_decoder) {
|
||||
case 0: // Consumer
|
||||
video.SetDecoder(Video::DECODER_CONSUMER);
|
||||
break;
|
||||
|
||||
|
||||
case 1: // Canonical
|
||||
video.SetDecoder(Video::DECODER_CANONICAL);
|
||||
break;
|
||||
|
||||
|
||||
case 2: // Alternative (Canonical with yellow boost)
|
||||
video.SetDecoder(Video::DECODER_ALTERNATIVE);
|
||||
break;
|
||||
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
video.SetBrightness(conf.video_brightness);
|
||||
video.SetSaturation(conf.video_saturation);
|
||||
video.SetContrast(conf.video_contrast);
|
||||
video.SetHue(conf.video_hue);
|
||||
|
||||
|
||||
// Set NTSC options
|
||||
if (conf.video_filter == 1) {
|
||||
switch (conf.video_ntsc_mode) {
|
||||
|
@ -345,7 +274,7 @@ void video_set_filter() {
|
|||
video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_COMP);
|
||||
video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_COMP);
|
||||
break;
|
||||
|
||||
|
||||
case 1: // S-Video
|
||||
video.SetSaturation(Video::DEFAULT_SATURATION_SVIDEO);
|
||||
video.SetSharpness(Video::DEFAULT_SHARPNESS_SVIDEO);
|
||||
|
@ -354,7 +283,7 @@ void video_set_filter() {
|
|||
video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_SVIDEO);
|
||||
video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_SVIDEO);
|
||||
break;
|
||||
|
||||
|
||||
case 2: // RGB
|
||||
video.SetSaturation(Video::DEFAULT_SATURATION_RGB);
|
||||
video.SetSharpness(Video::DEFAULT_SHARPNESS_RGB);
|
||||
|
@ -363,7 +292,7 @@ void video_set_filter() {
|
|||
video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_RGB);
|
||||
video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_RGB);
|
||||
break;
|
||||
|
||||
|
||||
case 3: // Monochrome
|
||||
video.SetSaturation(Video::DEFAULT_SATURATION_MONO);
|
||||
video.SetSharpness(Video::DEFAULT_SHARPNESS_MONO);
|
||||
|
@ -372,7 +301,7 @@ void video_set_filter() {
|
|||
video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_MONO);
|
||||
video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_MONO);
|
||||
break;
|
||||
|
||||
|
||||
case 4: // Custom
|
||||
video.SetSaturation(conf.video_saturation);
|
||||
video.SetSharpness(conf.video_ntsc_sharpness);
|
||||
|
@ -381,23 +310,23 @@ void video_set_filter() {
|
|||
video.SetColorArtifacts(conf.video_ntsc_artifacts);
|
||||
video.SetColorFringing(conf.video_ntsc_fringing);
|
||||
break;
|
||||
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set xBR options
|
||||
if (conf.video_filter == 2) {
|
||||
video.SetCornerRounding(conf.video_xbr_corner_rounding);
|
||||
video.SetBlend(conf.video_xbr_pixel_blending);
|
||||
}
|
||||
|
||||
|
||||
// Set up the render state parameters
|
||||
renderstate.filter = filter;
|
||||
renderstate.width = basesize.w;
|
||||
renderstate.height = basesize.h;
|
||||
renderstate.bits.count = 32;
|
||||
|
||||
|
||||
int e = 1; // Check Endianness
|
||||
if ((int)*((unsigned char *)&e) == 1) { // Little Endian
|
||||
renderstate.bits.mask.r = 0x00ff0000;
|
||||
|
@ -409,7 +338,7 @@ void video_set_filter() {
|
|||
renderstate.bits.mask.g = 0xff000000;
|
||||
renderstate.bits.mask.b = 0x00ff0000;
|
||||
}
|
||||
|
||||
|
||||
if (NES_FAILED(video.SetRenderState(renderstate))) {
|
||||
fprintf(stderr, "Nestopia core rejected render state\n");
|
||||
exit(1);
|
||||
|
@ -437,7 +366,7 @@ void video_set_dimensions() {
|
|||
if ((conf.video_scale_factor > 3) && (conf.video_filter == 5)) { scalefactor = 3; }
|
||||
int wscalefactor = conf.video_scale_factor;
|
||||
int tvwidth = nst_pal() ? PAL_TV_WIDTH : TV_WIDTH;
|
||||
|
||||
|
||||
switch(conf.video_filter) {
|
||||
case 0: // None
|
||||
basesize.w = Video::Output::WIDTH;
|
||||
|
@ -467,7 +396,7 @@ void video_set_dimensions() {
|
|||
overscan_offset = basesize.w * OVERSCAN_TOP * scalefactor;
|
||||
overscan_height = basesize.h - (OVERSCAN_TOP + OVERSCAN_BOTTOM) * scalefactor;
|
||||
break;
|
||||
|
||||
|
||||
case 4: // 2xSaI
|
||||
basesize.w = Video::Output::WIDTH * 2;
|
||||
basesize.h = Video::Output::HEIGHT * 2;
|
||||
|
@ -482,9 +411,13 @@ void video_set_dimensions() {
|
|||
rendersize.h -= (OVERSCAN_TOP + OVERSCAN_BOTTOM) * scalefactor;
|
||||
}
|
||||
else { overscan_offset = 0; overscan_height = basesize.h; }
|
||||
|
||||
|
||||
// Calculate the aspect from the height because it's smaller
|
||||
float aspect = (float)screensize.h / (float)rendersize.h;
|
||||
if (conf.video_fullscreen) {
|
||||
float aspect = (float)screensize.h / (float)rendersize.h;
|
||||
rendersize.w *= aspect;
|
||||
rendersize.h *= aspect;
|
||||
}
|
||||
}
|
||||
|
||||
long video_lock_screen(void*& ptr) {
|
||||
|
@ -493,15 +426,14 @@ long video_lock_screen(void*& ptr) {
|
|||
}
|
||||
|
||||
void video_unlock_screen(void*) {
|
||||
|
||||
int xscale = renderstate.width / Video::Output::WIDTH;;
|
||||
int yscale = renderstate.height / Video::Output::HEIGHT;
|
||||
|
||||
|
||||
if (osdtext.drawtext) {
|
||||
nst_video_text_draw(osdtext.textbuf, osdtext.xpos * xscale, osdtext.ypos * yscale, osdtext.bg);
|
||||
osdtext.drawtext--;
|
||||
}
|
||||
|
||||
|
||||
if (osdtext.drawtime) {
|
||||
nst_video_text_draw(osdtext.timebuf, 208 * xscale, 218 * yscale, false);
|
||||
}
|
||||
|
@ -513,7 +445,7 @@ void video_screenshot_flip(unsigned char *pixels, int width, int height, int byt
|
|||
unsigned char *row = (unsigned char*)malloc(rowsize);
|
||||
unsigned char *low = pixels;
|
||||
unsigned char *high = &pixels[(height - 1) * rowsize];
|
||||
|
||||
|
||||
for (; low < high; low += rowsize, high -= rowsize) {
|
||||
memcpy(row, low, rowsize);
|
||||
memcpy(low, high, rowsize);
|
||||
|
@ -526,16 +458,16 @@ void video_screenshot(const char* filename) {
|
|||
// Take a screenshot in .png format
|
||||
unsigned char *pixels;
|
||||
pixels = (unsigned char*)malloc(sizeof(unsigned char) * rendersize.w * rendersize.h * 4);
|
||||
|
||||
|
||||
// Read the pixels and flip them vertically
|
||||
glReadPixels(0, 0, rendersize.w, rendersize.h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
video_screenshot_flip(pixels, rendersize.w, rendersize.h, 4);
|
||||
|
||||
|
||||
if (filename == NULL) {
|
||||
// Set the filename
|
||||
char sshotpath[512];
|
||||
snprintf(sshotpath, sizeof(sshotpath), "%sscreenshots/%s-%ld-%d.png", nstpaths.nstdir, nstpaths.gamename, time(NULL), rand() % 899 + 100);
|
||||
|
||||
|
||||
// Save the file
|
||||
lodepng_encode32_file(sshotpath, (const unsigned char*)pixels, rendersize.w, rendersize.h);
|
||||
fprintf(stderr, "Screenshot: %s\n", sshotpath);
|
||||
|
@ -543,7 +475,7 @@ void video_screenshot(const char* filename) {
|
|||
else {
|
||||
lodepng_encode32_file(filename, (const unsigned char*)pixels, rendersize.w, rendersize.h);
|
||||
}
|
||||
|
||||
|
||||
free(pixels);
|
||||
}
|
||||
|
||||
|
@ -555,50 +487,18 @@ void video_clear_buffer() {
|
|||
void video_disp_nsf() {
|
||||
// Display NSF text
|
||||
Nsf nsf(emulator);
|
||||
|
||||
|
||||
int xscale = renderstate.width / Video::Output::WIDTH;;
|
||||
int yscale = renderstate.height / Video::Output::HEIGHT;;
|
||||
|
||||
|
||||
nst_video_text_draw(nsf.GetName(), 4 * xscale, 16 * yscale, false);
|
||||
nst_video_text_draw(nsf.GetArtist(), 4 * xscale, 28 * yscale, false);
|
||||
nst_video_text_draw(nsf.GetCopyright(), 4 * xscale, 40 * yscale, false);
|
||||
|
||||
|
||||
char currentsong[10];
|
||||
snprintf(currentsong, sizeof(currentsong), "%d / %d", nsf.GetCurrentSong() +1, nsf.GetNumSongs());
|
||||
nst_video_text_draw(currentsong, 4 * xscale, 52 * yscale, false);
|
||||
|
||||
nst_ogl_render();
|
||||
}
|
||||
|
||||
void nst_video_disp_inputconf(int type, int pnum, int bnum) {
|
||||
|
||||
int xscale = renderstate.width / Video::Output::WIDTH;;
|
||||
int yscale = renderstate.height / Video::Output::HEIGHT;;
|
||||
|
||||
char textbuf[32];
|
||||
char buttontext[8];
|
||||
|
||||
if (type == 0) { snprintf(textbuf, sizeof(textbuf), "Player %d Keyboard Configuration", pnum + 1); }
|
||||
else { snprintf(textbuf, sizeof(textbuf), "Player %d Joystick Configuration", pnum + 1); }
|
||||
|
||||
switch (bnum) {
|
||||
case 0: snprintf(buttontext, sizeof(buttontext), "Up"); break;
|
||||
case 1: snprintf(buttontext, sizeof(buttontext), "Down"); break;
|
||||
case 2: snprintf(buttontext, sizeof(buttontext), "Left"); break;
|
||||
case 3: snprintf(buttontext, sizeof(buttontext), "Right"); break;
|
||||
case 4: snprintf(buttontext, sizeof(buttontext), "Select"); break;
|
||||
case 5: snprintf(buttontext, sizeof(buttontext), "Start"); break;
|
||||
case 6: snprintf(buttontext, sizeof(buttontext), "A"); break;
|
||||
case 7: snprintf(buttontext, sizeof(buttontext), "B"); break;
|
||||
case 8: snprintf(buttontext, sizeof(buttontext), "Turbo A"); break;
|
||||
case 9: snprintf(buttontext, sizeof(buttontext), "Turbo B"); break;
|
||||
}
|
||||
|
||||
video_clear_buffer();
|
||||
|
||||
nst_video_text_draw(textbuf, 4 * xscale, 64 * yscale, false);
|
||||
nst_video_text_draw(buttontext, 112 * xscale, 128 * yscale, false);
|
||||
|
||||
nst_ogl_render();
|
||||
}
|
||||
|
||||
|
@ -621,13 +521,13 @@ void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg) {
|
|||
uint32_t b = 0x00000000; // Black
|
||||
uint32_t g = 0x00358570; // Nestopia UE Green
|
||||
uint32_t d = 0x00255f65; // Nestopia UE Dark Green
|
||||
|
||||
|
||||
int numchars = strlen(text);
|
||||
|
||||
|
||||
int letterypos;
|
||||
int letterxpos;
|
||||
int letternum = 0;
|
||||
|
||||
|
||||
if (bg) { // Draw background borders
|
||||
for (int i = 0; i < numchars * 8; i++) { // Rows above and below
|
||||
videobuf[(xpos + i) + ((ypos - 1) * renderstate.width)] = g;
|
||||
|
@ -638,7 +538,7 @@ void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg) {
|
|||
videobuf[(xpos + (numchars * 8)) + ((ypos + i) * renderstate.width)] = g;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int tpos = 0; tpos < (8 * numchars); tpos+=8) {
|
||||
nst_video_text_match(text, &letterxpos, &letterypos, letternum);
|
||||
for (int row = 0; row < 8; row++) { // Draw Rows
|
||||
|
@ -647,11 +547,11 @@ void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg) {
|
|||
case '.':
|
||||
videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = w;
|
||||
break;
|
||||
|
||||
|
||||
case '+':
|
||||
videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = g;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
if (bg) { videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = d; }
|
||||
break;
|
|
@ -10,11 +10,6 @@
|
|||
|
||||
#define VIDBUF_MAXSIZE 31457280
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#ifdef _APPLE
|
||||
#include <OpenGL/gl.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int w;
|
||||
int h;
|
||||
|
@ -35,9 +30,7 @@ void nst_ogl_deinit();
|
|||
void nst_ogl_render();
|
||||
|
||||
void video_init();
|
||||
void video_toggle_filter();
|
||||
void video_toggle_filterupdate();
|
||||
void video_toggle_scalefactor();
|
||||
void video_set_filter();
|
||||
|
||||
dimensions_t nst_video_get_dimensions_render();
|
||||
|
@ -50,7 +43,6 @@ void video_unlock_screen(void*);
|
|||
void video_screenshot(const char* filename);
|
||||
void video_clear_buffer();
|
||||
void video_disp_nsf();
|
||||
void nst_video_disp_inputconf(int type, int pnum, int bnum);
|
||||
void nst_video_print(const char *text, int xpos, int ypos, int seconds, bool bg);
|
||||
void nst_video_print_time(const char *timebuf, bool drawtime);
|
||||
void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg);
|
|
@ -1,696 +0,0 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2018 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "cli.h"
|
||||
#include "config.h"
|
||||
#include "audio.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
|
||||
#include "sdlinput.h"
|
||||
|
||||
#include "gtkui.h"
|
||||
#include "gtkui_archive.h"
|
||||
#include "gtkui_callbacks.h"
|
||||
#include "gtkui_config.h"
|
||||
#include "gtkui_cheats.h"
|
||||
#include "gtkui_dialogs.h"
|
||||
#include "gtkui_input.h"
|
||||
|
||||
GtkWidget *gtkwindow;
|
||||
static GtkWidget *menubar;
|
||||
static GtkWidget *drawingarea;
|
||||
|
||||
static GThread *emuthread;
|
||||
|
||||
char iconpath[512];
|
||||
char padpath[512];
|
||||
|
||||
extern bool (*nst_archive_select)(const char*, char*, size_t);
|
||||
|
||||
extern Input::Controllers *cNstPads;
|
||||
extern nstpaths_t nstpaths;
|
||||
int nst_quit = 1;
|
||||
|
||||
gpointer gtkui_emuloop(gpointer data) {
|
||||
while(!nst_quit) { nst_emuloop(); }
|
||||
g_thread_exit(emuthread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void gtkui_emuloop_start() {
|
||||
nst_quit = 0;
|
||||
emuthread = g_thread_new("emuloop", gtkui_emuloop, NULL);
|
||||
}
|
||||
|
||||
void gtkui_emuloop_stop() {
|
||||
nst_quit = true;
|
||||
}
|
||||
|
||||
void gtkui_quit() {
|
||||
gtkui_emuloop_stop();
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
static void gtkui_glarea_realize(GtkGLArea *glarea) {
|
||||
gtk_gl_area_make_current(glarea);
|
||||
gtk_gl_area_set_has_depth_buffer(glarea, FALSE);
|
||||
nst_ogl_init();
|
||||
}
|
||||
|
||||
static void gtkui_swapbuffers() {
|
||||
gtk_widget_queue_draw(drawingarea);
|
||||
gtk_widget_queue_draw(menubar); // Needed on some builds of GTK3
|
||||
nst_ogl_render();
|
||||
nst_emuloop();
|
||||
|
||||
// Move this later FIXME
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_JOYHATMOTION:
|
||||
case SDL_JOYAXISMOTION:
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
nstsdl_input_process(cNstPads, event);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_state_quickload(GtkWidget *widget, gpointer userdata) {
|
||||
// Wrapper function to quickload states
|
||||
nst_state_quickload(GPOINTER_TO_INT(userdata));
|
||||
}
|
||||
|
||||
void gtkui_state_quicksave(GtkWidget *widget, gpointer userdata) {
|
||||
// Wrapper function to quicksave states
|
||||
nst_state_quicksave(GPOINTER_TO_INT(userdata));
|
||||
}
|
||||
|
||||
void gtkui_open_recent(GtkWidget *widget, gpointer userdata) {
|
||||
// Open a recently used item
|
||||
gchar *uri = gtk_recent_chooser_get_current_uri((GtkRecentChooser*)widget);
|
||||
nst_load(g_filename_from_uri(uri, NULL, NULL));
|
||||
gtkui_set_title(nstpaths.gamename);
|
||||
gtkui_play();
|
||||
}
|
||||
|
||||
dimensions_t gtkui_video_get_dimensions() {
|
||||
// Return the dimensions of the current screen
|
||||
dimensions_t scrsize;
|
||||
dimensions_t rendsize = nst_video_get_dimensions_render();
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
GdkWindow *gdkwindow = gtk_widget_get_window(GTK_WIDGET(gtkwindow));
|
||||
GdkMonitor *monitor = gdk_display_get_monitor_at_window(display, gdkwindow);
|
||||
GdkRectangle geom;
|
||||
gdk_monitor_get_geometry(monitor, &geom);
|
||||
scrsize.w = geom.width;
|
||||
scrsize.h = geom.height;
|
||||
float ratio = (float)scrsize.h / (float)rendsize.h;
|
||||
scrsize.w = (int)(rendsize.w * ratio);
|
||||
return scrsize;
|
||||
}
|
||||
|
||||
void gtkui_create() {
|
||||
// Create the GTK Window
|
||||
|
||||
gtkui_image_paths();
|
||||
GdkPixbuf *icon = gdk_pixbuf_new_from_file(iconpath, NULL);
|
||||
|
||||
char title[24];
|
||||
snprintf(title, sizeof(title), "Nestopia UE");
|
||||
|
||||
gtkwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_icon(GTK_WINDOW(gtkwindow), icon);
|
||||
gtk_window_set_title(GTK_WINDOW(gtkwindow), title);
|
||||
gtk_window_set_resizable(GTK_WINDOW(gtkwindow), FALSE);
|
||||
|
||||
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add(GTK_CONTAINER(gtkwindow), box);
|
||||
|
||||
// Define the menubar and menus
|
||||
menubar = gtk_menu_bar_new();
|
||||
|
||||
// Define the File menu
|
||||
GtkWidget *filemenu = gtk_menu_new();
|
||||
GtkWidget *file = gtk_menu_item_new_with_label("File");
|
||||
GtkWidget *open = gtk_menu_item_new_with_label("Open...");
|
||||
GtkWidget *recent = gtk_menu_item_new_with_label("Open Recent");
|
||||
GtkWidget *sep_open = gtk_separator_menu_item_new();
|
||||
GtkWidget *stateload = gtk_menu_item_new_with_label("Load State...");
|
||||
GtkWidget *statesave = gtk_menu_item_new_with_label("Save State...");
|
||||
|
||||
GtkWidget *quickload = gtk_menu_item_new_with_label("Quick Load");
|
||||
GtkWidget *qloadmenu = gtk_menu_new();
|
||||
GtkWidget *qload0 = gtk_menu_item_new_with_label("0");
|
||||
GtkWidget *qload1 = gtk_menu_item_new_with_label("1");
|
||||
GtkWidget *qload2 = gtk_menu_item_new_with_label("2");
|
||||
GtkWidget *qload3 = gtk_menu_item_new_with_label("3");
|
||||
GtkWidget *qload4 = gtk_menu_item_new_with_label("4");
|
||||
|
||||
GtkWidget *quicksave = gtk_menu_item_new_with_label("Quick Save");
|
||||
GtkWidget *qsavemenu = gtk_menu_new();
|
||||
GtkWidget *qsave0 = gtk_menu_item_new_with_label("0");
|
||||
GtkWidget *qsave1 = gtk_menu_item_new_with_label("1");
|
||||
GtkWidget *qsave2 = gtk_menu_item_new_with_label("2");
|
||||
GtkWidget *qsave3 = gtk_menu_item_new_with_label("3");
|
||||
GtkWidget *qsave4 = gtk_menu_item_new_with_label("4");
|
||||
|
||||
GtkWidget *sep_state = gtk_separator_menu_item_new();
|
||||
GtkWidget *palette = gtk_menu_item_new_with_label("Open Palette...");
|
||||
GtkWidget *sep_palette = gtk_separator_menu_item_new();
|
||||
GtkWidget *screenshot = gtk_menu_item_new_with_label("Screenshot...");
|
||||
GtkWidget *sep_screenshot = gtk_separator_menu_item_new();
|
||||
GtkWidget *movieload = gtk_menu_item_new_with_label("Load Movie...");
|
||||
GtkWidget *moviesave = gtk_menu_item_new_with_label("Record Movie...");
|
||||
GtkWidget *moviestop = gtk_menu_item_new_with_label("Stop Movie");
|
||||
GtkWidget *sep_movie = gtk_separator_menu_item_new();
|
||||
GtkWidget *quit = gtk_menu_item_new_with_label("Quit");
|
||||
|
||||
// Set up the recently used items
|
||||
GtkWidget *recent_items = gtk_recent_chooser_menu_new();
|
||||
GtkRecentFilter *recent_filter = gtk_recent_filter_new();
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.nes");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.fds");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.unf");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.unif");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.nsf");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.zip");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.7z");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.txz");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.tar.xz");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.xz");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.tgz");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.tar.gz");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.gz");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.tbz");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.tar.bz2");
|
||||
gtk_recent_filter_add_pattern(recent_filter, "*.bz2");
|
||||
gtk_recent_chooser_add_filter(GTK_RECENT_CHOOSER(recent_items), recent_filter);
|
||||
|
||||
// Populate the File menu
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), recent);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), recent_items);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_open);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), stateload);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), statesave);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quickload);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(quickload), qloadmenu);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload0);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload1);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload2);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload3);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload4);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quicksave);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(quicksave), qsavemenu);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave0);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave1);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave2);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave3);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave4);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_state);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), palette);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_palette);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), screenshot);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_screenshot);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), movieload);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), moviesave);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), moviestop);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_movie);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
|
||||
|
||||
// Define the Emulator menu
|
||||
GtkWidget *emulatormenu = gtk_menu_new();
|
||||
GtkWidget *emu = gtk_menu_item_new_with_label("Emulator");
|
||||
GtkWidget *cont = gtk_menu_item_new_with_label("Continue");
|
||||
GtkWidget *pause = gtk_menu_item_new_with_label("Pause");
|
||||
GtkWidget *sep_pause = gtk_separator_menu_item_new();
|
||||
GtkWidget *resetsoft = gtk_menu_item_new_with_label("Reset (Soft)");
|
||||
GtkWidget *resethard = gtk_menu_item_new_with_label("Reset (Hard)");
|
||||
GtkWidget *sep_reset = gtk_separator_menu_item_new();
|
||||
GtkWidget *fullscreen = gtk_menu_item_new_with_label("Fullscreen");
|
||||
GtkWidget *sep_fullscreen = gtk_separator_menu_item_new();
|
||||
GtkWidget *diskflip = gtk_menu_item_new_with_label("Flip FDS Disk");
|
||||
GtkWidget *diskswitch = gtk_menu_item_new_with_label("Switch FDS Disk");
|
||||
GtkWidget *sep_disk = gtk_separator_menu_item_new();
|
||||
GtkWidget *cheats = gtk_menu_item_new_with_label("Cheats...");
|
||||
GtkWidget *sep_cheats = gtk_separator_menu_item_new();
|
||||
GtkWidget *configuration = gtk_menu_item_new_with_label("Configuration...");
|
||||
|
||||
// Populate the Emulator menu
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(emu), emulatormenu);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), cont);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), pause);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_pause);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), resetsoft);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), resethard);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_reset);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), fullscreen);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_fullscreen);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), diskflip);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), diskswitch);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_disk);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), cheats);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_cheats);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), configuration);
|
||||
|
||||
// Define the Help menu
|
||||
GtkWidget *helpmenu = gtk_menu_new();
|
||||
GtkWidget *help = gtk_menu_item_new_with_label("Help");
|
||||
GtkWidget *about = gtk_menu_item_new_with_label("About");
|
||||
|
||||
// Populate the Help menu
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(help), helpmenu);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu), about);
|
||||
|
||||
// Put the menus into the menubar
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), emu);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), help);
|
||||
|
||||
// Create the DrawingArea/OpenGL context
|
||||
drawingarea = gtk_gl_area_new();
|
||||
g_signal_connect(G_OBJECT(drawingarea), "realize", G_CALLBACK(gtkui_glarea_realize), NULL);
|
||||
g_signal_connect(G_OBJECT(drawingarea), "render", gtkui_swapbuffers, NULL);
|
||||
|
||||
g_object_set_data(G_OBJECT(gtkwindow), "area", drawingarea);
|
||||
|
||||
// Set the Drawing Area to be the size of the game output
|
||||
dimensions_t rendersize = nst_video_get_dimensions_render();
|
||||
gtk_widget_set_size_request(drawingarea, rendersize.w, rendersize.h);
|
||||
|
||||
// Pack the box with the menubar, drawingarea, and statusbar
|
||||
gtk_box_pack_start(GTK_BOX(box), menubar, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(box), drawingarea, TRUE, TRUE, 0);
|
||||
|
||||
// Make it dark if there's a dark theme
|
||||
GtkSettings *gtksettings = gtk_settings_get_default();
|
||||
g_object_set(G_OBJECT(gtksettings), "gtk-application-prefer-dark-theme", TRUE, nullptr);
|
||||
|
||||
// Set up the Drag and Drop target
|
||||
GtkTargetEntry target_entry[1];
|
||||
|
||||
target_entry[0].target = (gchar*)"text/uri-list";
|
||||
target_entry[0].flags = 0;
|
||||
target_entry[0].info = 0;
|
||||
|
||||
gtk_drag_dest_set(drawingarea, (GtkDestDefaults)(GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP),
|
||||
target_entry, sizeof(target_entry) / sizeof(GtkTargetEntry), (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY));
|
||||
|
||||
// Connect the signals
|
||||
g_signal_connect(G_OBJECT(drawingarea), "drag-data-received",
|
||||
G_CALLBACK(gtkui_drag_data), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(gtkwindow), "delete_event",
|
||||
G_CALLBACK(gtkui_quit), NULL);
|
||||
|
||||
// File menu
|
||||
g_signal_connect(G_OBJECT(open), "activate",
|
||||
G_CALLBACK(gtkui_file_open), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(recent_items), "item-activated",
|
||||
G_CALLBACK(gtkui_open_recent), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(stateload), "activate",
|
||||
G_CALLBACK(gtkui_state_load), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(statesave), "activate",
|
||||
G_CALLBACK(gtkui_state_save), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(qload0), "activate",
|
||||
G_CALLBACK(gtkui_state_quickload), gpointer(0));
|
||||
|
||||
g_signal_connect(G_OBJECT(qload1), "activate",
|
||||
G_CALLBACK(gtkui_state_quickload), gpointer(1));
|
||||
|
||||
g_signal_connect(G_OBJECT(qload2), "activate",
|
||||
G_CALLBACK(gtkui_state_quickload), gpointer(2));
|
||||
|
||||
g_signal_connect(G_OBJECT(qload3), "activate",
|
||||
G_CALLBACK(gtkui_state_quickload), gpointer(3));
|
||||
|
||||
g_signal_connect(G_OBJECT(qload4), "activate",
|
||||
G_CALLBACK(gtkui_state_quickload), gpointer(4));
|
||||
|
||||
g_signal_connect(G_OBJECT(qsave0), "activate",
|
||||
G_CALLBACK(gtkui_state_quicksave), gpointer(0));
|
||||
|
||||
g_signal_connect(G_OBJECT(qsave1), "activate",
|
||||
G_CALLBACK(gtkui_state_quicksave), gpointer(1));
|
||||
|
||||
g_signal_connect(G_OBJECT(qsave2), "activate",
|
||||
G_CALLBACK(gtkui_state_quicksave), gpointer(2));
|
||||
|
||||
g_signal_connect(G_OBJECT(qsave3), "activate",
|
||||
G_CALLBACK(gtkui_state_quicksave), gpointer(3));
|
||||
|
||||
g_signal_connect(G_OBJECT(qsave4), "activate",
|
||||
G_CALLBACK(gtkui_state_quicksave), gpointer(4));
|
||||
|
||||
g_signal_connect(G_OBJECT(screenshot), "activate",
|
||||
G_CALLBACK(gtkui_screenshot_save), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(palette), "activate",
|
||||
G_CALLBACK(gtkui_palette_load), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(moviesave), "activate",
|
||||
G_CALLBACK(gtkui_movie_save), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(movieload), "activate",
|
||||
G_CALLBACK(gtkui_movie_load), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(moviestop), "activate",
|
||||
G_CALLBACK(gtkui_movie_stop), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(quit), "activate",
|
||||
G_CALLBACK(gtkui_quit), NULL);
|
||||
|
||||
// Emulator menu
|
||||
g_signal_connect(G_OBJECT(cont), "activate",
|
||||
G_CALLBACK(gtkui_play), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(pause), "activate",
|
||||
G_CALLBACK(gtkui_pause), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(resetsoft), "activate",
|
||||
G_CALLBACK(gtkui_cb_reset), gpointer(0));
|
||||
|
||||
g_signal_connect(G_OBJECT(resethard), "activate",
|
||||
G_CALLBACK(gtkui_cb_reset), gpointer(1));
|
||||
|
||||
g_signal_connect(G_OBJECT(fullscreen), "activate",
|
||||
G_CALLBACK(gtkui_video_toggle_fullscreen), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(diskflip), "activate",
|
||||
G_CALLBACK(nst_fds_flip), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(diskswitch), "activate",
|
||||
G_CALLBACK(nst_fds_switch), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(cheats), "activate",
|
||||
G_CALLBACK(gtkui_cheats), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(configuration), "activate",
|
||||
G_CALLBACK(gtkui_config), NULL);
|
||||
|
||||
// Help menu
|
||||
g_signal_connect(G_OBJECT(about), "activate",
|
||||
G_CALLBACK(gtkui_about), NULL);
|
||||
|
||||
// Mouse input events
|
||||
gtk_widget_add_events(GTK_WIDGET(drawingarea), GDK_BUTTON_PRESS_MASK);
|
||||
gtk_widget_add_events(GTK_WIDGET(drawingarea), GDK_BUTTON_RELEASE_MASK);
|
||||
|
||||
gtk_widget_show_all(gtkwindow);
|
||||
|
||||
nst_video_set_dimensions_screen(gtkui_video_get_dimensions());
|
||||
}
|
||||
|
||||
void gtkui_signals_init() {
|
||||
// Key translation
|
||||
if (nst_nsf()) {
|
||||
g_signal_connect(G_OBJECT(gtkwindow), "key-press-event",
|
||||
G_CALLBACK(gtkui_input_process_key_nsf), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(gtkwindow), "key-release-event",
|
||||
G_CALLBACK(gtkui_input_process_key_nsf), NULL);
|
||||
}
|
||||
else {
|
||||
g_signal_connect(G_OBJECT(gtkwindow), "key-press-event",
|
||||
G_CALLBACK(gtkui_input_process_key), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(gtkwindow), "key-release-event",
|
||||
G_CALLBACK(gtkui_input_process_key), NULL);
|
||||
}
|
||||
// Mouse translation
|
||||
g_signal_connect(G_OBJECT(drawingarea), "button-press-event",
|
||||
G_CALLBACK(gtkui_input_process_mouse), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(drawingarea), "button-release-event",
|
||||
G_CALLBACK(gtkui_input_process_mouse), NULL);
|
||||
}
|
||||
|
||||
void gtkui_signals_deinit() {
|
||||
// Key translation
|
||||
g_signal_connect(G_OBJECT(gtkwindow), "key-press-event",
|
||||
gtkui_input_null, NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(gtkwindow), "key-release-event",
|
||||
gtkui_input_null, NULL);
|
||||
|
||||
// Mouse translation
|
||||
g_signal_connect(G_OBJECT(drawingarea), "button-press-event",
|
||||
gtkui_input_null, NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(drawingarea), "button-release-event",
|
||||
gtkui_input_null, NULL);
|
||||
}
|
||||
|
||||
void gtkui_resize() {
|
||||
// Resize the GTK window
|
||||
if (gtkwindow) {
|
||||
dimensions_t rendersize;
|
||||
if (conf.video_fullscreen) { rendersize = gtkui_video_get_dimensions(); }
|
||||
else { rendersize = nst_video_get_dimensions_render(); }
|
||||
gtk_widget_set_size_request(drawingarea, rendersize.w, rendersize.h);
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_set_title(const char *title) {
|
||||
gtk_window_set_title(GTK_WINDOW(gtkwindow), title);
|
||||
}
|
||||
|
||||
void gtkui_video_toggle_fullscreen() {
|
||||
conf.video_fullscreen ^= 1;
|
||||
|
||||
if (conf.video_fullscreen) {
|
||||
gtk_widget_hide(menubar);
|
||||
gtk_window_fullscreen(GTK_WINDOW(gtkwindow));
|
||||
if (nst_input_zapper_present()) {
|
||||
gtkui_cursor_set(conf.misc_disable_cursor_special ? 0 : 2);
|
||||
}
|
||||
else {gtkui_cursor_set(0); }
|
||||
}
|
||||
else {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(gtkwindow));
|
||||
gtk_widget_show(menubar);
|
||||
if (nst_input_zapper_present()) {
|
||||
gtkui_cursor_set(conf.misc_disable_cursor_special ? 0 : 2);
|
||||
}
|
||||
else {gtkui_cursor_set(1); }
|
||||
}
|
||||
nst_video_set_dimensions_screen(gtkui_video_get_dimensions());
|
||||
|
||||
gtkui_resize();
|
||||
video_init();
|
||||
}
|
||||
|
||||
void gtkui_video_toggle_filter() {
|
||||
video_toggle_filter();
|
||||
gtkui_resize();
|
||||
video_init();
|
||||
}
|
||||
|
||||
void gtkui_video_toggle_scale() {
|
||||
video_toggle_scalefactor();
|
||||
gtkui_resize();
|
||||
video_init();
|
||||
}
|
||||
|
||||
GtkWidget *gtkui_about() {
|
||||
// Pull up the About dialog
|
||||
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size(iconpath, 192, 192, NULL);
|
||||
GtkWidget *aboutdialog = gtk_about_dialog_new();
|
||||
gtk_window_set_transient_for(GTK_WINDOW(aboutdialog), GTK_WINDOW(gtkwindow));
|
||||
|
||||
gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(aboutdialog), pixbuf);
|
||||
gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(aboutdialog), "Nestopia UE");
|
||||
gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(aboutdialog), "vx.xx");
|
||||
gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(aboutdialog), "Cycle-Accurate Nintendo Entertainment System Emulator");
|
||||
gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(aboutdialog), "http://0ldsk00l.ca/nestopia/");
|
||||
gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(aboutdialog), "GTK Frontend\n(c) 2012-2021, R. Danbrook\n(c) 2007-2008, R. Belmont\n\nNestopia Emulator\n(c) 2020-2021, Rupert Carmichael\n(c) 2012-2020, Nestopia UE Contributors\n(c) 2003-2008, Martin Freij\n\nIcon based on art from Trollekop");
|
||||
gtk_dialog_run(GTK_DIALOG(aboutdialog));
|
||||
gtk_widget_destroy(aboutdialog);
|
||||
|
||||
return aboutdialog;
|
||||
}
|
||||
|
||||
void gtkui_image_paths() {
|
||||
// Set paths to SVG icons/images
|
||||
snprintf(iconpath, sizeof(iconpath), "%s/icons/hicolor/scalable/apps/nestopia.svg", DATAROOTDIR);
|
||||
snprintf(padpath, sizeof(padpath), "%s/icons/hicolor/scalable/apps/nespad.svg", DATAROOTDIR);
|
||||
|
||||
// Load the SVG from local source dir if make install hasn't been done
|
||||
struct stat svgstat;
|
||||
if (stat(iconpath, &svgstat) == -1) {
|
||||
snprintf(iconpath, sizeof(iconpath), "icons/svg/nestopia.svg");
|
||||
}
|
||||
if (stat(padpath, &svgstat) == -1) {
|
||||
snprintf(padpath, sizeof(padpath), "icons/svg/nespad.svg");
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_message(const char* message) {
|
||||
GtkWidget *messagewindow = gtk_message_dialog_new(
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_INFO,
|
||||
GTK_BUTTONS_OK,
|
||||
"%s", message);
|
||||
gtk_dialog_run(GTK_DIALOG(messagewindow));
|
||||
gtk_widget_destroy(messagewindow);
|
||||
}
|
||||
|
||||
void gtkui_cursor_set(int curtype) {
|
||||
// Set the cursor
|
||||
GdkCursor *cursor;
|
||||
GdkDisplay *display = gdk_display_get_default();
|
||||
|
||||
switch (curtype) {
|
||||
case 0: cursor = gdk_cursor_new_from_name(display, "none"); break;
|
||||
case 1: cursor = gdk_cursor_new_from_name(display, "default"); break;
|
||||
case 2: cursor = gdk_cursor_new_from_name(display, "crosshair"); break;
|
||||
default: cursor = gdk_cursor_new_from_name(display, "default"); break;
|
||||
}
|
||||
|
||||
GdkWindow *gdkwindow = gtk_widget_get_window(GTK_WIDGET(drawingarea));
|
||||
gdk_window_set_cursor(gdkwindow, cursor);
|
||||
gdk_display_flush(display);
|
||||
g_object_unref(cursor);
|
||||
}
|
||||
|
||||
void gtkui_play() {
|
||||
gtkui_signals_init();
|
||||
nst_play();
|
||||
|
||||
if (nst_input_zapper_present()) {
|
||||
gtkui_cursor_set(conf.misc_disable_cursor_special ? 0 : 2);
|
||||
}
|
||||
else {
|
||||
gtkui_cursor_set(conf.misc_disable_cursor ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_pause() {
|
||||
gtkui_signals_deinit();
|
||||
nst_pause();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// Set up directories
|
||||
nst_set_dirs();
|
||||
|
||||
// Set default config options
|
||||
config_set_default();
|
||||
|
||||
// Read the config file and override defaults
|
||||
config_file_read(nstpaths.nstconfdir);
|
||||
|
||||
// Handle command line arguments
|
||||
cli_handle_command(argc, argv);
|
||||
|
||||
// Set default input keys
|
||||
gtkui_input_set_default();
|
||||
|
||||
// Read the input config file and override defaults
|
||||
gtkui_input_config_read();
|
||||
|
||||
// Set the video dimensions
|
||||
video_set_dimensions();
|
||||
|
||||
// Set up callbacks
|
||||
nst_set_callbacks();
|
||||
|
||||
// Initialize SDL Audio and Joystick
|
||||
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) {
|
||||
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set archive handler function pointer
|
||||
nst_archive_select = >kui_archive_select;
|
||||
|
||||
// Detect and set up Joysticks
|
||||
nstsdl_input_joysticks_detect();
|
||||
nstsdl_input_conf_defaults();
|
||||
nstsdl_input_conf_read();
|
||||
|
||||
// Initialize and load FDS BIOS and NstDatabase.xml
|
||||
nst_fds_bios_load();
|
||||
nst_db_load();
|
||||
|
||||
// Initialize the GTK GUI
|
||||
gtk_init(&argc, &argv);
|
||||
gtkui_create();
|
||||
|
||||
// Load a rom from the command line
|
||||
if (argc > 1 && argv[argc - 1][0] != '-') {
|
||||
nst_load(argv[argc - 1]);
|
||||
if (conf.video_fullscreen) {
|
||||
conf.video_fullscreen = 0;
|
||||
gtkui_video_toggle_fullscreen();
|
||||
}
|
||||
gtkui_play();
|
||||
gtkui_set_title(nstpaths.gamename);
|
||||
}
|
||||
else if (conf.video_fullscreen) { conf.video_fullscreen = 0; }
|
||||
|
||||
// Start GTK main loop
|
||||
gtk_main();
|
||||
|
||||
// Remove the cartridge and shut down the NES
|
||||
nst_unload();
|
||||
|
||||
// Unload the FDS BIOS, NstDatabase.xml, and the custom palette
|
||||
nst_db_unload();
|
||||
nst_fds_bios_unload();
|
||||
nst_palette_unload();
|
||||
|
||||
// Deinitialize audio
|
||||
audio_deinit();
|
||||
|
||||
// Deinitialize joysticks
|
||||
nstsdl_input_joysticks_close();
|
||||
|
||||
// Write the input config file
|
||||
nstsdl_input_conf_write();
|
||||
|
||||
// Write the input config file
|
||||
gtkui_input_config_write();
|
||||
|
||||
// Write the config file
|
||||
config_file_write(nstpaths.nstconfdir);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef _GTKUI_H_
|
||||
#define _GTKUI_H_
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
void gtkui_emuloop_start();
|
||||
void gtkui_emuloop_stop();
|
||||
void gtkui_create();
|
||||
void gtkui_resize();
|
||||
void gtkui_set_title(const char *title);
|
||||
GtkWidget *gtkui_about();
|
||||
void gtkui_image_paths();
|
||||
void gtkui_message(const char* message);
|
||||
void gtkui_cursor_set(int curtype);
|
||||
void gtkui_video_toggle_fullscreen();
|
||||
void gtkui_video_toggle_filter();
|
||||
void gtkui_video_toggle_scale();
|
||||
void gtkui_signals_init();
|
||||
void gtkui_signals_deinit();
|
||||
void gtkui_play();
|
||||
void gtkui_pause();
|
||||
|
||||
#endif
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2016 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkui.h"
|
||||
#include "gtkui_archive.h"
|
||||
|
||||
static bool windowopen, cancelled;
|
||||
|
||||
static GtkWidget *archivewindow;
|
||||
|
||||
bool gtkui_archive_select(const char *filename, char *reqfile, size_t reqsize) {
|
||||
// Select a filename to pull out of the archive
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
int r, numarchives = 0;
|
||||
|
||||
cancelled = false;
|
||||
|
||||
a = archive_read_new();
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
r = archive_read_open_filename(a, filename, 10240);
|
||||
|
||||
// Test if it's actually an archive
|
||||
if (r != ARCHIVE_OK) {
|
||||
r = archive_read_free(a);
|
||||
return false;
|
||||
}
|
||||
// If it is an archive, handle it
|
||||
else {
|
||||
// Set up the archive window
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
archivewindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(archivewindow), "Choose File from Archive");
|
||||
gtk_window_set_modal(GTK_WINDOW(archivewindow), TRUE);
|
||||
|
||||
GtkWidget *archivebox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add(GTK_CONTAINER(archivewindow), archivebox);
|
||||
gtk_widget_show(archivebox);
|
||||
|
||||
GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_box_pack_start(GTK_BOX(archivebox), scrolledwindow, TRUE, TRUE, 0);
|
||||
gtk_widget_set_size_request(scrolledwindow, 340, 340);
|
||||
gtk_widget_show(scrolledwindow);
|
||||
|
||||
GtkWidget *buttonbox = gtk_widget_new(GTK_TYPE_BOX, "halign", GTK_ALIGN_END, NULL);
|
||||
gtk_box_pack_start(GTK_BOX(archivebox), buttonbox, FALSE, TRUE, 0);
|
||||
gtk_widget_show(buttonbox);
|
||||
|
||||
GtkWidget *treeview = gtk_tree_view_new();
|
||||
gtk_container_add(GTK_CONTAINER(scrolledwindow), treeview);
|
||||
gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW (treeview), FALSE);
|
||||
gtk_widget_show(treeview);
|
||||
|
||||
GtkTreeStore *treestore = gtk_tree_store_new(1, G_TYPE_STRING);
|
||||
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore));
|
||||
|
||||
// Fill the treestore with the filenames
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||
const char *currentfile = archive_entry_pathname(entry);
|
||||
if (nst_archive_checkext(currentfile)) {
|
||||
gtk_tree_store_append(treestore, &iter, NULL);
|
||||
gtk_tree_store_set(treestore, &iter, 0, currentfile, -1);
|
||||
numarchives++;
|
||||
snprintf(reqfile, reqsize, "%s", currentfile);
|
||||
}
|
||||
archive_read_data_skip(a);
|
||||
}
|
||||
// Free the archive
|
||||
r = archive_read_free(a);
|
||||
|
||||
// If there are no valid files in the archive, return
|
||||
if (numarchives == 0) { return false; }
|
||||
// If there's only one file, don't bring up the selector
|
||||
else if (numarchives == 1) { return true; }
|
||||
|
||||
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
||||
|
||||
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
|
||||
"NES file",
|
||||
renderer,
|
||||
"text", 0,
|
||||
nullptr);
|
||||
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW (treeview), column);
|
||||
|
||||
GtkWidget *cancelbutton = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "Cancel",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(buttonbox), cancelbutton, FALSE, FALSE, 0);
|
||||
gtk_widget_show(cancelbutton);
|
||||
|
||||
GtkWidget *okbutton = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "OK",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(buttonbox), okbutton, FALSE, FALSE, 0);
|
||||
gtk_widget_show(okbutton);
|
||||
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
|
||||
g_signal_connect(G_OBJECT(okbutton), "clicked",
|
||||
G_CALLBACK(gtkui_archive_ok), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(cancelbutton), "clicked",
|
||||
G_CALLBACK(gtkui_archive_cancel), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(treeview), "row-activated",
|
||||
G_CALLBACK(gtkui_archive_ok), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(archivewindow), "destroy",
|
||||
G_CALLBACK(gtkui_archive_cancel), NULL);
|
||||
|
||||
gtk_widget_show(archivewindow);
|
||||
|
||||
// Freeze the rest of the program until a selection is made
|
||||
windowopen = true;
|
||||
while (windowopen) {
|
||||
gtk_main_iteration_do(TRUE);
|
||||
if (cancelled) { return false; }
|
||||
}
|
||||
|
||||
gchar *reqbuf;
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
gtk_tree_selection_get_selected(selection, &model, &iter);
|
||||
gtk_tree_model_get(model, &iter, 0, &reqbuf, -1);
|
||||
|
||||
gtk_widget_destroy(archivewindow);
|
||||
|
||||
snprintf(reqfile, reqsize, "%s", reqbuf);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void gtkui_archive_ok() {
|
||||
windowopen = false;
|
||||
}
|
||||
|
||||
void gtkui_archive_cancel() {
|
||||
cancelled = true;
|
||||
gtk_widget_destroy(archivewindow);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef _GTKUI_ARCHIVE_H_
|
||||
#define _GTKUI_ARCHIVE_H_
|
||||
|
||||
bool gtkui_archive_select(const char *filename, char *reqfile, size_t reqsize);
|
||||
void gtkui_archive_ok();
|
||||
void gtkui_archive_cancel();
|
||||
|
||||
#endif
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2017 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "config.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
|
||||
#include "gtkui.h"
|
||||
#include "gtkui_callbacks.h"
|
||||
|
||||
extern bool kbactivate, confrunning;
|
||||
extern int nst_quit;
|
||||
|
||||
//// Menu ////
|
||||
|
||||
void gtkui_cb_reset(GtkWidget *reset, int hard) {
|
||||
// Reset the NES from the GUI
|
||||
nst_reset(hard);
|
||||
}
|
||||
|
||||
void gtkui_cb_nothing() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void gtkui_cb_video_refresh() {
|
||||
// Refresh the Video output after changes
|
||||
if (nst_playing()) { video_init(); }
|
||||
gtkui_resize();
|
||||
}
|
||||
|
||||
// Video //
|
||||
|
||||
void gtkui_cb_video_filter(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Change the video filter
|
||||
conf.video_filter = gtk_combo_box_get_active(combobox);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_scale(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Change the scale factor
|
||||
conf.video_scale_factor = gtk_combo_box_get_active(combobox) + 1;
|
||||
|
||||
// The scalex filter only allows 3x scale and crashes otherwise
|
||||
if (conf.video_filter == 5 && conf.video_scale_factor == 4) {
|
||||
conf.video_scale_factor = 3;
|
||||
}
|
||||
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_ntscmode(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Change the NTSC Mode
|
||||
conf.video_ntsc_mode = gtk_combo_box_get_active(combobox);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_xbrrounding(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Set xBR corner rounding parameters
|
||||
conf.video_xbr_corner_rounding = gtk_combo_box_get_active(combobox);
|
||||
gtkui_cb_video_refresh();
|
||||
video_toggle_filterupdate();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_xbrpixblend(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Set xBR pixel blending parameters
|
||||
conf.video_xbr_pixel_blending = gtk_toggle_button_get_active(togglebutton);
|
||||
gtkui_cb_video_refresh();
|
||||
video_toggle_filterupdate();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_linear_filter(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Set linear filter
|
||||
conf.video_linear_filter = gtk_toggle_button_get_active(togglebutton);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_tv_aspect(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Set TV aspect ratio
|
||||
conf.video_tv_aspect = gtk_toggle_button_get_active(togglebutton);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_unmask_overscan(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Set overscan mask
|
||||
conf.video_unmask_overscan = gtk_toggle_button_get_active(togglebutton);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_stretch_aspect(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Set aspect ratio stretching/preservation
|
||||
conf.video_stretch_aspect = gtk_toggle_button_get_active(togglebutton);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_unlimited_sprites(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Set sprite limit
|
||||
conf.video_unlimited_sprites = gtk_toggle_button_get_active(togglebutton);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_palette(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Change the video palette
|
||||
conf.video_palette_mode = gtk_combo_box_get_active(combobox);
|
||||
gtkui_cb_video_refresh();
|
||||
// this doesn't work unless there's a restart - fix
|
||||
}
|
||||
|
||||
void gtkui_cb_video_decoder(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Change the YUV Decoder
|
||||
conf.video_decoder = gtk_combo_box_get_active(combobox);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_brightness(GtkRange *range, gpointer userdata) {
|
||||
// Change video brightness
|
||||
conf.video_brightness = (int)gtk_range_get_value(range);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_saturation(GtkRange *range, gpointer userdata) {
|
||||
// Change video saturation
|
||||
conf.video_saturation = (int)gtk_range_get_value(range);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_contrast(GtkRange *range, gpointer userdata) {
|
||||
// Change video contrast
|
||||
conf.video_contrast = (int)gtk_range_get_value(range);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
void gtkui_cb_video_hue(GtkRange *range, gpointer userdata) {
|
||||
// Change video hue
|
||||
conf.video_hue = (int)gtk_range_get_value(range);
|
||||
gtkui_cb_video_refresh();
|
||||
}
|
||||
|
||||
// Audio //
|
||||
|
||||
void gtkui_cb_audio_samplerate(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Change the Sample Rate
|
||||
switch (gtk_combo_box_get_active(combobox)) {
|
||||
case 0:
|
||||
conf.audio_sample_rate = 11025;
|
||||
break;
|
||||
case 1:
|
||||
conf.audio_sample_rate = 22050;
|
||||
break;
|
||||
case 2:
|
||||
conf.audio_sample_rate = 44100;
|
||||
break;
|
||||
case 3:
|
||||
conf.audio_sample_rate = 48000;
|
||||
break;
|
||||
case 4:
|
||||
conf.audio_sample_rate = 96000;
|
||||
break;
|
||||
default:
|
||||
conf.audio_sample_rate = 44100;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nst_playing()) {
|
||||
nst_pause();
|
||||
nst_play();
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_cb_audio_stereo(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Toggle Stereo
|
||||
conf.audio_stereo = gtk_toggle_button_get_active(togglebutton);
|
||||
|
||||
if (nst_playing()) {
|
||||
nst_pause();
|
||||
nst_play();
|
||||
}
|
||||
}
|
||||
|
||||
//// Input ////
|
||||
|
||||
void gtkui_cb_input_turbopulse(GtkRange *range, gpointer userdata) {
|
||||
// Change turbo pulse
|
||||
conf.timing_turbopulse = (int)gtk_range_get_value(range);
|
||||
}
|
||||
|
||||
//// Misc ////
|
||||
|
||||
void gtkui_cb_misc_default_system(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Select the default system
|
||||
conf.misc_default_system = gtk_combo_box_get_active(combobox);
|
||||
}
|
||||
|
||||
void gtkui_cb_misc_power_state(GtkComboBox *combobox, gpointer userdata) {
|
||||
// Select the default system
|
||||
conf.misc_power_state = gtk_combo_box_get_active(combobox);
|
||||
}
|
||||
|
||||
void gtkui_cb_timing_ffspeed(GtkRange *range, gpointer userdata) {
|
||||
// Set Fast-Forward Speed
|
||||
conf.timing_ffspeed = (int)gtk_range_get_value(range);
|
||||
}
|
||||
|
||||
void gtkui_cb_misc_soft_patching(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Enable or Disable automatic soft patching
|
||||
conf.misc_soft_patching = gtk_toggle_button_get_active(togglebutton);
|
||||
}
|
||||
|
||||
void gtkui_cb_misc_genie_distortion(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Enable or Disable Game Genie Sound Distortion
|
||||
conf.misc_genie_distortion = gtk_toggle_button_get_active(togglebutton);
|
||||
}
|
||||
|
||||
void gtkui_cb_misc_disable_cursor(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Enable or Disable the Cursor
|
||||
conf.misc_disable_cursor = gtk_toggle_button_get_active(togglebutton);
|
||||
if (!nst_quit) { gtkui_play(); }
|
||||
}
|
||||
|
||||
void gtkui_cb_misc_disable_cursor_special(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Enable or Disable Special Cursors
|
||||
conf.misc_disable_cursor_special = gtk_toggle_button_get_active(togglebutton);
|
||||
if (!nst_quit) { gtkui_play(); }
|
||||
}
|
||||
|
||||
void gtkui_cb_misc_config_pause(GtkToggleButton *togglebutton, gpointer userdata) {
|
||||
// Pause GUI when configuration window is open
|
||||
conf.misc_config_pause = gtk_toggle_button_get_active(togglebutton);
|
||||
}
|
||||
|
||||
void gtkui_drag_data(GtkWidget *widget, GdkDragContext *dragcontext, gint x, gint y, GtkSelectionData *seldata, guint info, guint time, gpointer data) {
|
||||
// Handle the Drag and Drop
|
||||
if ((widget == NULL) || (dragcontext == NULL) || (seldata == NULL)) { return; }
|
||||
|
||||
if (info == 0) {
|
||||
gchar *fileuri = (gchar*)gtk_selection_data_get_data(seldata);
|
||||
gchar *filename = g_filename_from_uri(fileuri, NULL, NULL);
|
||||
|
||||
// Dirty hack. g_filename_from_uri adds a \r\n to the string
|
||||
size_t ln = strlen(filename) - 2;
|
||||
if (filename[ln] == '\r') { filename[ln] = '\0'; }
|
||||
|
||||
nst_load(filename);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef _GTKUI_CALLBACKS_H_
|
||||
#define _GTKUI_CALLBACKS_H_
|
||||
|
||||
void gtkui_cb_reset(GtkWidget *reset, int hard);
|
||||
void gtkui_cb_nothing();
|
||||
void gtkui_cb_video_refresh();
|
||||
|
||||
void gtkui_cb_video_filter(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_video_scale(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_video_ntscmode(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_video_xbrrounding(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_video_xbrpixblend(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_video_linear_filter(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_video_tv_aspect(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_video_unmask_overscan(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_video_stretch_aspect(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_video_unlimited_sprites(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_video_palette(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_video_decoder(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_video_brightness(GtkRange *range, gpointer userdata);
|
||||
void gtkui_cb_video_saturation(GtkRange *range, gpointer userdata);
|
||||
void gtkui_cb_video_contrast(GtkRange *range, gpointer userdata);
|
||||
void gtkui_cb_video_hue(GtkRange *range, gpointer userdata);
|
||||
|
||||
void gtkui_cb_audio_samplerate(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_audio_stereo(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
|
||||
void gtkui_cb_input_turbopulse(GtkRange *range, gpointer userdata);
|
||||
|
||||
void gtkui_cb_misc_default_system(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_misc_power_state(GtkComboBox *combobox, gpointer userdata);
|
||||
void gtkui_cb_timing_ffspeed(GtkRange *range, gpointer userdata);
|
||||
void gtkui_cb_misc_soft_patching(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_misc_genie_distortion(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_misc_disable_cursor(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_misc_disable_cursor_special(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
void gtkui_cb_misc_config_pause(GtkToggleButton *togglebutton, gpointer userdata);
|
||||
|
||||
void gtkui_drag_data(GtkWidget *widget, GdkDragContext *dragcontext, gint x, gint y, GtkSelectionData *seldata, guint info, guint time, gpointer data);
|
||||
|
||||
#endif
|
|
@ -1,619 +0,0 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2016 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "config.h"
|
||||
#include "cheats.h"
|
||||
|
||||
#include "gtkui.h"
|
||||
#include "gtkui_callbacks.h"
|
||||
#include "gtkui_cheats.h"
|
||||
#include "gtkui_dialogs.h"
|
||||
|
||||
extern nstpaths_t nstpaths;
|
||||
extern Emulator emulator;
|
||||
|
||||
GtkWidget *cheatwindow;
|
||||
GtkTreeStore *treestore;
|
||||
GtkWidget *treeview;
|
||||
GtkWidget *descedit, *ggedit, *paredit;
|
||||
GtkWidget *infobar, *infolabel;
|
||||
|
||||
Xml savexml;
|
||||
Xml::Node saveroot;
|
||||
|
||||
GtkWidget *gtkui_cheats() {
|
||||
// Create the Cheats window
|
||||
|
||||
if (cheatwindow) { return NULL; }
|
||||
|
||||
cheatwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW (cheatwindow), "Cheat Manager");
|
||||
|
||||
GtkWidget *cheatbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add(GTK_CONTAINER(cheatwindow), cheatbox);
|
||||
|
||||
GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_box_pack_start(GTK_BOX(cheatbox), scrolledwindow, TRUE, TRUE, 0);
|
||||
gtk_widget_set_size_request(scrolledwindow, 512, 256);
|
||||
|
||||
treeview = gtk_tree_view_new();
|
||||
gtk_container_add(GTK_CONTAINER (scrolledwindow), treeview);
|
||||
|
||||
infobar = gtk_info_bar_new();
|
||||
infolabel = gtk_widget_new(GTK_TYPE_LABEL,"label", "", NULL);
|
||||
gtk_box_pack_start(GTK_BOX(cheatbox), infobar, TRUE, TRUE, 0);
|
||||
|
||||
GtkWidget *content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(infobar));
|
||||
gtk_box_pack_start(GTK_BOX(content_area), infolabel, TRUE, TRUE, 0);
|
||||
|
||||
GtkWidget *opensavebox = gtk_widget_new(GTK_TYPE_BOX, "halign", GTK_ALIGN_END, NULL);
|
||||
gtk_box_pack_start(GTK_BOX(cheatbox), opensavebox, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *cheatopen = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "Open",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(opensavebox), cheatopen, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *cheatclear = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "Clear",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(opensavebox), cheatclear, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *cheatremove = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "Remove",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(opensavebox), cheatremove, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *descbox = gtk_widget_new(
|
||||
GTK_TYPE_BOX,
|
||||
"halign", GTK_ALIGN_END,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(cheatbox), descbox, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *desclabel = gtk_widget_new(
|
||||
GTK_TYPE_LABEL,
|
||||
"label", "Description:",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-left", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(descbox), desclabel, FALSE, FALSE, 0);
|
||||
|
||||
descedit = gtk_widget_new(
|
||||
GTK_TYPE_ENTRY,
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(descbox), descedit, TRUE, TRUE, 0);
|
||||
|
||||
GtkWidget *ggbox = gtk_widget_new(
|
||||
GTK_TYPE_BOX,
|
||||
"halign", GTK_ALIGN_END,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(cheatbox), ggbox, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *gglabel = gtk_widget_new(
|
||||
GTK_TYPE_LABEL,
|
||||
"label", "Game Genie:",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-left", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(ggbox), gglabel, FALSE, FALSE, 0);
|
||||
|
||||
ggedit = gtk_widget_new(
|
||||
GTK_TYPE_ENTRY,
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(ggbox), ggedit, TRUE, TRUE, 0);
|
||||
|
||||
GtkWidget *genieadd = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "Add",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(ggbox), genieadd, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *parbox = gtk_widget_new(
|
||||
GTK_TYPE_BOX,
|
||||
"halign", GTK_ALIGN_END,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(cheatbox), parbox, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *parlabel = gtk_widget_new(
|
||||
GTK_TYPE_LABEL,
|
||||
"label", "Pro Action Rocky:",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-left", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(parbox), parlabel, FALSE, FALSE, 0);
|
||||
|
||||
paredit = gtk_widget_new(
|
||||
GTK_TYPE_ENTRY,
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(parbox), paredit, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *paradd = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "Add",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(parbox), paradd, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *cheatok = gtk_widget_new(
|
||||
GTK_TYPE_BUTTON,
|
||||
"label", "OK",
|
||||
"halign", GTK_ALIGN_END,
|
||||
"margin-top", 8,
|
||||
"margin-bottom", 8,
|
||||
"margin-right", 8,
|
||||
NULL);
|
||||
gtk_box_pack_start(GTK_BOX(cheatbox), cheatok, FALSE, FALSE, 0);
|
||||
|
||||
gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), FALSE);
|
||||
|
||||
treestore = gtk_tree_store_new(5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore));
|
||||
|
||||
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
||||
GtkCellRenderer *checkbox = gtk_cell_renderer_toggle_new();
|
||||
|
||||
GtkTreeViewColumn *column[5];
|
||||
// create the display columns
|
||||
column[0] = gtk_tree_view_column_new_with_attributes("Enable", checkbox, "active", 0, nullptr);
|
||||
column[1] = gtk_tree_view_column_new_with_attributes("Game Genie", renderer, "text", 1, nullptr);
|
||||
column[2] = gtk_tree_view_column_new_with_attributes("PAR", renderer, "text", 2, nullptr);
|
||||
column[3] = gtk_tree_view_column_new_with_attributes("Raw", renderer, "text", 3, nullptr);
|
||||
column[4] = gtk_tree_view_column_new_with_attributes("Description", renderer, "text", 4, nullptr);
|
||||
|
||||
// add the display column and renderer to the tree view
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[0]);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[1]);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[2]);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[3]);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[4]);
|
||||
|
||||
gtkui_cheats_fill_tree(nstpaths.cheatpath);
|
||||
|
||||
/*g_signal_connect(G_OBJECT(checkbox), "toggled",
|
||||
G_CALLBACK(gtkui_cheats_check), NULL);*/
|
||||
|
||||
g_signal_connect(G_OBJECT(treeview), "row-activated",
|
||||
G_CALLBACK(gtkui_cheats_toggle), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(cheatopen), "clicked",
|
||||
G_CALLBACK(gtkui_cheats_load), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(cheatclear), "clicked",
|
||||
G_CALLBACK(gtkui_cheats_clear), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(cheatremove), "clicked",
|
||||
G_CALLBACK(gtkui_cheats_remove), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(genieadd), "clicked",
|
||||
G_CALLBACK(gtkui_cheats_gg_add), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(paradd), "clicked",
|
||||
G_CALLBACK(gtkui_cheats_par_add), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(cheatok), "clicked",
|
||||
G_CALLBACK(gtkui_cheats_ok), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(cheatwindow), "destroy",
|
||||
G_CALLBACK(gtkui_cheats_ok), NULL);
|
||||
|
||||
gtk_widget_show_all(cheatwindow);
|
||||
gtk_widget_hide(infobar);
|
||||
|
||||
return cheatwindow;
|
||||
}
|
||||
|
||||
void gtkui_cheats_check(GtkWidget *widget, gchar *element, gpointer userdata) {
|
||||
// This function doesn't work. Fix later.
|
||||
GtkTreeIter iter;
|
||||
|
||||
bool value;
|
||||
|
||||
// Read the value of the checkbox
|
||||
value = gtk_cell_renderer_toggle_get_active((GtkCellRendererToggle*)widget);
|
||||
|
||||
// Flip the value and set it
|
||||
value ^= 1;
|
||||
gtk_cell_renderer_toggle_set_active((GtkCellRendererToggle*)widget, value);
|
||||
}
|
||||
|
||||
void gtkui_cheats_toggle(GtkWidget *widget, gpointer userdata) {
|
||||
// Toggle a cheat on or off
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
bool value;
|
||||
|
||||
// Get the selected item
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
|
||||
gtk_tree_selection_get_selected(selection, &model, &iter);
|
||||
|
||||
// Read the value of the checkbox
|
||||
gtk_tree_model_get(model, &iter, 0, &value, -1);
|
||||
|
||||
// Flip the value and set it
|
||||
value ^= 1;
|
||||
gtk_tree_store_set(treestore, &iter, 0, value, -1);
|
||||
|
||||
//Re-initialize the cheats
|
||||
Cheats cheats(emulator);
|
||||
cheats.ClearCodes();
|
||||
|
||||
gtk_tree_model_foreach(GTK_TREE_MODEL(model), gtkui_cheats_scan_list, NULL);
|
||||
}
|
||||
|
||||
void gtkui_cheats_fill_tree(char *filename) {
|
||||
// Fill the cheat list
|
||||
Xml xml;
|
||||
|
||||
GtkTreeIter iter;
|
||||
|
||||
bool enabled = false;
|
||||
|
||||
char codebuf[9];
|
||||
char descbuf[512];
|
||||
|
||||
gtkui_cheats_clear();
|
||||
|
||||
std::ifstream cheatfile(filename, std::ifstream::in|std::ifstream::binary);
|
||||
|
||||
if (cheatfile.is_open()) {
|
||||
xml.Read(cheatfile);
|
||||
|
||||
if (xml.GetRoot().IsType(L"cheats")) {
|
||||
|
||||
Xml::Node root(xml.GetRoot());
|
||||
Xml::Node node(root.GetFirstChild());
|
||||
|
||||
for (int i = 0; i < root.NumChildren(L"cheat"); i++) {
|
||||
|
||||
wcstombs(descbuf, node.GetChild(L"description").GetValue(), sizeof(descbuf));
|
||||
|
||||
// Check if the cheat is enabled
|
||||
node.GetAttribute(L"enabled").IsValue(L"1") ? enabled = true : enabled = false;
|
||||
|
||||
// Add the cheats to the list
|
||||
if (node.GetChild(L"genie")) { // Game Genie
|
||||
wcstombs(codebuf, node.GetChild(L"genie").GetValue(), sizeof(codebuf));
|
||||
gtk_tree_store_append(treestore, &iter, NULL);
|
||||
gtk_tree_store_set(treestore, &iter,
|
||||
0, enabled,
|
||||
1, codebuf,
|
||||
4, descbuf,
|
||||
-1);
|
||||
if (enabled) { nst_cheats_code_gg_add(node.GetChild(L"genie").GetValue()); }
|
||||
}
|
||||
|
||||
else if (node.GetChild(L"rocky")) { // Pro Action Rocky
|
||||
wcstombs(codebuf, node.GetChild(L"rocky").GetValue(), sizeof(codebuf));
|
||||
gtk_tree_store_append(treestore, &iter, NULL);
|
||||
gtk_tree_store_set(treestore, &iter,
|
||||
0, enabled,
|
||||
2, codebuf,
|
||||
4, descbuf,
|
||||
-1);
|
||||
if (enabled) { nst_cheats_code_par_add(node.GetChild(L"rocky").GetValue()); }
|
||||
}
|
||||
|
||||
else if (node.GetChild(L"address")) { // Raw
|
||||
char rawbuf[11];
|
||||
snprintf(rawbuf, sizeof(rawbuf),
|
||||
"%04lu %02lu %02lu",
|
||||
node.GetChild(L"address").GetUnsignedValue(),
|
||||
node.GetChild(L"value").GetUnsignedValue(),
|
||||
node.GetChild(L"compare").GetUnsignedValue());
|
||||
|
||||
gtk_tree_store_append(treestore, &iter, NULL);
|
||||
gtk_tree_store_set(treestore, &iter,
|
||||
0, enabled,
|
||||
3, rawbuf,
|
||||
4, descbuf,
|
||||
-1);
|
||||
if (enabled) { nst_cheats_code_raw_add(node); }
|
||||
}
|
||||
|
||||
node = node.GetNextSibling();
|
||||
}
|
||||
}
|
||||
cheatfile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_cheats_save() {
|
||||
// Save the cheat list
|
||||
std::ofstream cheatfile(nstpaths.cheatpath, std::ifstream::out|std::ifstream::binary);
|
||||
|
||||
if (cheatfile.is_open()) {
|
||||
|
||||
GtkTreeModel *model;
|
||||
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
|
||||
|
||||
saveroot = (savexml.GetRoot());
|
||||
|
||||
saveroot = savexml.Create( L"cheats" );
|
||||
saveroot.AddAttribute( L"version", L"1.0" );
|
||||
|
||||
gtk_tree_model_foreach(GTK_TREE_MODEL(model), gtkui_cheats_write_list, NULL);
|
||||
|
||||
savexml.Write(saveroot, cheatfile);
|
||||
cheatfile.close();
|
||||
}
|
||||
else { return; }
|
||||
}
|
||||
|
||||
void gtkui_cheats_gg_add(GtkWidget *widget, gpointer userdata) {
|
||||
// Add a Game Genie code to the list
|
||||
GtkTreeIter iter;
|
||||
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
char codebuf[9];
|
||||
char descbuf[512];
|
||||
|
||||
snprintf(codebuf, sizeof(codebuf), "%.8s", gtk_entry_get_text(GTK_ENTRY(ggedit)));
|
||||
snprintf(descbuf, sizeof(descbuf), "%s", gtk_entry_get_text(GTK_ENTRY(descedit)));
|
||||
|
||||
if (cheats.GameGenieDecode(codebuf, code) == Nes::RESULT_OK) {
|
||||
gtk_tree_store_append(treestore, &iter, NULL);
|
||||
gtk_tree_store_set(treestore, &iter,
|
||||
0, true,
|
||||
1, codebuf,
|
||||
4, descbuf,
|
||||
-1);
|
||||
gtk_entry_set_text(GTK_ENTRY(descedit), "");
|
||||
gtk_entry_set_text(GTK_ENTRY(ggedit), "");
|
||||
gtk_entry_set_text(GTK_ENTRY(paredit), "");
|
||||
gtk_widget_hide(infobar);
|
||||
gtk_label_set_text(GTK_LABEL(infolabel), "");
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
else {
|
||||
gtk_info_bar_set_message_type(GTK_INFO_BAR(infobar), GTK_MESSAGE_ERROR);
|
||||
gtk_label_set_text(GTK_LABEL(infolabel), "Error: Invalid Game Genie code");
|
||||
gtk_widget_show(infobar);
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_cheats_par_add(GtkWidget *widget, gpointer userdata) {
|
||||
// Add a Pro Action Rocky code to the list
|
||||
GtkTreeIter iter;
|
||||
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
char codebuf[9];
|
||||
char descbuf[512];
|
||||
|
||||
snprintf(codebuf, sizeof(codebuf), "%.8s", gtk_entry_get_text(GTK_ENTRY(paredit)));
|
||||
snprintf(descbuf, sizeof(descbuf), "%s", gtk_entry_get_text(GTK_ENTRY(descedit)));
|
||||
|
||||
if (cheats.ProActionRockyDecode(codebuf, code) == Nes::RESULT_OK) {
|
||||
gtk_tree_store_append(treestore, &iter, NULL);
|
||||
gtk_tree_store_set(treestore, &iter,
|
||||
0, true,
|
||||
1, codebuf,
|
||||
4, descbuf,
|
||||
-1);
|
||||
gtk_entry_set_text(GTK_ENTRY(descedit), "");
|
||||
gtk_entry_set_text(GTK_ENTRY(ggedit), "");
|
||||
gtk_entry_set_text(GTK_ENTRY(paredit), "");
|
||||
gtk_widget_hide(infobar);
|
||||
gtk_label_set_text(GTK_LABEL(infolabel), "");
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
else {
|
||||
gtk_info_bar_set_message_type(GTK_INFO_BAR(infobar), GTK_MESSAGE_ERROR);
|
||||
gtk_label_set_text(GTK_LABEL(infolabel), "Error: Invalid PAR code");
|
||||
gtk_widget_show(infobar);
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_cheats_remove(GtkWidget *widget, gpointer userdata) {
|
||||
// Remove a cheat from the list
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
// Get the selected item
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
gtk_tree_selection_get_selected(selection, &model, &iter);
|
||||
|
||||
// Remove the cheat
|
||||
if (gtk_tree_store_iter_is_valid(treestore, &iter)) {
|
||||
gtk_tree_store_remove(treestore, &iter);
|
||||
}
|
||||
|
||||
//Re-initialize the cheats
|
||||
Cheats cheats(emulator);
|
||||
cheats.ClearCodes();
|
||||
|
||||
gtk_tree_model_foreach(GTK_TREE_MODEL(model), gtkui_cheats_scan_list, NULL);
|
||||
}
|
||||
|
||||
void gtkui_cheats_ok() {
|
||||
// Save the cheats and close the window
|
||||
gtkui_cheats_save();
|
||||
gtk_widget_destroy(cheatwindow);
|
||||
cheatwindow = NULL;
|
||||
}
|
||||
|
||||
void gtkui_cheats_clear() {
|
||||
// Clear the list
|
||||
gtk_tree_store_clear(treestore);
|
||||
Cheats cheats(emulator);
|
||||
cheats.ClearCodes();
|
||||
}
|
||||
|
||||
gboolean gtkui_cheats_scan_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata) {
|
||||
// Scan through the list of cheats
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
bool enabled;
|
||||
gchar *ggcode, *parcode, *rawcode, *description;
|
||||
|
||||
gtk_tree_model_get(model, iter, 0, &enabled, 1, &ggcode, 2, &parcode, 3, &rawcode, 4, &description, -1);
|
||||
|
||||
if (enabled) {
|
||||
if (ggcode) {
|
||||
cheats.GameGenieDecode(ggcode, code);
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
else if (parcode) {
|
||||
cheats.ProActionRockyDecode(parcode, code);
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
else if (rawcode) {
|
||||
code.useCompare = false;
|
||||
|
||||
int addr, value, compare;
|
||||
char buf[5];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%c%c%c%c", rawcode[0], rawcode[1], rawcode[2], rawcode[3]);
|
||||
sscanf(buf, "%x", &addr);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%c%c", rawcode[5], rawcode[6]);
|
||||
sscanf(buf, "%x", &value);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%c%c", rawcode[8], rawcode[9]);
|
||||
sscanf(buf, "%x", &compare);
|
||||
|
||||
code.address = addr;
|
||||
code.value = value;
|
||||
code.compare = compare;
|
||||
|
||||
if (compare) { code.useCompare = true; }
|
||||
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(ggcode);
|
||||
g_free(parcode);
|
||||
g_free(rawcode);
|
||||
g_free(description);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
gboolean gtkui_cheats_write_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata) {
|
||||
// Write entries to the cheat file
|
||||
bool enabled;
|
||||
gchar *ggcode, *parcode, *rawcode, *description;
|
||||
|
||||
char buf[9];
|
||||
wchar_t wbuf[9];
|
||||
|
||||
gtk_tree_model_get(model, iter, 0, &enabled, 1, &ggcode, 2, &parcode, 3, &rawcode, 4, &description, -1);
|
||||
|
||||
Xml::Node node(saveroot.AddChild(L"cheat"));
|
||||
node.AddAttribute(L"enabled", enabled ? L"1" : L"0");
|
||||
|
||||
if (ggcode) {
|
||||
snprintf(buf, sizeof(buf), "%s", ggcode);
|
||||
mbstowcs(wbuf, buf, 9);
|
||||
node.AddChild(L"genie", wbuf);
|
||||
}
|
||||
if (parcode) {
|
||||
snprintf(buf, sizeof(buf), "%s", parcode);
|
||||
mbstowcs(wbuf, buf, 9);
|
||||
node.AddChild(L"rocky", wbuf);
|
||||
}
|
||||
if (rawcode) {
|
||||
snprintf(buf, sizeof(buf), "0x%c%c%c%c", rawcode[0], rawcode[1], rawcode[2], rawcode[3]);
|
||||
mbstowcs(wbuf, buf, 9);
|
||||
node.AddChild(L"address", wbuf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "0x%c%c", rawcode[5], rawcode[6]);
|
||||
mbstowcs(wbuf, buf, 9);
|
||||
node.AddChild(L"value", wbuf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "0x%c%c", rawcode[8], rawcode[9]);
|
||||
mbstowcs(wbuf, buf, 9);
|
||||
node.AddChild(L"compare", wbuf);
|
||||
}
|
||||
if (description) {
|
||||
char descbuf[512];
|
||||
wchar_t wdescbuf[512];
|
||||
|
||||
snprintf(descbuf, sizeof(descbuf), "%s", description);
|
||||
mbstowcs(wdescbuf, descbuf, 512);
|
||||
node.AddChild(L"description", wdescbuf);
|
||||
}
|
||||
|
||||
g_free(ggcode);
|
||||
g_free(parcode);
|
||||
g_free(rawcode);
|
||||
g_free(description);
|
||||
|
||||
return false;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef _GTKUI_CHEATS_H_
|
||||
#define _GTKUI_CHEATS_H_
|
||||
|
||||
GtkWidget *gtkui_cheats();
|
||||
void gtkui_cheats_check(GtkWidget *widget, gchar *element, gpointer userdata);
|
||||
void gtkui_cheats_toggle(GtkWidget *widget, gpointer userdata);
|
||||
void gtkui_cheats_fill_tree(char *filename);
|
||||
void gtkui_cheats_save();
|
||||
void gtkui_cheats_gg_add(GtkWidget *widget, gpointer userdata);
|
||||
void gtkui_cheats_par_add(GtkWidget *widget, gpointer userdata);
|
||||
void gtkui_cheats_remove(GtkWidget *widget, gpointer userdata);
|
||||
void gtkui_cheats_ok();
|
||||
void gtkui_cheats_clear();
|
||||
gboolean gtkui_cheats_scan_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata);
|
||||
gboolean gtkui_cheats_write_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,18 +0,0 @@
|
|||
#ifndef _GTKUI_CONFIG_H_
|
||||
#define _GTKUI_CONFIG_H_
|
||||
|
||||
#define MARGIN_TB 5
|
||||
#define MARGIN_LR 10
|
||||
|
||||
#define NUMCHANNELS 12
|
||||
|
||||
GtkWidget *gtkui_config();
|
||||
void gtkui_config_ok();
|
||||
void gtkui_audio_volume();
|
||||
void gtkui_audio_volume_master();
|
||||
void gtkui_config_input_activate(GtkWidget *widget, GtkTreePath *path, gpointer userdata);
|
||||
void gtkui_config_input_refresh();
|
||||
void gtkui_config_input_fields(int type, int pnum);
|
||||
void gtkui_config_input_defaults();
|
||||
|
||||
#endif
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2016 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "video.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkui.h"
|
||||
#include "gtkui_cheats.h"
|
||||
|
||||
extern nstpaths_t nstpaths;
|
||||
extern GtkWidget *gtkwindow;
|
||||
|
||||
void gtkui_file_open() {
|
||||
// Open a file using a GTK dialog
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||
"Select a ROM",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Open", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
if(conf.misc_last_folder != NULL)
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), conf.misc_last_folder);
|
||||
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
|
||||
gtk_file_filter_set_name(filter, "NES ROMs and Archives");
|
||||
gtk_file_filter_add_pattern(filter, "*.nes");
|
||||
gtk_file_filter_add_pattern(filter, "*.fds");
|
||||
gtk_file_filter_add_pattern(filter, "*.unf");
|
||||
gtk_file_filter_add_pattern(filter, "*.unif");
|
||||
gtk_file_filter_add_pattern(filter, "*.nsf");
|
||||
gtk_file_filter_add_pattern(filter, "*.zip");
|
||||
gtk_file_filter_add_pattern(filter, "*.7z");
|
||||
gtk_file_filter_add_pattern(filter, "*.txz");
|
||||
gtk_file_filter_add_pattern(filter, "*.tar.xz");
|
||||
gtk_file_filter_add_pattern(filter, "*.xz");
|
||||
gtk_file_filter_add_pattern(filter, "*.tgz");
|
||||
gtk_file_filter_add_pattern(filter, "*.tar.gz");
|
||||
gtk_file_filter_add_pattern(filter, "*.gz");
|
||||
gtk_file_filter_add_pattern(filter, "*.tbz");
|
||||
gtk_file_filter_add_pattern(filter, "*.tar.bz2");
|
||||
gtk_file_filter_add_pattern(filter, "*.bz2");
|
||||
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename;
|
||||
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
|
||||
if(conf.misc_last_folder != NULL)
|
||||
free(conf.misc_last_folder);
|
||||
|
||||
conf.misc_last_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
nst_load(filename);
|
||||
gtkui_set_title(nstpaths.gamename);
|
||||
gtkui_play();
|
||||
g_free(filename);
|
||||
}
|
||||
else { gtk_widget_destroy(dialog); }
|
||||
}
|
||||
|
||||
void gtkui_state_save() {
|
||||
// Save a state from the GUI
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save State (.nst)",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Save", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
char statepath[512];
|
||||
snprintf(statepath, sizeof(statepath), "%s.nst", nstpaths.statepath);
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), statepath);
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.statepath);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
nst_state_save(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
void gtkui_state_load() {
|
||||
// Load a state from the GUI
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load State (.nst)",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Open", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, "Nestopia Save States");
|
||||
gtk_file_filter_add_pattern(filter, "*.nst");
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.statepath);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
nst_state_load(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
void gtkui_screenshot_save() {
|
||||
// Save a screenshot from the GUI
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save screenshot (.png)",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Save", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
char sshotpath[512];
|
||||
char sshotfile[768];
|
||||
snprintf(sshotpath, sizeof(sshotpath), "%sscreenshots/", nstpaths.nstdir);
|
||||
snprintf(sshotfile, sizeof(sshotfile), "%s%s.png", sshotpath, nstpaths.gamename);
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), sshotfile);
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), sshotpath);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
video_screenshot(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
void gtkui_movie_save() {
|
||||
// Save a movie from the GUI
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save movie (.nsv)",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Save", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
char moviepath[512];
|
||||
snprintf(moviepath, sizeof(moviepath), "%s%s.nsv", nstpaths.nstdir, nstpaths.gamename);
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), moviepath);
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.nstdir);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
nst_movie_save(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
void gtkui_movie_load() {
|
||||
// Load a movie from the GUI
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load movie (.nsv)",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Open", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, "Nestopia movies");
|
||||
gtk_file_filter_add_pattern(filter, "*.nsv");
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.nstdir);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
nst_movie_load(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
void gtkui_movie_stop() {
|
||||
nst_movie_stop();
|
||||
}
|
||||
|
||||
void gtkui_cheats_load() {
|
||||
// Load cheats from the GUI
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load cheats (.xml)",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Open", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, "Nestopia cheats");
|
||||
gtk_file_filter_add_pattern(filter, "*.xml");
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.nstdir);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
gtkui_cheats_fill_tree(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
void gtkui_palette_load() {
|
||||
// Load a palette from the GUI
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Load palette (.pal)",
|
||||
GTK_WINDOW(gtkwindow),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Open", GTK_RESPONSE_ACCEPT,
|
||||
nullptr);
|
||||
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, "NES Palettes");
|
||||
gtk_file_filter_add_pattern(filter, "*.pal");
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
nst_palette_load(filename);
|
||||
nst_palette_save();
|
||||
g_free(filename);
|
||||
conf.video_palette_mode = 2;
|
||||
video_init();
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef _GTKUI_DIALOGS_H_
|
||||
#define _GTKUI_DIALOGS_H_
|
||||
|
||||
void gtkui_file_open();
|
||||
void gtkui_state_save();
|
||||
void gtkui_state_load();
|
||||
|
||||
void gtkui_screenshot_save();
|
||||
|
||||
void gtkui_movie_save();
|
||||
void gtkui_movie_load();
|
||||
void gtkui_movie_stop();
|
||||
|
||||
void gtkui_cheats_load();
|
||||
|
||||
void gtkui_palette_load();
|
||||
|
||||
#endif
|
|
@ -1,388 +0,0 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2017 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nstcommon.h"
|
||||
#include "input.h"
|
||||
#include "video.h"
|
||||
#include "audio.h"
|
||||
#include "ini.h"
|
||||
|
||||
#include "sdlinput.h"
|
||||
|
||||
#include "gtkui.h"
|
||||
#include "gtkui_input.h"
|
||||
|
||||
static ginputsettings_t inputconf;
|
||||
static gkeys_t ui;
|
||||
gpad_t pad[NUMGAMEPADS];
|
||||
|
||||
static char inputconfpath[256];
|
||||
static bool confrunning = false;
|
||||
static guint keyval = 0;
|
||||
|
||||
extern GtkWidget *configwindow;
|
||||
extern nstpaths_t nstpaths;
|
||||
extern Input::Controllers *cNstPads;
|
||||
|
||||
static int gtkui_input_config_match(void* user, const char* section, const char* name, const char* value) {
|
||||
// Match values from input config file and populate live config
|
||||
ginputsettings_t* pconfig = (ginputsettings_t*)user;
|
||||
|
||||
// User Interface
|
||||
if (MATCH("ui", "qsave1")) { pconfig->qsave1 = strdup(value); }
|
||||
else if (MATCH("ui", "qsave2")) { pconfig->qsave2 = strdup(value); }
|
||||
else if (MATCH("ui", "qload1")) { pconfig->qload1 = strdup(value); }
|
||||
else if (MATCH("ui", "qload2")) { pconfig->qload2 = strdup(value); }
|
||||
else if (MATCH("ui", "screenshot")) { pconfig->screenshot = strdup(value); }
|
||||
else if (MATCH("ui", "fdsflip")) { pconfig->fdsflip = strdup(value); }
|
||||
else if (MATCH("ui", "fdsswitch")) { pconfig->fdsswitch = strdup(value); }
|
||||
else if (MATCH("ui", "insertcoin1")) { pconfig->insertcoin1 = strdup(value); }
|
||||
else if (MATCH("ui", "insertcoin2")) { pconfig->insertcoin2 = strdup(value); }
|
||||
else if (MATCH("ui", "reset")) { pconfig->reset = strdup(value); }
|
||||
else if (MATCH("ui", "ffspeed")) { pconfig->ffspeed = strdup(value); }
|
||||
else if (MATCH("ui", "rwstart")) { pconfig->rwstart = strdup(value); }
|
||||
else if (MATCH("ui", "rwstop")) { pconfig->rwstop = strdup(value); }
|
||||
else if (MATCH("ui", "fullscreen")) { pconfig->fullscreen = strdup(value); }
|
||||
else if (MATCH("ui", "filter")) { pconfig->filter = strdup(value); }
|
||||
else if (MATCH("ui", "scalefactor")) { pconfig->scalefactor = strdup(value); }
|
||||
|
||||
// Player 1
|
||||
else if (MATCH("gamepad1", "kb_u")) { pconfig->kb_p1u = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_d")) { pconfig->kb_p1d = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_l")) { pconfig->kb_p1l = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_r")) { pconfig->kb_p1r = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_select")) { pconfig->kb_p1select = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_start")) { pconfig->kb_p1start = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_a")) { pconfig->kb_p1a = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_b")) { pconfig->kb_p1b = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_ta")) { pconfig->kb_p1ta = strdup(value); }
|
||||
else if (MATCH("gamepad1", "kb_tb")) { pconfig->kb_p1tb = strdup(value); }
|
||||
|
||||
// Player 2
|
||||
else if (MATCH("gamepad2", "kb_u")) { pconfig->kb_p2u = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_d")) { pconfig->kb_p2d = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_l")) { pconfig->kb_p2l = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_r")) { pconfig->kb_p2r = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_select")) { pconfig->kb_p2select = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_start")) { pconfig->kb_p2start = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_a")) { pconfig->kb_p2a = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_b")) { pconfig->kb_p2b = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_ta")) { pconfig->kb_p2ta = strdup(value); }
|
||||
else if (MATCH("gamepad2", "kb_tb")) { pconfig->kb_p2tb = strdup(value); }
|
||||
|
||||
else { return 0; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
void gtkui_input_set_default() {
|
||||
// Set the default input for GTK
|
||||
|
||||
// Gamepads
|
||||
pad[0].u = GDK_KEY_Up;
|
||||
pad[0].d = GDK_KEY_Down;
|
||||
pad[0].l = GDK_KEY_Left;
|
||||
pad[0].r = GDK_KEY_Right;
|
||||
pad[0].select = GDK_KEY_Shift_R;
|
||||
pad[0].start = GDK_KEY_Return;
|
||||
pad[0].a = GDK_KEY_z;
|
||||
pad[0].b = GDK_KEY_a;
|
||||
pad[0].ta = GDK_KEY_x;
|
||||
pad[0].tb = GDK_KEY_s;
|
||||
|
||||
pad[1].u = GDK_KEY_i;
|
||||
pad[1].d = GDK_KEY_k;
|
||||
pad[1].l = GDK_KEY_j;
|
||||
pad[1].r = GDK_KEY_l;
|
||||
pad[1].select = GDK_KEY_Shift_L;
|
||||
pad[1].start = GDK_KEY_Control_L;
|
||||
pad[1].a = GDK_KEY_m;
|
||||
pad[1].b = GDK_KEY_n;
|
||||
pad[1].ta = GDK_KEY_b;
|
||||
pad[1].tb = GDK_KEY_v;
|
||||
|
||||
// User Interface
|
||||
ui.qsave1 = GDK_KEY_F5;
|
||||
ui.qsave2 = GDK_KEY_F6;
|
||||
ui.qload1 = GDK_KEY_F7;
|
||||
ui.qload2 = GDK_KEY_F8;
|
||||
ui.screenshot = GDK_KEY_F9;
|
||||
ui.fdsflip = GDK_KEY_F3;
|
||||
ui.fdsswitch = GDK_KEY_F4;
|
||||
ui.insertcoin1 = GDK_KEY_F1;
|
||||
ui.insertcoin2 = GDK_KEY_F2;
|
||||
ui.reset = GDK_KEY_F12;
|
||||
ui.ffspeed = GDK_KEY_grave;
|
||||
ui.rwstart = GDK_KEY_BackSpace;
|
||||
ui.rwstop = GDK_KEY_backslash;
|
||||
ui.fullscreen = GDK_KEY_f;
|
||||
ui.filter = GDK_KEY_t;
|
||||
ui.scalefactor = GDK_KEY_g;
|
||||
}
|
||||
|
||||
void gtkui_input_config_read() {
|
||||
// Read the input config file
|
||||
snprintf(inputconfpath, sizeof(inputconfpath), "%sgtkinput.conf", nstpaths.nstconfdir);
|
||||
if (ini_parse(inputconfpath, gtkui_input_config_match, &inputconf) < 0) {
|
||||
fprintf(stderr, "Failed to load input config file %s: Using defaults.\n", inputconfpath);
|
||||
}
|
||||
else {
|
||||
// Map the input settings from the config file
|
||||
|
||||
// User Interface
|
||||
ui.qsave1 = gdk_keyval_from_name(inputconf.qsave1);
|
||||
ui.qsave2 = gdk_keyval_from_name(inputconf.qsave2);
|
||||
ui.qload1 = gdk_keyval_from_name(inputconf.qload1);
|
||||
ui.qload2 = gdk_keyval_from_name(inputconf.qload2);
|
||||
ui.screenshot = gdk_keyval_from_name(inputconf.screenshot);
|
||||
ui.fdsflip = gdk_keyval_from_name(inputconf.fdsflip);
|
||||
ui.fdsswitch = gdk_keyval_from_name(inputconf.fdsswitch);
|
||||
ui.insertcoin1 = gdk_keyval_from_name(inputconf.insertcoin1);
|
||||
ui.insertcoin2 = gdk_keyval_from_name(inputconf.insertcoin2);
|
||||
ui.reset = gdk_keyval_from_name(inputconf.reset);
|
||||
ui.ffspeed = gdk_keyval_from_name(inputconf.ffspeed);
|
||||
ui.rwstart = gdk_keyval_from_name(inputconf.rwstart);
|
||||
ui.rwstop = gdk_keyval_from_name(inputconf.rwstop);
|
||||
ui.fullscreen = gdk_keyval_from_name(inputconf.fullscreen);
|
||||
ui.filter = gdk_keyval_from_name(inputconf.filter);
|
||||
ui.scalefactor = gdk_keyval_from_name(inputconf.scalefactor);
|
||||
|
||||
// Player 1
|
||||
pad[0].u = gdk_keyval_from_name(inputconf.kb_p1u);
|
||||
pad[0].d = gdk_keyval_from_name(inputconf.kb_p1d);
|
||||
pad[0].l = gdk_keyval_from_name(inputconf.kb_p1l);
|
||||
pad[0].r = gdk_keyval_from_name(inputconf.kb_p1r);
|
||||
pad[0].select = gdk_keyval_from_name(inputconf.kb_p1select);
|
||||
pad[0].start = gdk_keyval_from_name(inputconf.kb_p1start);
|
||||
pad[0].a = gdk_keyval_from_name(inputconf.kb_p1a);
|
||||
pad[0].b = gdk_keyval_from_name(inputconf.kb_p1b);
|
||||
pad[0].ta = gdk_keyval_from_name(inputconf.kb_p1ta);
|
||||
pad[0].tb = gdk_keyval_from_name(inputconf.kb_p1tb);
|
||||
|
||||
// Player 2
|
||||
pad[1].u = gdk_keyval_from_name(inputconf.kb_p2u);
|
||||
pad[1].d = gdk_keyval_from_name(inputconf.kb_p2d);
|
||||
pad[1].l = gdk_keyval_from_name(inputconf.kb_p2l);
|
||||
pad[1].r = gdk_keyval_from_name(inputconf.kb_p2r);
|
||||
pad[1].select = gdk_keyval_from_name(inputconf.kb_p2select);
|
||||
pad[1].start = gdk_keyval_from_name(inputconf.kb_p2start);
|
||||
pad[1].a = gdk_keyval_from_name(inputconf.kb_p2a);
|
||||
pad[1].b = gdk_keyval_from_name(inputconf.kb_p2b);
|
||||
pad[1].ta = gdk_keyval_from_name(inputconf.kb_p2ta);
|
||||
pad[1].tb = gdk_keyval_from_name(inputconf.kb_p2tb);
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_input_config_write() {
|
||||
// Write out the input configuration file
|
||||
|
||||
FILE *fp = fopen(inputconfpath, "w");
|
||||
if (fp != NULL) {
|
||||
fprintf(fp, "; Nestopia UE GTK Input Configuration File\n\n");
|
||||
fprintf(fp, "; Values for keyboard input are these values with the GDK_KEY_ prefix removed:\n; https://git.gnome.org/browse/gtk+/plain/gdk/gdkkeysyms.h\n\n");
|
||||
|
||||
fprintf(fp, "[ui]\n");
|
||||
fprintf(fp, "qsave1=%s\n", gdk_keyval_name(ui.qsave1));
|
||||
fprintf(fp, "qsave2=%s\n", gdk_keyval_name(ui.qsave2));
|
||||
fprintf(fp, "qload1=%s\n", gdk_keyval_name(ui.qload1));
|
||||
fprintf(fp, "qload2=%s\n", gdk_keyval_name(ui.qload2));
|
||||
fprintf(fp, "screenshot=%s\n", gdk_keyval_name(ui.screenshot));
|
||||
fprintf(fp, "fdsflip=%s\n", gdk_keyval_name(ui.fdsflip));
|
||||
fprintf(fp, "fdsswitch=%s\n", gdk_keyval_name(ui.fdsswitch));
|
||||
fprintf(fp, "insertcoin1=%s\n", gdk_keyval_name(ui.insertcoin1));
|
||||
fprintf(fp, "insertcoin2=%s\n", gdk_keyval_name(ui.insertcoin2));
|
||||
fprintf(fp, "reset=%s\n", gdk_keyval_name(ui.reset));
|
||||
fprintf(fp, "ffspeed=%s\n", gdk_keyval_name(ui.ffspeed));
|
||||
fprintf(fp, "rwstart=%s\n", gdk_keyval_name(ui.rwstart));
|
||||
fprintf(fp, "rwstop=%s\n", gdk_keyval_name(ui.rwstop));
|
||||
fprintf(fp, "fullscreen=%s\n", gdk_keyval_name(ui.fullscreen));
|
||||
fprintf(fp, "filter=%s\n", gdk_keyval_name(ui.filter));
|
||||
fprintf(fp, "scalefactor=%s\n", gdk_keyval_name(ui.scalefactor));
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
fprintf(fp, "[gamepad1]\n");
|
||||
fprintf(fp, "kb_u=%s\n", gdk_keyval_name(pad[0].u));
|
||||
fprintf(fp, "kb_d=%s\n", gdk_keyval_name(pad[0].d));
|
||||
fprintf(fp, "kb_l=%s\n", gdk_keyval_name(pad[0].l));
|
||||
fprintf(fp, "kb_r=%s\n", gdk_keyval_name(pad[0].r));
|
||||
fprintf(fp, "kb_select=%s\n", gdk_keyval_name(pad[0].select));
|
||||
fprintf(fp, "kb_start=%s\n", gdk_keyval_name(pad[0].start));
|
||||
fprintf(fp, "kb_a=%s\n", gdk_keyval_name(pad[0].a));
|
||||
fprintf(fp, "kb_b=%s\n", gdk_keyval_name(pad[0].b));
|
||||
fprintf(fp, "kb_ta=%s\n", gdk_keyval_name(pad[0].ta));
|
||||
fprintf(fp, "kb_tb=%s\n", gdk_keyval_name(pad[0].tb));
|
||||
fprintf(fp, "\n"); // End of Section
|
||||
|
||||
fprintf(fp, "[gamepad2]\n");
|
||||
fprintf(fp, "kb_u=%s\n", gdk_keyval_name(pad[1].u));
|
||||
fprintf(fp, "kb_d=%s\n", gdk_keyval_name(pad[1].d));
|
||||
fprintf(fp, "kb_l=%s\n", gdk_keyval_name(pad[1].l));
|
||||
fprintf(fp, "kb_r=%s\n", gdk_keyval_name(pad[1].r));
|
||||
fprintf(fp, "kb_select=%s\n", gdk_keyval_name(pad[1].select));
|
||||
fprintf(fp, "kb_start=%s\n", gdk_keyval_name(pad[1].start));
|
||||
fprintf(fp, "kb_a=%s\n", gdk_keyval_name(pad[1].a));
|
||||
fprintf(fp, "kb_b=%s\n", gdk_keyval_name(pad[1].b));
|
||||
fprintf(fp, "kb_ta=%s\n", gdk_keyval_name(pad[1].ta));
|
||||
fprintf(fp, "kb_tb=%s\n", gdk_keyval_name(pad[1].tb));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void gtkui_input_config_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata) {
|
||||
keyval = event->keyval;
|
||||
if (keyval == GDK_KEY_Escape || keyval == GDK_KEY_space) { keyval = 0; }
|
||||
confrunning = false;
|
||||
}
|
||||
|
||||
void gtkui_input_config_signals_init() {
|
||||
// Key translation
|
||||
g_signal_connect(G_OBJECT(configwindow), "key-press-event",
|
||||
G_CALLBACK(gtkui_input_config_process_key), NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(configwindow), "key-release-event",
|
||||
G_CALLBACK(gtkui_input_config_process_key), NULL);
|
||||
}
|
||||
|
||||
void gtkui_input_config_signals_deinit() {
|
||||
// Key translation
|
||||
g_signal_connect(G_OBJECT(configwindow), "key-press-event",
|
||||
gtkui_input_null, NULL);
|
||||
|
||||
g_signal_connect(G_OBJECT(configwindow), "key-release-event",
|
||||
gtkui_input_null, NULL);
|
||||
}
|
||||
|
||||
void gtkui_input_config_key(int pnum, int bnum) {
|
||||
// Connect signals
|
||||
gtkui_input_config_signals_init();
|
||||
|
||||
// Wait for input
|
||||
confrunning = true;
|
||||
while (confrunning) { gtk_main_iteration(); }
|
||||
|
||||
// Set the keyval for the input item
|
||||
if (keyval != 0) {
|
||||
switch (bnum) {
|
||||
case 0: pad[pnum].u = keyval; break;
|
||||
case 1: pad[pnum].d = keyval; break;
|
||||
case 2: pad[pnum].l = keyval; break;
|
||||
case 3: pad[pnum].r = keyval; break;
|
||||
case 4: pad[pnum].select = keyval; break;
|
||||
case 5: pad[pnum].start = keyval; break;
|
||||
case 6: pad[pnum].a = keyval; break;
|
||||
case 7: pad[pnum].b = keyval; break;
|
||||
case 8: pad[pnum].ta = keyval; break;
|
||||
case 9: pad[pnum].tb = keyval; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect signals
|
||||
gtkui_input_config_signals_deinit();
|
||||
}
|
||||
|
||||
void gtkui_input_config_js(int pnum, int bnum) {
|
||||
// Wait for input
|
||||
nstsdl_input_conf_button(pnum, bnum);
|
||||
}
|
||||
|
||||
void gtkui_input_null() {}
|
||||
|
||||
int gtkui_input_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata) {
|
||||
// Process input from GDK events
|
||||
|
||||
nesinput_t input;
|
||||
|
||||
input.nescode = input.player = input.pressed = input.turboa = input.turbob = 0;
|
||||
|
||||
for (int i = 0; i < NUMGAMEPADS; i++) {
|
||||
if (event->keyval == pad[i].u) { input.player = i; input.nescode = Input::Controllers::Pad::UP; }
|
||||
else if (event->keyval == pad[i].d) { input.player = i; input.nescode = Input::Controllers::Pad::DOWN; }
|
||||
else if (event->keyval == pad[i].l) { input.player = i; input.nescode = Input::Controllers::Pad::LEFT; }
|
||||
else if (event->keyval == pad[i].r) { input.player = i; input.nescode = Input::Controllers::Pad::RIGHT; }
|
||||
else if (event->keyval == pad[i].select) { input.player = i; input.nescode = Input::Controllers::Pad::SELECT; }
|
||||
else if (event->keyval == pad[i].start) { input.player = i; input.nescode = Input::Controllers::Pad::START; }
|
||||
else if (event->keyval == pad[i].a) { input.player = i; input.nescode = Input::Controllers::Pad::A; }
|
||||
else if (event->keyval == pad[i].b) { input.player = i; input.nescode = Input::Controllers::Pad::B; }
|
||||
else if (event->keyval == pad[i].ta) { input.player = i; input.turboa = 1; input.nescode = Input::Controllers::Pad::A; }
|
||||
else if (event->keyval == pad[i].tb) { input.player = i; input.turbob = 1; input.nescode = Input::Controllers::Pad::B; }
|
||||
}
|
||||
|
||||
switch(event->type) {
|
||||
case GDK_KEY_PRESS:
|
||||
//printf("Keyval: %x\n", event->keyval);
|
||||
//printf("Keyval: %s\n", gdk_keyval_name(event->keyval));
|
||||
input.pressed = 1;
|
||||
if (event->keyval == ui.qsave1) { nst_state_quicksave(0); }
|
||||
else if (event->keyval == ui.qsave2) { nst_state_quicksave(1); }
|
||||
else if (event->keyval == ui.qload1) { nst_state_quickload(0); }
|
||||
else if (event->keyval == ui.qload2) { nst_state_quickload(1); }
|
||||
else if (event->keyval == ui.screenshot) { video_screenshot(NULL); }
|
||||
else if (event->keyval == ui.fdsflip) { nst_fds_flip(); }
|
||||
else if (event->keyval == ui.fdsswitch) { nst_fds_switch(); }
|
||||
else if (event->keyval == ui.insertcoin1) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_1; }
|
||||
else if (event->keyval == ui.insertcoin2) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_2; }
|
||||
else if (event->keyval == ui.reset) { nst_reset(0); }
|
||||
else if (event->keyval == ui.ffspeed) { nst_timing_set_ffspeed(); }
|
||||
else if (event->keyval == ui.rwstart) { nst_set_rewind(0); }
|
||||
else if (event->keyval == ui.rwstop) { nst_set_rewind(1); }
|
||||
else if (event->keyval == ui.filter) { gtkui_video_toggle_filter(); }
|
||||
else if (event->keyval == ui.scalefactor) { gtkui_video_toggle_scale(); }
|
||||
else if (event->keyval == gdk_keyval_from_name("space")) { cNstPads->pad[1].mic = 0x04; }
|
||||
break;
|
||||
case GDK_KEY_RELEASE:
|
||||
input.pressed = 0;
|
||||
if (event->keyval == ui.ffspeed) { nst_timing_set_default(); }
|
||||
else if (event->keyval == ui.fullscreen) { gtkui_video_toggle_fullscreen(); }
|
||||
else if (event->keyval == gdk_keyval_from_name("space")) { cNstPads->pad[1].mic = 0x00; }
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
nst_input_inject(cNstPads, input);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int gtkui_input_process_key_nsf(GtkWidget *widget, GdkEventKey *event, gpointer userdata) {
|
||||
if (event->type == GDK_KEY_RELEASE) {
|
||||
if (event->keyval == GDK_KEY_Up) { nst_nsf_play(); }
|
||||
if (event->keyval == GDK_KEY_Down) { nst_nsf_stop(); }
|
||||
if (event->keyval == GDK_KEY_Left) { nst_nsf_prev(); }
|
||||
if (event->keyval == GDK_KEY_Right) { nst_nsf_next(); }
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int gtkui_input_process_mouse(GtkWidget *widget, GdkEventButton *event, gpointer userdata) {
|
||||
switch(event->type) {
|
||||
case GDK_BUTTON_PRESS:
|
||||
nst_input_inject_mouse(cNstPads, event->button, 1, (int)event->x, (int)event->y);
|
||||
break;
|
||||
|
||||
case GDK_BUTTON_RELEASE:
|
||||
nst_input_inject_mouse(cNstPads, event->button, 0, (int)event->x, (int)event->y);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
#ifndef _GTKUI_INPUT_H_
|
||||
#define _GTKUI_INPUT_H_
|
||||
|
||||
typedef struct {
|
||||
guint u;
|
||||
guint d;
|
||||
guint l;
|
||||
guint r;
|
||||
guint select;
|
||||
guint start;
|
||||
guint a;
|
||||
guint b;
|
||||
guint ta;
|
||||
guint tb;
|
||||
} gpad_t;
|
||||
|
||||
typedef struct {
|
||||
guint qsave1;
|
||||
guint qsave2;
|
||||
guint qload1;
|
||||
guint qload2;
|
||||
guint screenshot;
|
||||
guint fdsflip;
|
||||
guint fdsswitch;
|
||||
guint insertcoin1;
|
||||
guint insertcoin2;
|
||||
guint reset;
|
||||
guint ffspeed;
|
||||
guint rwstart;
|
||||
guint rwstop;
|
||||
guint fullscreen;
|
||||
guint filter;
|
||||
guint scalefactor;
|
||||
} gkeys_t;
|
||||
|
||||
typedef struct {
|
||||
// User Interface
|
||||
char *qsave1;
|
||||
char *qsave2;
|
||||
char *qload1;
|
||||
char *qload2;
|
||||
|
||||
char *screenshot;
|
||||
|
||||
char *fdsflip;
|
||||
char *fdsswitch;
|
||||
|
||||
char *insertcoin1;
|
||||
char *insertcoin2;
|
||||
|
||||
char *reset;
|
||||
|
||||
char *ffspeed;
|
||||
char *rwstart;
|
||||
char *rwstop;
|
||||
|
||||
char *fullscreen;
|
||||
char *filter;
|
||||
char *scalefactor;
|
||||
|
||||
// Player 1
|
||||
char *kb_p1u;
|
||||
char *kb_p1d;
|
||||
char *kb_p1l;
|
||||
char *kb_p1r;
|
||||
char *kb_p1select;
|
||||
char *kb_p1start;
|
||||
char *kb_p1a;
|
||||
char *kb_p1b;
|
||||
char *kb_p1ta;
|
||||
char *kb_p1tb;
|
||||
|
||||
// Player 2
|
||||
char *kb_p2u;
|
||||
char *kb_p2d;
|
||||
char *kb_p2l;
|
||||
char *kb_p2r;
|
||||
char *kb_p2select;
|
||||
char *kb_p2start;
|
||||
char *kb_p2a;
|
||||
char *kb_p2b;
|
||||
char *kb_p2ta;
|
||||
char *kb_p2tb;
|
||||
} ginputsettings_t;
|
||||
|
||||
void gtkui_input_set_default();
|
||||
void gtkui_input_config_read();
|
||||
void gtkui_input_config_write();
|
||||
void gtkui_input_config_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata);
|
||||
void gtkui_input_config_signals_init();
|
||||
void gtkui_input_config_signals_deinit();
|
||||
void gtkui_input_config_key(int pnum, int bnum);
|
||||
void gtkui_input_config_js(int pnum, int bnum);
|
||||
void gtkui_input_null();
|
||||
int gtkui_input_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata);
|
||||
int gtkui_input_process_key_nsf(GtkWidget *widget, GdkEventKey *event, gpointer userdata);
|
||||
int gtkui_input_process_mouse(GtkWidget *widget, GdkEventButton *event, gpointer userdata);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue