diff --git a/Makefile.wii b/Makefile.wii index 8eece93..67bbff9 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -1,161 +1,163 @@ -#--------------------------------------------------------------------------------- -# Clear the implicit built in rules -#--------------------------------------------------------------------------------- -.SUFFIXES: -#--------------------------------------------------------------------------------- -ifeq ($(strip $(DEVKITPPC)),) -$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") -endif - -include $(DEVKITPPC)/wii_rules - -#--------------------------------------------------------------------------------- -# TARGET is the name of the output -# BUILD is the directory where object files & intermediate files will be placed -# SOURCES is a list of directories containing source code -# INCLUDES is a list of directories containing extra header files -#--------------------------------------------------------------------------------- -TARGET := frodo -BUILD := build -SOURCES := Src -DATA := -INCLUDES := - -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- - -PCFLAGS = -DPRECISE_CPU_CYCLES=1 -DPRECISE_CIA_CYCLES=1 -DPC_IS_POINTER=0 -SCFLAGS = $(PCFLAGS) -DFRODO_SC -CFLAGS = -O3 -g -Wall $(MACHDEP) $(INCLUDE) -U__unix -DHAVE_SDL $(SCFLAGS) -I$(LIBOGC_INC)/SDL -I$(PWD)/Src/ -CXXFLAGS = $(CFLAGS) - -LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map - -#--------------------------------------------------------------------------------- -# any extra libraries we wish to link with the project -#--------------------------------------------------------------------------------- -LIBS := -lSDL_ttf -lSDL_image -lpng -ljpeg -lz -lSDL -lfreetype -lfat -lwiiuse -lbte -logc -lm -lwiikeyboard - -#--------------------------------------------------------------------------------- -# list of directories containing libraries, this must be the top level containing -# include and lib -#--------------------------------------------------------------------------------- -LIBDIRS := - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- - -export OUTPUT := $(CURDIR)/$(TARGET) - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -export DEPSDIR := $(CURDIR)/$(BUILD) - -#--------------------------------------------------------------------------------- -# automatically build a list of object files for our project -#--------------------------------------------------------------------------------- -CFILES := gcaudio.c d64-read.c gui/menu_messages.c -CPPFILES := Display.cpp main.cpp Prefs.cpp SID.cpp REU.cpp IEC.cpp 1541fs.cpp \ - 1541d64.cpp 1541t64.cpp 1541job.cpp C64_SC.cpp CPUC64_SC.cpp VIC_SC.cpp \ - CIA_SC.cpp CPU1541_SC.cpp CPU_common.cpp \ - Network.cpp gui/dialogue_box.cpp gui/widget.cpp utils.cpp \ - gui/game_info.cpp gui/status_bar.cpp gui/gui.cpp gui/listener.cpp \ - timer.cpp utils.cpp gui/virtual_keyboard.cpp gui/menu.cpp \ - gui/file_browser.cpp data_store.cpp gui/network_server_messages.cpp - -sFILES := -SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) - -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) - export LD := $(CC) -else - export LD := $(CXX) -endif - -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ - $(sFILES:.s=.o) $(SFILES:.S=.o) - -#--------------------------------------------------------------------------------- -# build a list of include paths -#--------------------------------------------------------------------------------- -export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) \ - -I$(LIBOGC_INC) - -#--------------------------------------------------------------------------------- -# build a list of library paths -#--------------------------------------------------------------------------------- -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ - -L$(LIBOGC_LIB) -L/opt/devkitpro/libogc/lib - -export OUTPUT := $(CURDIR)/$(TARGET) -.PHONY: $(BUILD) clean - -#--------------------------------------------------------------------------------- -$(BUILD): - @[ -d $@ ] || mkdir -p $@ $@/gui - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.wii - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol Src/*.o \ - FrodoSC FrodoPC dist - -dist: $(BUILD) - rm -rf $@ - install -d $@/apps/frodo - install -d $@/frodo/images - install -d $@/frodo/saves - install -d $@/frodo/metadata - install -d $@/frodo/tmp - echo "a" > $@/frodo/tmp/dummy - touch $@/apps/frodo/frodorc - cp $(TARGET).dol $@/apps/frodo/boot.dol - cp -rap themes $@/frodo/themes - cp meta.xml $@/apps/frodo/ - cp icon.png $@/apps/frodo/ - find $@ -name ".svn" | xargs rm -rf - cd $@ && tar -czf ../c64-network.org-wii-bin.tar.gz * - -#--------------------------------------------------------------------------------- -run: - wiiload $(TARGET).dol - - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -$(OUTPUT).dol: $(OUTPUT).elf -$(OUTPUT).elf: $(OFILES) - -#--------------------------------------------------------------------------------- -# This rule links in binary data with the .jpg extension -#--------------------------------------------------------------------------------- -%.jpg.o : %.jpg -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - $(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +include $(DEVKITPPC)/wii_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := frodo +BUILD := build +SOURCES := Src +DATA := +INCLUDES := + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +PCFLAGS = -DPRECISE_CPU_CYCLES=1 -DPRECISE_CIA_CYCLES=1 -DPC_IS_POINTER=0 -DWII_PORT +SCFLAGS = $(PCFLAGS) -DFRODO_SC +CFLAGS = -O3 -g -Wall $(MACHDEP) $(INCLUDE) -DHAVE_SDL $(SCFLAGS) -I$(LIBOGC_INC)/SDL +CXXFLAGS = $(CFLAGS) + +LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lSDL_ttf -lSDL_image -lpng -ljpeg -lz -lSDL -lfreetype -lfat -lwiiuse -lbte -logc -lm -lwiikeyboard + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := gcaudio.c d64-read.c gui/menu_messages.c +CPPFILES := Display.cpp main.cpp Prefs.cpp SID.cpp REU.cpp IEC.cpp 1541fs.cpp \ + 1541d64.cpp 1541t64.cpp 1541job.cpp C64_SC.cpp CPUC64_SC.cpp VIC_SC.cpp \ + CIA_SC.cpp CPU1541_SC.cpp CPU_common.cpp \ + Network.cpp gui/dialogue_box.cpp gui/widget.cpp utils.cpp \ + gui/game_info.cpp gui/status_bar.cpp gui/gui.cpp gui/listener.cpp \ + timer.cpp utils.cpp gui/virtual_keyboard.cpp gui/menu.cpp \ + gui/file_browser.cpp data_store.cpp gui/network_server_messages.cpp + +sFILES := +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) \ + -I$(CURDIR)/Src \ + -I$(PORTLIBS)/include + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) -L/opt/devkitpro/libogc/lib + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ $@/gui + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.wii + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol Src/*.o \ + FrodoSC FrodoPC dist + +dist: $(BUILD) + rm -rf $@ + install -d $@/apps/frodo + install -d $@/frodo/images + install -d $@/frodo/saves + install -d $@/frodo/metadata + install -d $@/frodo/tmp + echo "a" > $@/frodo/tmp/dummy + touch $@/apps/frodo/frodorc + cp $(TARGET).dol $@/apps/frodo/boot.dol + cp -rap themes $@/frodo/themes + cp meta.xml $@/apps/frodo/ + cp icon.png $@/apps/frodo/ + find $@ -name ".svn" | xargs rm -rf + cd $@ && tar -czf ../c64-network.org-wii-bin.tar.gz * + +#--------------------------------------------------------------------------------- +run: + wiiload $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/Src/C64.cpp b/Src/C64.cpp index a7a464b..c9b61e0 100644 --- a/Src/C64.cpp +++ b/Src/C64.cpp @@ -1,707 +1,708 @@ -/* - * C64.cpp - Put the pieces together - * - * Frodo (C) 1994-1997,2002-2005 Christian Bauer - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sysdeps.h" - -#include "C64.h" -#include "CPUC64.h" -#include "CPU1541.h" -#include "VIC.h" -#include "SID.h" -#include "CIA.h" -#include "REU.h" -#include "IEC.h" -#include "1541job.h" -#include "Display.h" -#include "Prefs.h" - -#ifdef FRODO_SC -bool IsFrodoSC = true; -#else -bool IsFrodoSC = false; -#endif - - -/* - * Constructor: Allocate objects and memory - */ - -C64::C64() -{ - uint8 *p; - - // The thread is not yet running - thread_running = false; - quit_thyself = false; - have_a_break = false; - - // System-dependent things - c64_ctor1(); - - // Open display - printf("ssof1 %d:%d\n", - sizeof(C64Display), sizeof(C64)); - TheDisplay = new C64Display(this); - - // Allocate RAM/ROM memory - RAM = new uint8[C64_RAM_SIZE]; - Basic = new uint8[BASIC_ROM_SIZE]; - Kernal = new uint8[KERNAL_ROM_SIZE]; - Char = new uint8[CHAR_ROM_SIZE]; - Color = new uint8[COLOR_RAM_SIZE]; - RAM1541 = new uint8[DRIVE_RAM_SIZE]; - ROM1541 = new uint8[DRIVE_ROM_SIZE]; - - // Create the chips - TheCPU = new MOS6510(this, RAM, Basic, Kernal, Char, Color); - - TheJob1541 = new Job1541(RAM1541); - TheCPU1541 = new MOS6502_1541(this, TheJob1541, TheDisplay, RAM1541, ROM1541); - - TheVIC = TheCPU->TheVIC = new MOS6569(this, TheDisplay, TheCPU, RAM, Char, Color); - TheSID = TheCPU->TheSID = new MOS6581(this); - TheCIA1 = TheCPU->TheCIA1 = new MOS6526_1(TheCPU, TheVIC); - TheCIA2 = TheCPU->TheCIA2 = TheCPU1541->TheCIA2 = new MOS6526_2(TheCPU, TheVIC, TheCPU1541); - TheIEC = TheCPU->TheIEC = new IEC(TheDisplay); - TheREU = TheCPU->TheREU = new REU(TheCPU); - - // Initialize RAM with powerup pattern - p = RAM; - for (unsigned i=0; i<512; i++) { - for (unsigned j=0; j<64; j++) - *p++ = 0; - for (unsigned j=0; j<64; j++) - *p++ = 0xff; - } - - // Initialize color RAM with random values - p = Color; - for (unsigned i=0; iAsyncReset(); - TheCPU1541->AsyncReset(); - TheSID->Reset(); - TheCIA1->Reset(); - TheCIA2->Reset(); - TheIEC->Reset(); -} - - -/* - * NMI C64 - */ - -void C64::NMI(void) -{ - TheCPU->AsyncNMI(); -} - - -/* - * The preferences have changed. prefs is a pointer to the new - * preferences, ThePrefs still holds the previous ones. - * The emulation must be in the paused state! - */ - -void C64::NewPrefs(Prefs *prefs) -{ - PatchKernal(prefs->FastReset, prefs->Emul1541Proc); - - TheDisplay->NewPrefs(prefs); - - TheIEC->NewPrefs(prefs); - TheJob1541->NewPrefs(prefs); - - TheREU->NewPrefs(prefs); - TheSID->NewPrefs(prefs); - - // Reset 1541 processor if turned on - if (!ThePrefs.Emul1541Proc && prefs->Emul1541Proc) - TheCPU1541->AsyncReset(); -} - - -/* - * Patch kernal IEC routines - */ - -void C64::PatchKernal(bool fast_reset, bool emul_1541_proc) -{ - if (fast_reset) { - Kernal[0x1d84] = 0xa0; - Kernal[0x1d85] = 0x00; - } else { - Kernal[0x1d84] = orig_kernal_1d84; - Kernal[0x1d85] = orig_kernal_1d85; - } - - if (emul_1541_proc) { - Kernal[0x0d40] = 0x78; - Kernal[0x0d41] = 0x20; - Kernal[0x0d23] = 0x78; - Kernal[0x0d24] = 0x20; - Kernal[0x0d36] = 0x78; - Kernal[0x0d37] = 0x20; - Kernal[0x0e13] = 0x78; - Kernal[0x0e14] = 0xa9; - Kernal[0x0def] = 0x78; - Kernal[0x0df0] = 0x20; - Kernal[0x0dbe] = 0xad; - Kernal[0x0dbf] = 0x00; - Kernal[0x0dcc] = 0x78; - Kernal[0x0dcd] = 0x20; - Kernal[0x0e03] = 0x20; - Kernal[0x0e04] = 0xbe; - } else { - Kernal[0x0d40] = 0xf2; // IECOut - Kernal[0x0d41] = 0x00; - Kernal[0x0d23] = 0xf2; // IECOutATN - Kernal[0x0d24] = 0x01; - Kernal[0x0d36] = 0xf2; // IECOutSec - Kernal[0x0d37] = 0x02; - Kernal[0x0e13] = 0xf2; // IECIn - Kernal[0x0e14] = 0x03; - Kernal[0x0def] = 0xf2; // IECSetATN - Kernal[0x0df0] = 0x04; - Kernal[0x0dbe] = 0xf2; // IECRelATN - Kernal[0x0dbf] = 0x05; - Kernal[0x0dcc] = 0xf2; // IECTurnaround - Kernal[0x0dcd] = 0x06; - Kernal[0x0e03] = 0xf2; // IECRelease - Kernal[0x0e04] = 0x07; - } - - // 1541 - ROM1541[0x2ae4] = 0xea; // Don't check ROM checksum - ROM1541[0x2ae5] = 0xea; - ROM1541[0x2ae8] = 0xea; - ROM1541[0x2ae9] = 0xea; - ROM1541[0x2c9b] = 0xf2; // DOS idle loop - ROM1541[0x2c9c] = 0x00; - ROM1541[0x3594] = 0x20; // Write sector - ROM1541[0x3595] = 0xf2; - ROM1541[0x3596] = 0xf5; - ROM1541[0x3597] = 0xf2; - ROM1541[0x3598] = 0x01; - ROM1541[0x3b0c] = 0xf2; // Format track - ROM1541[0x3b0d] = 0x02; -} - - -/* - * Save RAM contents - */ - -void C64::SaveRAM(char *filename) -{ - FILE *f; - - if ((f = fopen(filename, "wb")) == NULL) - ShowRequester("RAM save failed.", "OK", NULL); - else { - fwrite((void*)RAM, 1, 0x10000, f); - fwrite((void*)Color, 1, 0x400, f); - if (ThePrefs.Emul1541Proc) - fwrite((void*)RAM1541, 1, 0x800, f); - fclose(f); - } -} - - -/* - * Save CPU state to snapshot - * - * 0: Error - * 1: OK - * -1: Instruction not completed - */ - -int C64::SaveCPUState(FILE *f) -{ - MOS6510State state; - TheCPU->GetState(&state); - - if (!state.instruction_complete) - return -1; - - int i = fwrite(RAM, 0x10000, 1, f); - i += fwrite(Color, 0x400, 1, f); - i += fwrite((void*)&state, sizeof(state), 1, f); - - return i == 3; -} - - -/* - * Load CPU state from snapshot - */ - -bool C64::LoadCPUState(FILE *f) -{ - MOS6510State state; - - int i = fread(RAM, 0x10000, 1, f); - i += fread(Color, 0x400, 1, f); - i += fread((void*)&state, sizeof(state), 1, f); - - if (i == 3) { - TheCPU->SetState(&state); - return true; - } else - return false; -} - - -/* - * Save 1541 state to snapshot - * - * 0: Error - * 1: OK - * -1: Instruction not completed - */ - -int C64::Save1541State(FILE *f) -{ - MOS6502State state; - TheCPU1541->GetState(&state); - - if (!state.idle && !state.instruction_complete) - return -1; - - int i = fwrite(RAM1541, 0x800, 1, f); - i += fwrite((void*)&state, sizeof(state), 1, f); - - return i == 2; -} - - -/* - * Load 1541 state from snapshot - */ - -bool C64::Load1541State(FILE *f) -{ - MOS6502State state; - - int i = fread(RAM1541, 0x800, 1, f); - i += fread((void*)&state, sizeof(state), 1, f); - - if (i == 2) { - TheCPU1541->SetState(&state); - return true; - } else - return false; -} - - -/* - * Save VIC state to snapshot - */ - -bool C64::SaveVICState(FILE *f) -{ - MOS6569State state; - TheVIC->GetState(&state); - return fwrite((void*)&state, sizeof(state), 1, f) == 1; -} - - -/* - * Load VIC state from snapshot - */ - -bool C64::LoadVICState(FILE *f) -{ - MOS6569State state; - - if (fread((void*)&state, sizeof(state), 1, f) == 1) { - TheVIC->SetState(&state); - return true; - } else - return false; -} - - -/* - * Save SID state to snapshot - */ - -bool C64::SaveSIDState(FILE *f) -{ - MOS6581State state; - TheSID->GetState(&state); - return fwrite((void*)&state, sizeof(state), 1, f) == 1; -} - - -/* - * Load SID state from snapshot - */ - -bool C64::LoadSIDState(FILE *f) -{ - MOS6581State state; - - if (fread((void*)&state, sizeof(state), 1, f) == 1) { - TheSID->SetState(&state); - return true; - } else - return false; -} - - -/* - * Save CIA states to snapshot - */ - -bool C64::SaveCIAState(FILE *f) -{ - MOS6526State state; - TheCIA1->GetState(&state); - - if (fwrite((void*)&state, sizeof(state), 1, f) == 1) { - TheCIA2->GetState(&state); - return fwrite((void*)&state, sizeof(state), 1, f) == 1; - } else - return false; -} - - -/* - * Load CIA states from snapshot - */ - -bool C64::LoadCIAState(FILE *f) -{ - MOS6526State state; - - if (fread((void*)&state, sizeof(state), 1, f) == 1) { - TheCIA1->SetState(&state); - if (fread((void*)&state, sizeof(state), 1, f) == 1) { - TheCIA2->SetState(&state); - return true; - } else - return false; - } else - return false; -} - - -/* - * Save 1541 GCR state to snapshot - */ - -bool C64::Save1541JobState(FILE *f) -{ - Job1541State state; - TheJob1541->GetState(&state); - return fwrite((void*)&state, sizeof(state), 1, f) == 1; -} - - -/* - * Load 1541 GCR state from snapshot - */ - -bool C64::Load1541JobState(FILE *f) -{ - Job1541State state; - - if (fread((void*)&state, sizeof(state), 1, f) == 1) { - TheJob1541->SetState(&state); - return true; - } else - return false; -} - - -#define SNAPSHOT_HEADER "FrodoSnapshot" -#define SNAPSHOT_1541 1 - -#define ADVANCE_CYCLES \ - TheVIC->EmulateCycle(); \ - TheCIA1->EmulateCycle(); \ - TheCIA2->EmulateCycle(); \ - TheCPU->EmulateCycle(); \ - if (ThePrefs.Emul1541Proc) { \ - TheCPU1541->CountVIATimers(1); \ - if (!TheCPU1541->Idle) \ - TheCPU1541->EmulateCycle(); \ - } - - -/* - * Save snapshot (emulation must be paused and in VBlank) - * - * To be able to use SC snapshots with SL, SC snapshots are made thus that no - * partially dealt with instructions are saved. Instead all devices are advanced - * cycle by cycle until the current instruction has been finished. The number of - * cycles this takes is saved in the snapshot and will be reconstructed if the - * snapshot is loaded into FrodoSC again. - */ - -void C64::SaveSnapshot(const char *filename) -{ - FILE *f; - uint8 flags; - uint8 delay; - int stat; - - if ((f = fopen(filename, "wb")) == NULL) { - ShowRequester("Unable to open snapshot file", "OK", NULL); - return; - } - - fprintf(f, "%s%c", SNAPSHOT_HEADER, 10); - fputc(0, f); // Version number 0 - flags = 0; - if (ThePrefs.Emul1541Proc) - flags |= SNAPSHOT_1541; - fputc(flags, f); - SaveVICState(f); - SaveSIDState(f); - SaveCIAState(f); - -#ifdef FRODO_SC - delay = 0; - do { - if ((stat = SaveCPUState(f)) == -1) { // -1 -> Instruction not finished yet - ADVANCE_CYCLES; // Advance everything by one cycle - delay++; - } - } while (stat == -1); - fputc(delay, f); // Number of cycles the saved CPUC64 lags behind the previous chips -#else - SaveCPUState(f); - fputc(0, f); // No delay -#endif - - if (ThePrefs.Emul1541Proc) { - fwrite(ThePrefs.DrivePath[0], 256, 1, f); -#ifdef FRODO_SC - delay = 0; - do { - if ((stat = Save1541State(f)) == -1) { - ADVANCE_CYCLES; - delay++; - } - } while (stat == -1); - fputc(delay, f); -#else - Save1541State(f); - fputc(0, f); // No delay -#endif - Save1541JobState(f); - } - fclose(f); - -} - - -/* - * Load snapshot (emulation must be paused and in VBlank) - */ - -bool C64::LoadSnapshot(const char *filename) -{ - FILE *f; - - if ((f = fopen(filename, "rb")) != NULL) { - char Header[] = SNAPSHOT_HEADER; - char *b = Header, c = 0; - uint8 delay, i; - - // For some reason memcmp()/strcmp() and so forth utterly fail here. - while (*b > 32) { - if ((c = fgetc(f)) != *b++) { - b = NULL; - break; - } - } - if (b != NULL) { - uint8 flags; - bool error = false; -#ifndef FRODO_SC - long vicptr; // File offset of VIC data -#endif - - while (c != 10) - c = fgetc(f); // Shouldn't be necessary - if (fgetc(f) != 0) { - ShowRequester("Unknown snapshot format", "OK", NULL); - fclose(f); - return false; - } - flags = fgetc(f); -#ifndef FRODO_SC - vicptr = ftell(f); -#endif - - error |= !LoadVICState(f); - error |= !LoadSIDState(f); - error |= !LoadCIAState(f); - error |= !LoadCPUState(f); - - delay = fgetc(f); // Number of cycles the 6510 is ahead of the previous chips -#ifdef FRODO_SC - // Make the other chips "catch up" with the 6510 - for (i=0; iEmulateCycle(); - TheCIA1->EmulateCycle(); - TheCIA2->EmulateCycle(); - } -#endif - if ((flags & SNAPSHOT_1541) != 0) { - Prefs *prefs = new Prefs(ThePrefs); - - // First switch on emulation - error |= (fread(prefs->DrivePath[0], 256, 1, f) != 1); - prefs->Emul1541Proc = true; - NewPrefs(prefs); - ThePrefs = *prefs; - delete prefs; - - // Then read the context - error |= !Load1541State(f); - - delay = fgetc(f); // Number of cycles the 6502 is ahead of the previous chips -#ifdef FRODO_SC - // Make the other chips "catch up" with the 6502 - for (i=0; iEmulateCycle(); - TheCIA1->EmulateCycle(); - TheCIA2->EmulateCycle(); - TheCPU->EmulateCycle(); - } -#endif - Load1541JobState(f); - } else if (ThePrefs.Emul1541Proc) { // No emulation in snapshot, but currently active? - Prefs *prefs = new Prefs(ThePrefs); - prefs->Emul1541Proc = false; - NewPrefs(prefs); - ThePrefs = *prefs; - delete prefs; - } - -#ifndef FRODO_SC - fseek(f, vicptr, SEEK_SET); - LoadVICState(f); // Load VIC data twice in SL (is REALLY necessary sometimes!) -#endif - fclose(f); - - if (error) { - ShowRequester("Error reading snapshot file", "OK", NULL); - Reset(); - return false; - } else - return true; - } else { - fclose(f); - ShowRequester("Not a Frodo snapshot file", "OK", NULL); - return false; - } - } else { - ShowRequester("Can't open snapshot file", "OK", NULL); - return false; - } -} - -void C64::Pause(void) -{ - /* No pause when the network is running */ - if (this->network) - { - this->have_a_break = false; - return; - } - - this->have_a_break = true; - TheSID->PauseSound(); -} - -bool C64::IsPaused() -{ - return this->have_a_break; -} - - -void C64::Resume(void) -{ - this->have_a_break = false; - TheSID->ResumeSound(); -} - -#include "C64_SDL.h" +/* + * C64.cpp - Put the pieces together + * + * Frodo (C) 1994-1997,2002-2005 Christian Bauer + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" + +#include "C64.h" +#include "CPUC64.h" +#include "CPU1541.h" +#include "VIC.h" +#include "SID.h" +#include "CIA.h" +#include "REU.h" +#include "IEC.h" +#include "1541job.h" +#include "Display.h" +#include "Prefs.h" + +#ifdef FRODO_SC +bool IsFrodoSC = true; +#else +bool IsFrodoSC = false; +#endif + + +/* + * Constructor: Allocate objects and memory + */ + +C64::C64() +{ + uint8 *p; + + // The thread is not yet running + thread_running = false; + quit_thyself = false; + have_a_break = false; + + // System-dependent things + c64_ctor1(); + + // Open display + printf("ssof1 %d:%d\n", + sizeof(C64Display), sizeof(C64)); + TheDisplay = new C64Display(this); + + // Allocate RAM/ROM memory + RAM = new uint8[C64_RAM_SIZE]; + Basic = new uint8[BASIC_ROM_SIZE]; + Kernal = new uint8[KERNAL_ROM_SIZE]; + Char = new uint8[CHAR_ROM_SIZE]; + Color = new uint8[COLOR_RAM_SIZE]; + RAM1541 = new uint8[DRIVE_RAM_SIZE]; + ROM1541 = new uint8[DRIVE_ROM_SIZE]; + + // Create the chips + TheCPU = new MOS6510(this, RAM, Basic, Kernal, Char, Color); + + TheJob1541 = new Job1541(RAM1541); + TheCPU1541 = new MOS6502_1541(this, TheJob1541, TheDisplay, RAM1541, ROM1541); + + TheVIC = TheCPU->TheVIC = new MOS6569(this, TheDisplay, TheCPU, RAM, Char, Color); + TheSID = TheCPU->TheSID = new MOS6581(this); + TheCIA1 = TheCPU->TheCIA1 = new MOS6526_1(TheCPU, TheVIC); + TheCIA2 = TheCPU->TheCIA2 = TheCPU1541->TheCIA2 = new MOS6526_2(TheCPU, TheVIC, TheCPU1541); + TheIEC = TheCPU->TheIEC = new IEC(TheDisplay); + TheREU = TheCPU->TheREU = new REU(TheCPU); + + // Initialize RAM with powerup pattern + p = RAM; + for (unsigned i=0; i<512; i++) { + for (unsigned j=0; j<64; j++) + *p++ = 0; + for (unsigned j=0; j<64; j++) + *p++ = 0xff; + } + + // Initialize color RAM with random values + p = Color; + for (unsigned i=0; iAsyncReset(); + TheCPU1541->AsyncReset(); + TheSID->Reset(); + TheCIA1->Reset(); + TheCIA2->Reset(); + TheIEC->Reset(); +} + + +/* + * NMI C64 + */ + +void C64::NMI(void) +{ + TheCPU->AsyncNMI(); +} + + +/* + * The preferences have changed. prefs is a pointer to the new + * preferences, ThePrefs still holds the previous ones. + * The emulation must be in the paused state! + */ + +void C64::NewPrefs(Prefs *prefs) +{ + PatchKernal(prefs->FastReset, prefs->Emul1541Proc); + + TheDisplay->NewPrefs(prefs); + + TheIEC->NewPrefs(prefs); + TheJob1541->NewPrefs(prefs); + + TheREU->NewPrefs(prefs); + TheSID->NewPrefs(prefs); + + // Reset 1541 processor if turned on + if (!ThePrefs.Emul1541Proc && prefs->Emul1541Proc) + TheCPU1541->AsyncReset(); +} + + +/* + * Patch kernal IEC routines + */ + +void C64::PatchKernal(bool fast_reset, bool emul_1541_proc) +{ + if (fast_reset) { + Kernal[0x1d84] = 0xa0; + Kernal[0x1d85] = 0x00; + } else { + Kernal[0x1d84] = orig_kernal_1d84; + Kernal[0x1d85] = orig_kernal_1d85; + } + + if (emul_1541_proc) { + Kernal[0x0d40] = 0x78; + Kernal[0x0d41] = 0x20; + Kernal[0x0d23] = 0x78; + Kernal[0x0d24] = 0x20; + Kernal[0x0d36] = 0x78; + Kernal[0x0d37] = 0x20; + Kernal[0x0e13] = 0x78; + Kernal[0x0e14] = 0xa9; + Kernal[0x0def] = 0x78; + Kernal[0x0df0] = 0x20; + Kernal[0x0dbe] = 0xad; + Kernal[0x0dbf] = 0x00; + Kernal[0x0dcc] = 0x78; + Kernal[0x0dcd] = 0x20; + Kernal[0x0e03] = 0x20; + Kernal[0x0e04] = 0xbe; + } else { + Kernal[0x0d40] = 0xf2; // IECOut + Kernal[0x0d41] = 0x00; + Kernal[0x0d23] = 0xf2; // IECOutATN + Kernal[0x0d24] = 0x01; + Kernal[0x0d36] = 0xf2; // IECOutSec + Kernal[0x0d37] = 0x02; + Kernal[0x0e13] = 0xf2; // IECIn + Kernal[0x0e14] = 0x03; + Kernal[0x0def] = 0xf2; // IECSetATN + Kernal[0x0df0] = 0x04; + Kernal[0x0dbe] = 0xf2; // IECRelATN + Kernal[0x0dbf] = 0x05; + Kernal[0x0dcc] = 0xf2; // IECTurnaround + Kernal[0x0dcd] = 0x06; + Kernal[0x0e03] = 0xf2; // IECRelease + Kernal[0x0e04] = 0x07; + } + + // 1541 + ROM1541[0x2ae4] = 0xea; // Don't check ROM checksum + ROM1541[0x2ae5] = 0xea; + ROM1541[0x2ae8] = 0xea; + ROM1541[0x2ae9] = 0xea; + ROM1541[0x2c9b] = 0xf2; // DOS idle loop + ROM1541[0x2c9c] = 0x00; + ROM1541[0x3594] = 0x20; // Write sector + ROM1541[0x3595] = 0xf2; + ROM1541[0x3596] = 0xf5; + ROM1541[0x3597] = 0xf2; + ROM1541[0x3598] = 0x01; + ROM1541[0x3b0c] = 0xf2; // Format track + ROM1541[0x3b0d] = 0x02; +} + + +/* + * Save RAM contents + */ + +void C64::SaveRAM(char *filename) +{ + FILE *f; + + if ((f = fopen(filename, "wb")) == NULL) + ShowRequester("RAM save failed.", "OK", NULL); + else { + fwrite((void*)RAM, 1, 0x10000, f); + fwrite((void*)Color, 1, 0x400, f); + if (ThePrefs.Emul1541Proc) + fwrite((void*)RAM1541, 1, 0x800, f); + fclose(f); + } +} + + +/* + * Save CPU state to snapshot + * + * 0: Error + * 1: OK + * -1: Instruction not completed + */ + +int C64::SaveCPUState(FILE *f) +{ + MOS6510State state; + TheCPU->GetState(&state); + + if (!state.instruction_complete) + return -1; + + int i = fwrite(RAM, 0x10000, 1, f); + i += fwrite(Color, 0x400, 1, f); + i += fwrite((void*)&state, sizeof(state), 1, f); + + return i == 3; +} + + +/* + * Load CPU state from snapshot + */ + +bool C64::LoadCPUState(FILE *f) +{ + MOS6510State state; + + int i = fread(RAM, 0x10000, 1, f); + i += fread(Color, 0x400, 1, f); + i += fread((void*)&state, sizeof(state), 1, f); + + if (i == 3) { + TheCPU->SetState(&state); + return true; + } else + return false; +} + + +/* + * Save 1541 state to snapshot + * + * 0: Error + * 1: OK + * -1: Instruction not completed + */ + +int C64::Save1541State(FILE *f) +{ + MOS6502State state; + TheCPU1541->GetState(&state); + + if (!state.idle && !state.instruction_complete) + return -1; + + int i = fwrite(RAM1541, 0x800, 1, f); + i += fwrite((void*)&state, sizeof(state), 1, f); + + return i == 2; +} + + +/* + * Load 1541 state from snapshot + */ + +bool C64::Load1541State(FILE *f) +{ + MOS6502State state; + + int i = fread(RAM1541, 0x800, 1, f); + i += fread((void*)&state, sizeof(state), 1, f); + + if (i == 2) { + TheCPU1541->SetState(&state); + return true; + } else + return false; +} + + +/* + * Save VIC state to snapshot + */ + +bool C64::SaveVICState(FILE *f) +{ + MOS6569State state; + TheVIC->GetState(&state); + return fwrite((void*)&state, sizeof(state), 1, f) == 1; +} + + +/* + * Load VIC state from snapshot + */ + +bool C64::LoadVICState(FILE *f) +{ + MOS6569State state; + + if (fread((void*)&state, sizeof(state), 1, f) == 1) { + TheVIC->SetState(&state); + return true; + } else + return false; +} + + +/* + * Save SID state to snapshot + */ + +bool C64::SaveSIDState(FILE *f) +{ + MOS6581State state; + TheSID->GetState(&state); + return fwrite((void*)&state, sizeof(state), 1, f) == 1; +} + + +/* + * Load SID state from snapshot + */ + +bool C64::LoadSIDState(FILE *f) +{ + MOS6581State state; + + if (fread((void*)&state, sizeof(state), 1, f) == 1) { + TheSID->SetState(&state); + return true; + } else + return false; +} + + +/* + * Save CIA states to snapshot + */ + +bool C64::SaveCIAState(FILE *f) +{ + MOS6526State state; + TheCIA1->GetState(&state); + + if (fwrite((void*)&state, sizeof(state), 1, f) == 1) { + TheCIA2->GetState(&state); + return fwrite((void*)&state, sizeof(state), 1, f) == 1; + } else + return false; +} + + +/* + * Load CIA states from snapshot + */ + +bool C64::LoadCIAState(FILE *f) +{ + MOS6526State state; + + if (fread((void*)&state, sizeof(state), 1, f) == 1) { + TheCIA1->SetState(&state); + if (fread((void*)&state, sizeof(state), 1, f) == 1) { + TheCIA2->SetState(&state); + return true; + } else + return false; + } else + return false; +} + + +/* + * Save 1541 GCR state to snapshot + */ + +bool C64::Save1541JobState(FILE *f) +{ + Job1541State state; + TheJob1541->GetState(&state); + return fwrite((void*)&state, sizeof(state), 1, f) == 1; +} + + +/* + * Load 1541 GCR state from snapshot + */ + +bool C64::Load1541JobState(FILE *f) +{ + Job1541State state; + + if (fread((void*)&state, sizeof(state), 1, f) == 1) { + TheJob1541->SetState(&state); + return true; + } else + return false; +} + + +#define SNAPSHOT_HEADER "FrodoSnapshot" +#define SNAPSHOT_1541 1 + +#define ADVANCE_CYCLES \ + TheVIC->EmulateCycle(); \ + TheCIA1->EmulateCycle(); \ + TheCIA2->EmulateCycle(); \ + TheCPU->EmulateCycle(); \ + if (ThePrefs.Emul1541Proc) { \ + TheCPU1541->CountVIATimers(1); \ + if (!TheCPU1541->Idle) \ + TheCPU1541->EmulateCycle(); \ + } + + +/* + * Save snapshot (emulation must be paused and in VBlank) + * + * To be able to use SC snapshots with SL, SC snapshots are made thus that no + * partially dealt with instructions are saved. Instead all devices are advanced + * cycle by cycle until the current instruction has been finished. The number of + * cycles this takes is saved in the snapshot and will be reconstructed if the + * snapshot is loaded into FrodoSC again. + */ + +void C64::SaveSnapshot(const char *filename) +{ + FILE *f; + uint8 flags; + uint8 delay; + int stat; + + if ((f = fopen(filename, "wb")) == NULL) { + ShowRequester("Unable to open snapshot file", "OK", NULL); + return; + } + + fprintf(f, "%s%c", SNAPSHOT_HEADER, 10); + fputc(0, f); // Version number 0 + flags = 0; + if (ThePrefs.Emul1541Proc) + flags |= SNAPSHOT_1541; + fputc(flags, f); + SaveVICState(f); + SaveSIDState(f); + SaveCIAState(f); + +#ifdef FRODO_SC + delay = 0; + do { + if ((stat = SaveCPUState(f)) == -1) { // -1 -> Instruction not finished yet + ADVANCE_CYCLES; // Advance everything by one cycle + delay++; + } + } while (stat == -1); + fputc(delay, f); // Number of cycles the saved CPUC64 lags behind the previous chips +#else + SaveCPUState(f); + fputc(0, f); // No delay +#endif + + if (ThePrefs.Emul1541Proc) { + fwrite(ThePrefs.DrivePath[0], 256, 1, f); +#ifdef FRODO_SC + delay = 0; + do { + if ((stat = Save1541State(f)) == -1) { + ADVANCE_CYCLES; + delay++; + } + } while (stat == -1); + fputc(delay, f); +#else + Save1541State(f); + fputc(0, f); // No delay +#endif + Save1541JobState(f); + } + fclose(f); + +} + + +/* + * Load snapshot (emulation must be paused and in VBlank) + */ + +bool C64::LoadSnapshot(const char *filename) +{ + FILE *f; + + if ((f = fopen(filename, "rb")) != NULL) { + char Header[] = SNAPSHOT_HEADER; + char *b = Header, c = 0; + uint8 delay, i; + + // For some reason memcmp()/strcmp() and so forth utterly fail here. + while (*b > 32) { + if ((c = fgetc(f)) != *b++) { + b = NULL; + break; + } + } + if (b != NULL) { + uint8 flags; + bool error = false; +#ifndef FRODO_SC + long vicptr; // File offset of VIC data +#endif + + while (c != 10) + c = fgetc(f); // Shouldn't be necessary + if (fgetc(f) != 0) { + ShowRequester("Unknown snapshot format", "OK", NULL); + fclose(f); + return false; + } + flags = fgetc(f); +#ifndef FRODO_SC + vicptr = ftell(f); +#endif + + error |= !LoadVICState(f); + error |= !LoadSIDState(f); + error |= !LoadCIAState(f); + error |= !LoadCPUState(f); + + delay = fgetc(f); // Number of cycles the 6510 is ahead of the previous chips +#ifdef FRODO_SC + // Make the other chips "catch up" with the 6510 + for (i=0; iEmulateCycle(); + TheCIA1->EmulateCycle(); + TheCIA2->EmulateCycle(); + } +#endif + if ((flags & SNAPSHOT_1541) != 0) { + Prefs *prefs = new Prefs(ThePrefs); + + // First switch on emulation + error |= (fread(prefs->DrivePath[0], 256, 1, f) != 1); + prefs->Emul1541Proc = true; + NewPrefs(prefs); + ThePrefs = *prefs; + delete prefs; + + // Then read the context + error |= !Load1541State(f); + + delay = fgetc(f); // Number of cycles the 6502 is ahead of the previous chips +#ifdef FRODO_SC + // Make the other chips "catch up" with the 6502 + for (i=0; iEmulateCycle(); + TheCIA1->EmulateCycle(); + TheCIA2->EmulateCycle(); + TheCPU->EmulateCycle(); + } +#endif + Load1541JobState(f); + } else if (ThePrefs.Emul1541Proc) { // No emulation in snapshot, but currently active? + Prefs *prefs = new Prefs(ThePrefs); + prefs->Emul1541Proc = false; + NewPrefs(prefs); + ThePrefs = *prefs; + delete prefs; + } + +#ifndef FRODO_SC + fseek(f, vicptr, SEEK_SET); + LoadVICState(f); // Load VIC data twice in SL (is REALLY necessary sometimes!) +#endif + fclose(f); + + if (error) { + ShowRequester("Error reading snapshot file", "OK", NULL); + Reset(); + return false; + } else + return true; + } else { + fclose(f); + ShowRequester("Not a Frodo snapshot file", "OK", NULL); + return false; + } + } else { + ShowRequester("Can't open snapshot file", "OK", NULL); + return false; + } +} + +void C64::Pause(void) +{ + /* No pause when the network is running */ + if (this->network) + { + this->have_a_break = false; + return; + } + + this->have_a_break = true; + TheSID->PauseSound(); +} + +bool C64::IsPaused() +{ + return this->have_a_break; +} + + +void C64::Resume(void) +{ + this->have_a_break = false; + TheSID->ResumeSound(); + //SDL_FillRect(real_screen, NULL, 0); +} + +#include "C64_SDL.h" diff --git a/Src/C64_SDL.h b/Src/C64_SDL.h index 5558f20..ddf1c3c 100644 --- a/Src/C64_SDL.h +++ b/Src/C64_SDL.h @@ -303,8 +303,8 @@ void C64::VBlank(bool draw_frame) Gui::gui->runLogic(); - if (this->quit_thyself) - ThePrefs.Save(ThePrefs.PrefsPath); + //if (this->quit_thyself) + // ThePrefs.Save(ThePrefs.PrefsPath); #if defined(GEKKO) if (this->quit_thyself && Network::networking_started == true) SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); diff --git a/Src/Display.cpp b/Src/Display.cpp index 0288239..bcf7e45 100644 --- a/Src/Display.cpp +++ b/Src/Display.cpp @@ -1,1044 +1,1088 @@ -/* - * Display.cpp - C64 graphics display, emulator window handling - * - * Frodo (C) 1994-1997,2002-2005 Christian Bauer - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sysdeps.h" -#if defined(GEKKO) -# include -#endif - -#include "Display.h" -#include "Version.h" -#include "main.h" -#include "Prefs.h" -#include "C64.h" -#include "CIA.h" -#include "utils.hh" - -#include "gui/gui.hh" -#include "gui/status_bar.hh" -#include "gui/virtual_keyboard.hh" - -// LED states -enum { - LED_OFF, // LED off - LED_ON, // LED on (green) - LED_ERROR_ON, // LED blinking (red), currently on - LED_ERROR_OFF // LED blinking, currently off -}; - - -#define USE_PEPTO_COLORS 1 - -#ifdef USE_PEPTO_COLORS - -// C64 color palette -// Values based on measurements by Philip "Pepto" Timmermann -// (see http://www.pepto.de/projects/colorvic/) -const uint8 palette_red[16] = { - 0x00, 0xff, 0x86, 0x4c, 0x88, 0x35, 0x20, 0xcf, 0x88, 0x40, 0xcb, 0x34, 0x68, 0x8b, 0x68, 0xa1 -}; - -const uint8 palette_green[16] = { - 0x00, 0xff, 0x19, 0xc1, 0x17, 0xac, 0x07, 0xf2, 0x3e, 0x2a, 0x55, 0x34, 0x68, 0xff, 0x4a, 0xa1 -}; - -const uint8 palette_blue[16] = { - 0x00, 0xff, 0x01, 0xe3, 0xbd, 0x0a, 0xc0, 0x2d, 0x00, 0x00, 0x37, 0x34, 0x68, 0x59, 0xff, 0xa1 -}; - -#else - -// C64 color palette (traditional Frodo colors) -const uint8 palette_red[16] = { - 0x00, 0xff, 0x99, 0x00, 0xcc, 0x44, 0x11, 0xff, 0xaa, 0x66, 0xff, 0x40, 0x80, 0x66, 0x77, 0xc0 -}; - -const uint8 palette_green[16] = { - 0x00, 0xff, 0x00, 0xff, 0x00, 0xcc, 0x00, 0xdd, 0x55, 0x33, 0x66, 0x40, 0x80, 0xff, 0x77, 0xc0 -}; - -const uint8 palette_blue[16] = { - 0x00, 0xff, 0x00, 0xcc, 0xcc, 0x44, 0x99, 0x00, 0x00, 0x00, 0x66, 0x40, 0x80, 0x66, 0xff, 0xc0 -}; - -#endif - - -/* - * Update drive LED display (deferred until Update()) - */ - -void C64Display::UpdateLEDs(int l0, int l1, int l2, int l3) -{ - led_state[0] = l0; - led_state[1] = l1; - led_state[2] = l2; - led_state[3] = l3; -} - - -// Display surface -static Uint8 screen[DISPLAY_X * DISPLAY_Y]; -static Uint16 *screen_16; -static Uint32 *screen_32; -static int screen_bits_per_pixel; - -static SDL_Surface *sdl_screen; -SDL_Surface *real_screen = NULL; - -// Keyboard -static bool num_locked = false; - -// SDL joysticks -static SDL_Joystick *joy[2] = {NULL, NULL}; - -static Uint16 palette_16[PALETTE_SIZE]; -static Uint32 palette_32[PALETTE_SIZE]; -SDL_Color sdl_palette[PALETTE_SIZE]; - -/* - C64 keyboard matrix: - - Bit 7 6 5 4 3 2 1 0 - 0 CUD F5 F3 F1 F7 CLR RET DEL - 1 SHL E S Z 4 A W 3 - 2 X T F C 6 D R 5 - 3 V U H B 8 G Y 7 - 4 N O K M 0 J I 9 - 5 , @ : . - L P + - 6 / ^ = SHR HOM ; * � - 7 R/S Q C= SPC 2 CTL <- 1 -*/ - -#define MATRIX(a,b) (((a) << 3) | (b)) - - -/* - * Open window - */ - -int init_graphics(void) -{ - Uint32 rmask, gmask, bmask, amask; - const SDL_VideoInfo *info = SDL_GetVideoInfo(); - Uint32 flags = SDL_DOUBLEBUF; - - /* SDL interprets each pixel as a 32-bit number, so our masks must depend - on the endianness (byte order) of the machine */ -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; -#else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; -#endif - - // Open window - SDL_ShowCursor(SDL_DISABLE); - - SDL_FreeSurface(sdl_screen); - sdl_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, DISPLAY_X, DISPLAY_Y + 17, 8, - rmask, gmask, bmask, amask); - if (!sdl_screen) - { - fprintf(stderr, "Cannot allocate surface to draw on: %s\n", - SDL_GetError()); - exit(1); - } - if (ThePrefs.DisplayType == DISPTYPE_SCREEN) - flags |= SDL_FULLSCREEN; - screen_bits_per_pixel = info->vfmt->BitsPerPixel; - SDL_FreeSurface(real_screen); - real_screen = SDL_SetVideoMode(FULL_DISPLAY_X, FULL_DISPLAY_Y, screen_bits_per_pixel, - flags); - if (!real_screen) - { - fprintf(stderr, "\n\nCannot initialize video: %s\n", SDL_GetError()); - exit(1); - } - free(screen_16); - free(screen_32); - - switch (screen_bits_per_pixel) - { - case 8: - /* Default, no need to do anything further */ - break; - case 16: - /* Allocate a 16 bit screen */ - screen_16 = (Uint16*)calloc(real_screen->pitch * FULL_DISPLAY_Y, sizeof(Uint16) ); - break; - case 24: - case 32: - screen_32 = (Uint32*)calloc(real_screen->pitch * FULL_DISPLAY_Y, sizeof(Uint32) ); - break; - default: - printf("What is this???\n"); - break; - } - - return 1; -} - - -/* - * Display constructor - */ - -C64Display::C64Display(C64 *the_c64) : TheC64(the_c64) -{ - quit_requested = false; - speedometer_string[0] = 0; - networktraffic_string[0] = 0; - this->text_message_send = NULL; - - // Open window - SDL_WM_SetCaption(VERSION_STRING, "Frodo"); - // LEDs off - for (int i=0; i<4; i++) - led_state[i] = old_led_state[i] = LED_OFF; -} - - -/* - * Display destructor - */ - -C64Display::~C64Display() -{ - SDL_Quit(); -} - - -/* - * Prefs may have changed - */ - -void C64Display::NewPrefs(Prefs *prefs) -{ -} - - -/* - * Redraw bitmap - */ -void C64Display::Update_32(uint8 *src_pixels) -{ - const Uint16 src_pitch = DISPLAY_X; - const int x_border = (DISPLAY_X - FULL_DISPLAY_X / 2) / 2; - const int y_border = (DISPLAY_Y - FULL_DISPLAY_Y / 2) / 2; - Uint32 *dst_pixels = (Uint32*)real_screen->pixels; - const int dst_pitch = real_screen->pitch / sizeof(Uint32); - - /* Center, double size */ - for (int y = y_border; y < (FULL_DISPLAY_Y/2) + y_border; y++) - { - for (int x = x_border; x < (FULL_DISPLAY_X / 2 + x_border); x++) - { - int src_off = y * src_pitch + x; - int dst_off = ((y * 2 - y_border * 2) * dst_pitch + (x * 2 - x_border * 2)); - Uint32 v = palette_32[src_pixels[src_off]]; - - dst_pixels[ dst_off ] = v; - dst_pixels[ dst_off + 1 ] = v; - dst_pixels[ dst_off + dst_pitch ] = v; - dst_pixels[ dst_off + dst_pitch + 1] = v; - } - } -} - -void C64Display::Update_16(uint8 *src_pixels) -{ - const Uint16 src_pitch = DISPLAY_X; - const int x_border = (DISPLAY_X - FULL_DISPLAY_X / 2) / 2; - const int y_border = (DISPLAY_Y - FULL_DISPLAY_Y / 2) / 2; - Uint16 *dst_pixels = (Uint16*)real_screen->pixels; - const Uint16 dst_pitch = real_screen->pitch / sizeof(Uint16); - - /* Center, double size */ - for (int y = y_border; y < (FULL_DISPLAY_Y/2) + y_border; y++) - { - for (int x = x_border; x < (FULL_DISPLAY_X / 2 + x_border); x++) - { - int src_off = y * src_pitch + x; - int dst_off = ((y * 2 - y_border * 2) * dst_pitch + (x * 2 - x_border * 2)); - Uint16 v = palette_16[src_pixels[src_off]]; - - dst_pixels[ dst_off ] = v; - dst_pixels[ dst_off + 1 ] = v; - dst_pixels[ dst_off + dst_pitch ] = v; - dst_pixels[ dst_off + dst_pitch + 1] = v; - } - } -} - -void C64Display::Update_8(uint8 *src_pixels) -{ - const Uint16 src_pitch = DISPLAY_X; - const int x_border = (DISPLAY_X - FULL_DISPLAY_X / 2) / 2; - const int y_border = (DISPLAY_Y - FULL_DISPLAY_Y / 2) / 2; - Uint8 *dst_pixels = (Uint8*)real_screen->pixels; - const Uint16 dst_pitch = real_screen->pitch; - - /* Center, double size */ - for (int y = y_border; y < (FULL_DISPLAY_Y/2) + y_border; y++) - { - for (int x = x_border; x < (FULL_DISPLAY_X / 2 + x_border); x++) - { - int src_off = y * src_pitch + x; - int dst_off = (y * 2 - y_border * 2) * dst_pitch + (x * 2 - x_border * 2); - Uint8 v = src_pixels[src_off]; - - dst_pixels[ dst_off ] = v; - dst_pixels[ dst_off + 1 ] = v; - dst_pixels[ dst_off + dst_pitch ] = v; - dst_pixels[ dst_off + dst_pitch + 1] = v; - } - } -} - -void C64Display::Update_stretched(uint8 *src_pixels) -{ - SDL_Rect srcrect = {0, 0, DISPLAY_X, DISPLAY_Y}; - SDL_Rect dstrect = {0, 0, FULL_DISPLAY_X, FULL_DISPLAY_Y}; - Uint8 *dst_pixels = (Uint8*)sdl_screen->pixels; - const Uint16 src_pitch = DISPLAY_X; - - /* Draw 1-1 */ - for (int y = 0; y < DISPLAY_Y; y++) - { - for (int x = 0; x < DISPLAY_X; x++) - { - int src_off = y * src_pitch + x; - int dst_off = src_off; - Uint8 v = src_pixels[src_off]; - - dst_pixels[ dst_off ] = v; - } - } - - /* Stretch */ - SDL_SoftStretch(sdl_screen, &srcrect, real_screen, &dstrect); -} - -void C64Display::Update(uint8 *src_pixels) -{ - if (0) - this->Update_stretched(src_pixels); - else - { - switch (screen_bits_per_pixel) - { - case 8: - this->Update_8(src_pixels); break; - case 16: - this->Update_16(src_pixels); break; - case 24: - case 32: - default: - this->Update_32((Uint8*)src_pixels); break; - } - } - Gui::gui->draw(real_screen); - - SDL_Flip(real_screen); -} - -void C64Display::Update() -{ - this->Update((Uint8*)screen); -} - -SDL_Surface *C64Display::SurfaceFromC64Display() -{ - Uint32 rmask,gmask,bmask,amask; - SDL_Surface *out; - -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; -#else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; -#endif - - out = SDL_CreateRGBSurface(SDL_SWSURFACE, DISPLAY_X / 2, DISPLAY_Y / 2, 8, - rmask, gmask, bmask, amask); - if (!out) - return NULL; - - Uint8 *dst_pixels = (Uint8*)out->pixels; - const Uint16 src_pitch = DISPLAY_X; - - /* Draw 1-1 */ - for (int y = 0; y < DISPLAY_Y / 2; y++) - { - for (int x = 0; x < DISPLAY_X / 2; x++) - { - int src_off = (y * 2) * src_pitch + (x * 2); - int dst_off = y * out->pitch + x; - Uint8 v = screen[src_off]; - - dst_pixels[ dst_off ] = v; - } - } - SDL_SetColors(out, sdl_palette, 0, PALETTE_SIZE); - - return out; -} - -/* - * Draw string into surface using the C64 ROM font - */ - -/* - * Draw speedometer - */ - -void C64Display::Speedometer(int speed) -{ - static int delay = 0; - - if (delay >= 20) { - delay = 0; - sprintf(speedometer_string, "%d%%", speed); - } else - delay++; -} - -void C64Display::NetworkTrafficMeter(float kb_per_s, bool is_throttled) -{ - snprintf(this->networktraffic_string, sizeof(this->networktraffic_string), - "%6.2f KB/S%s", kb_per_s, is_throttled ? " THROTTLED" : ""); -} - -/* - * Return pointer to bitmap data - */ - -uint8 *C64Display::BitmapBase(void) -{ - return screen; -} - - -/* - * Return number of bytes per row - */ - -int C64Display::BitmapXMod(void) -{ - return DISPLAY_X; -} - -void C64Display::FakeKeyPress(int kc, uint8 *CIA_key_matrix, - uint8 *CIA_rev_matrix) -{ - // Clear matrices - for (int i = 0; i < 8; i ++) - { - CIA_key_matrix[i] = 0xFF; - CIA_rev_matrix[i] = 0xFF; - } - if (kc != -1) - this->UpdateKeyMatrix(kc, false, CIA_key_matrix, CIA_rev_matrix, - NULL); -} - -void C64Display::UpdateKeyMatrix(int c64_key, bool key_up, - uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick) -{ - bool shifted = c64_key & 0x80; - int c64_byte; - int c64_bit; - - c64_key &= ~0x80; - c64_byte = (c64_key >> 3) & 7; - c64_bit = c64_key & 7; - - // Handle joystick emulation - if (joystick && (c64_key & 0x40)) { - c64_key &= 0x1f; - if (key_up) - *joystick |= c64_key; - else - *joystick &= ~c64_key; - return; - } - - if (key_up) { - if (shifted) { - key_matrix[6] |= 0x10; - rev_matrix[4] |= 0x40; - } - key_matrix[c64_byte] |= (1 << c64_bit); - rev_matrix[c64_bit] |= (1 << c64_byte); - } else { - if (shifted) { - key_matrix[6] &= 0xef; - rev_matrix[4] &= 0xbf; - } - key_matrix[c64_byte] &= ~(1 << c64_bit); - rev_matrix[c64_bit] &= ~(1 << c64_byte); - } -} - -/* - * Poll the keyboard - */ - -void C64Display::TranslateKey(SDLKey key, bool key_up, uint8 *key_matrix, - uint8 *rev_matrix, uint8 *joystick) -{ - static bool shift_on = false; - int c64_key = -1; - - switch (key) { - case SDLK_a: c64_key = MATRIX(1,2); break; - case SDLK_b: c64_key = MATRIX(3,4); break; - case SDLK_c: c64_key = MATRIX(2,4); break; - case SDLK_d: c64_key = MATRIX(2,2); break; - case SDLK_e: c64_key = MATRIX(1,6); break; - case SDLK_f: c64_key = MATRIX(2,5); break; - case SDLK_g: c64_key = MATRIX(3,2); break; - case SDLK_h: c64_key = MATRIX(3,5); break; - case SDLK_i: c64_key = MATRIX(4,1); break; - case SDLK_j: c64_key = MATRIX(4,2); break; - case SDLK_k: c64_key = MATRIX(4,5); break; - case SDLK_l: c64_key = MATRIX(5,2); break; - case SDLK_m: c64_key = MATRIX(4,4); break; - case SDLK_n: c64_key = MATRIX(4,7); break; - case SDLK_o: c64_key = MATRIX(4,6); break; - case SDLK_p: c64_key = MATRIX(5,1); break; - case SDLK_q: c64_key = MATRIX(7,6); break; - case SDLK_r: c64_key = MATRIX(2,1); break; - case SDLK_s: c64_key = MATRIX(1,5); break; - case SDLK_t: c64_key = MATRIX(2,6); break; - case SDLK_u: c64_key = MATRIX(3,6); break; - case SDLK_v: c64_key = MATRIX(3,7); break; - case SDLK_w: c64_key = MATRIX(1,1); break; - case SDLK_x: c64_key = MATRIX(2,7); break; - case SDLK_y: c64_key = MATRIX(3,1); break; - case SDLK_z: c64_key = MATRIX(1,4); break; - - case SDLK_0: c64_key = MATRIX(4,3); break; - case SDLK_1: c64_key = MATRIX(7,0); break; - case SDLK_2: c64_key = MATRIX(7,3); break; - case SDLK_3: c64_key = MATRIX(1,0); break; - case SDLK_4: c64_key = MATRIX(1,3); break; - case SDLK_5: c64_key = MATRIX(2,0); break; - case SDLK_6: c64_key = MATRIX(2,3); break; - case SDLK_7: c64_key = MATRIX(3,0); break; - case SDLK_8: c64_key = MATRIX(3,3); break; - case SDLK_9: c64_key = MATRIX(4,0); break; - - case SDLK_SPACE: c64_key = MATRIX(7,4); break; - case SDLK_BACKQUOTE: c64_key = MATRIX(7,1); break; - case SDLK_BACKSLASH: c64_key = MATRIX(6,6); break; - case SDLK_COMMA: c64_key = MATRIX(5,7); break; - case SDLK_PERIOD: c64_key = MATRIX(5,4); break; - case SDLK_MINUS: c64_key = MATRIX(5,0); break; - case SDLK_EQUALS: c64_key = MATRIX(5,3); break; - case SDLK_LEFTBRACKET: c64_key = MATRIX(5,6); break; - case SDLK_RIGHTBRACKET: c64_key = MATRIX(6,1); break; - case SDLK_SEMICOLON: c64_key = MATRIX(5,5); break; - case SDLK_QUOTE: c64_key = MATRIX(6,2); break; - case SDLK_SLASH: c64_key = MATRIX(6,7); break; - - case SDLK_ESCAPE: c64_key = MATRIX(7,7); break; - case SDLK_RETURN: c64_key = MATRIX(0,1); break; - case SDLK_BACKSPACE: case SDLK_DELETE: c64_key = MATRIX(0,0); break; - case SDLK_INSERT: c64_key = MATRIX(6,3); break; - case SDLK_HOME: c64_key = MATRIX(6,3); break; - case SDLK_END: c64_key = MATRIX(6,0); break; - case SDLK_PAGEUP: c64_key = MATRIX(6,0); break; - case SDLK_PAGEDOWN: c64_key = MATRIX(6,5); break; - - case SDLK_LCTRL: c64_key = 0x10 | 0x40; break; - case SDLK_TAB: c64_key = MATRIX(7,2); break; - case SDLK_RCTRL: c64_key = MATRIX(7,5); break; - case SDLK_LSHIFT: c64_key = MATRIX(1,7); break; - case SDLK_RSHIFT: c64_key = MATRIX(6,4); break; - case SDLK_LALT: case SDLK_LMETA: c64_key = MATRIX(7,5); break; - case SDLK_RALT: case SDLK_RMETA: c64_key = MATRIX(7,5); break; - case SDLK_UP: - { - if (ThePrefs.CursorKeysForJoystick) - c64_key = 0x01 | 0x40; - else - c64_key = MATRIX(0,7) | 0x80; - break; - } - case SDLK_DOWN: - { - if (ThePrefs.CursorKeysForJoystick) - c64_key = 0x02 | 0x40; - else - c64_key = MATRIX(0,7); - break; - } - case SDLK_LEFT: - { - if (ThePrefs.CursorKeysForJoystick) - c64_key = 0x04 | 0x40; - else - c64_key = MATRIX(0,2) | 0x80; - break; - } - case SDLK_RIGHT: - { - if (ThePrefs.CursorKeysForJoystick) - c64_key = 0x08 | 0x40; - else - c64_key = MATRIX(0,2); - break; - } - case SDLK_F1: c64_key = MATRIX(0,4); break; - case SDLK_F2: c64_key = MATRIX(0,4) | 0x80; break; - case SDLK_F3: c64_key = MATRIX(0,5); break; - case SDLK_F4: c64_key = MATRIX(0,5) | 0x80; break; - case SDLK_F5: c64_key = MATRIX(0,6); break; - case SDLK_F6: c64_key = MATRIX(0,6) | 0x80; break; - case SDLK_F7: c64_key = MATRIX(0,3); break; - case SDLK_F8: c64_key = MATRIX(0,3) | 0x80; break; - - case SDLK_KP0: case SDLK_KP5: c64_key = 0x10 | 0x40; break; - case SDLK_KP1: c64_key = 0x06 | 0x40; break; - case SDLK_KP2: c64_key = 0x02 | 0x40; break; - case SDLK_KP3: c64_key = 0x0a | 0x40; break; - case SDLK_KP4: c64_key = 0x04 | 0x40; break; - case SDLK_KP6: c64_key = 0x08 | 0x40; break; - case SDLK_KP7: c64_key = 0x05 | 0x40; break; - case SDLK_KP8: c64_key = 0x01 | 0x40; break; - case SDLK_KP9: c64_key = 0x09 | 0x40; break; - - case SDLK_KP_DIVIDE: c64_key = MATRIX(6,7); break; - case SDLK_KP_ENTER: c64_key = MATRIX(0,1); break; - default: break; - } - - if (c64_key < 0) - return; - /* Ugly handling of shift. Sorry about that */ - if (!key_up && (c64_key == MATRIX(1,7) || c64_key == MATRIX(6,4))) - shift_on = true; - else if (c64_key == MATRIX(1,7) || c64_key == MATRIX(6,4)) - shift_on = false; - - this->UpdateKeyMatrix(c64_key, key_up, key_matrix, rev_matrix, joystick); -} - -const char *C64Display::GetTextMessage() -{ - const char *out = this->text_message_send; - - this->text_message_send = NULL; - - return out; -} - -class TypeNetworkMessageListener : public KeyboardListener -{ -public: - TypeNetworkMessageListener(const char **out) - { - this->out = out; - } - - virtual void stringCallback(const char *str) - { - *out = (const char *)xstrdup(str); - if (strlen(str) > 0) - Gui::gui->status_bar->queueMessage("Network message sent!"); - else - Gui::gui->status_bar->queueMessage("Not sending empty message"); - /* Remove thyself! */ - delete this; - } - -private: - const char **out; -}; - -void C64Display::TypeNetworkMessage(bool broadcast) -{ - TypeNetworkMessageListener *nl = new TypeNetworkMessageListener(&this->text_message_send); - - this->text_message_broadcast = broadcast; - Gui::gui->status_bar->queueMessage("Type message to send to peer"); - VirtualKeyboard::kbd->registerListener(nl); - VirtualKeyboard::kbd->activate(); -} - - -void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick) -{ - SDL_Event event; - while (SDL_PollEvent(&event)) { - Gui::gui->pushEvent(&event); - - /* Ignore keyboard input while the menu is active */ - if (Gui::gui->is_active || Gui::gui->kbd) - continue; - - switch (event.type) { - - // Key pressed - case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - - case SDLK_F10: // F10/ScrLk: Enter text (for network taunts) - case SDLK_SCROLLOCK: - if (TheC64->network_connection_type == CLIENT || - TheC64->network_connection_type == MASTER) - this->TypeNetworkMessage(); - break; - - case SDLK_F11: // F11: NMI (Restore) - TheC64->NMI(); - break; - - case SDLK_F12: // F12: Reset - TheC64->Reset(); - break; - - case SDLK_HOME: // Home: Pause and enter menu - Gui::gui->activate(); - break; - - case SDLK_KP_PLUS: // '+' on keypad: Increase SkipFrames - ThePrefs.SkipFrames++; - break; - - case SDLK_KP_MINUS: // '-' on keypad: Decrease SkipFrames - if (ThePrefs.SkipFrames > 1) - ThePrefs.SkipFrames--; - break; - - case SDLK_KP_MULTIPLY: // '*' on keypad: Toggle speed limiter - ThePrefs.LimitSpeed = !ThePrefs.LimitSpeed; - break; - - default: - TranslateKey(event.key.keysym.sym, false, key_matrix, rev_matrix, joystick); - break; - } - break; - - // Key released - case SDL_KEYUP: - TranslateKey(event.key.keysym.sym, true, key_matrix, rev_matrix, joystick); - break; - - // Quit Frodo - case SDL_QUIT: - quit_requested = true; - break; - } - } -#if defined(GEKKO) - if (SYS_ResetButtonDown() != 0) - quit_requested = true; -#endif -} - - -/* - * Check if NumLock is down (for switching the joystick keyboard emulation) - */ - -bool C64Display::NumLock(void) -{ - return num_locked; -} - - -/* - * Open/close joystick drivers given old and new state of - * joystick preferences - */ -void C64::open_joystick(int port) -{ - joy_minx[port] = joy_miny[port] = -32767; // Reset calibration - joy_maxx[port] = joy_maxy[port] = 32768; - joy[port] = SDL_JoystickOpen(port); - if (joy[port] == NULL) - fprintf(stderr, "Couldn't open joystick %d\n", port + 1); -} - -void C64::close_joystick(int port) -{ - if (joy[port]) { - SDL_JoystickClose(joy[port]); - joy[port] = NULL; - } -} - -/* The implementation principles are borrowed from UAE */ -uint8 C64::poll_joystick_axes(int port, bool *has_event) -{ - SDL_Joystick *js = joy[port]; - unsigned int i, axes; - uint8 out = 0xff; - - axes = SDL_JoystickNumAxes (js); - for (i = 0; i < axes; i++) { - int axis; - - if (ThePrefs.JoystickAxes[i] == JOY_NONE) - continue; - - axis = SDL_JoystickGetAxis (js, i); - - /* Assume horizontal */ - int *max_axis = &this->joy_maxx[port]; - int *min_axis = &this->joy_minx[port]; - uint8 neg_val = 0xfb; - uint8 pos_val = 0xf7; - event_t gui_neg_val = KEY_LEFT; - event_t gui_pos_val = KEY_RIGHT; - - if (ThePrefs.JoystickAxes[i] == JOY_VERT) - { - max_axis = &this->joy_maxy[port]; - min_axis = &this->joy_miny[port]; - neg_val = 0xfe; - pos_val = 0xfd; - gui_neg_val = KEY_UP; - gui_pos_val = KEY_DOWN; - } - - /* Dynamic joystick calibration */ - if (axis > *max_axis) - *max_axis = axis; - if (axis < *min_axis) - *min_axis = axis; - - /* Too small as of yet */ - if (*max_axis - *min_axis < 1000) - continue; - - if (axis < (*min_axis + (*max_axis - *min_axis)/3)) { - out &= neg_val; - Gui::gui->pushJoystickEvent(gui_neg_val); - *has_event = true; - } - else if (axis > (*min_axis + 2*(*max_axis - *min_axis)/3)) { - out &= pos_val; - Gui::gui->pushJoystickEvent(gui_pos_val); - *has_event = true; - } - } - - return out; -} - -uint8 C64::poll_joystick_hats(int port, bool *has_event) -{ - SDL_Joystick *js = joy[port]; - unsigned int i, hats; - uint8 out = 0xff; - - hats = SDL_JoystickNumHats(js); - for (i = 0; i < hats; i++) { - - Uint8 v = SDL_JoystickGetHat (js, i); - Uint8 up_mask = 0xfe; - Uint8 down_mask = 0xfd; - Uint8 left_mask = 0xfb; - Uint8 right_mask = 0xf7; - event_t up_ev = KEY_UP; - event_t down_ev = KEY_DOWN; - event_t left_ev = KEY_LEFT; - event_t right_ev = KEY_RIGHT; - - if (ThePrefs.MenuJoystickHats[i] == HAT_ROTATED_90) - { - up_mask = 0xf7; - down_mask = 0xfb; - left_mask = 0xfe; - right_mask = 0xfd; - up_ev = KEY_RIGHT; - down_ev = KEY_LEFT; - left_ev = KEY_UP; - right_ev = KEY_DOWN; - } - - if ((v & (SDL_HAT_UP | SDL_HAT_DOWN | SDL_HAT_LEFT | SDL_HAT_RIGHT)) == 0) - continue; - *has_event = true; - - if (v & SDL_HAT_UP) { - out &= up_mask; - Gui::gui->pushJoystickEvent(up_ev); - } - if (v & SDL_HAT_DOWN) { - out &= down_mask; - Gui::gui->pushJoystickEvent(down_ev); - } - if (v & SDL_HAT_LEFT) { - out &= left_mask; - Gui::gui->pushJoystickEvent(left_ev); - } - if (v & SDL_HAT_RIGHT) { - out &= right_mask; - Gui::gui->pushJoystickEvent(right_ev); - } - } - - return out; -} - -uint8 C64::poll_joystick_buttons(int port, uint8 *table, bool *has_event) -{ - SDL_Joystick *js = joy[port]; - uint8 out = 0xff; - int i; - - for (i = 0; i < SDL_JoystickNumButtons (js); i++) { - bool cur = SDL_JoystickGetButton (js, i) ? true : false; - int kc = ThePrefs.JoystickButtons[i]; - event_t ev = (event_t)ThePrefs.MenuJoystickButtons[i]; - - if (cur && ev != EVENT_NONE) - { - Gui::gui->pushJoystickEvent(ev); - *has_event = true; - } - if (kc == JOY_NONE) - continue; - - if (table[kc] == 0) - table[kc] = cur ? 2 : 1; - /* Special case for joysticks: Each button can be pressed multiple times */ - if ((kc & 0x40) && cur) - table[kc] = 2; - } - - return out; -} - -/* - * Poll joystick port, return CIA mask - */ -uint8 C64::poll_joystick(int port) -{ - bool has_event = false; - uint8 out = 0xff; - static uint8 last_table_ports[2][0xff]; - uint8 table_ports[2][0xff]; - uint8 *last_table = last_table_ports[port]; - uint8 *table = table_ports[port]; - - if (!joy[port]) - return out; - - memset(table, 0, 0xff); - - out &= this->poll_joystick_axes(port, &has_event); - out &= this->poll_joystick_hats(port, &has_event); - out &= this->poll_joystick_buttons(port, table, &has_event); - - if (!has_event) - Gui::gui->pushJoystickEvent(EVENT_NONE); - - /* No joystick input when the Gui is active */ - if (Gui::gui->is_active || Gui::gui->kbd) - return 0xff; - - /* Handle keyboard codes */ - for (int i = 0; i < 0x51; i++) - { - if (table[i] == 0) - continue; - if ( !(i & 0x40) && table[i] == last_table[i] ) - continue; - - TheDisplay->UpdateKeyMatrix(i, table[i] == 1, - TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &out); - } - - memcpy(last_table, table, 0xff); - - return out; -} - - -/* - * Allocate C64 colors - */ - -void C64Display::InitColors(uint8 *colors) -{ - for (int i=0; i<16; i++) { - sdl_palette[i].r = palette_red[i]; - sdl_palette[i].g = palette_green[i]; - sdl_palette[i].b = palette_blue[i]; - } - sdl_palette[fill_gray].r = sdl_palette[fill_gray].g = sdl_palette[fill_gray].b = 0xd0; - sdl_palette[shine_gray].r = sdl_palette[shine_gray].g = sdl_palette[shine_gray].b = 0xf0; - sdl_palette[shadow_gray].r = sdl_palette[shadow_gray].g = sdl_palette[shadow_gray].b = 0x80; - sdl_palette[red].r = 0xf0; - sdl_palette[red].g = sdl_palette[red].b = 0; - sdl_palette[green].g = 0xf0; - sdl_palette[green].r = sdl_palette[green].b = 0; - - if (real_screen->format->BitsPerPixel == 8) - SDL_SetColors(real_screen, sdl_palette, 0, PALETTE_SIZE); - for (int i = 0; i < PALETTE_SIZE; i++) { - int rs = real_screen->format->Rshift; - int gs = real_screen->format->Gshift; - int bs = real_screen->format->Bshift; - int rl = real_screen->format->Rloss; - int gl = real_screen->format->Gloss; - int bl = real_screen->format->Bloss; - int rm = real_screen->format->Rmask; - int gm = real_screen->format->Gmask; - int bm = real_screen->format->Bmask; - uint32 r = palette_red[i] & 0xff; - uint32 g = palette_green[i] & 0xff; - uint32 b = palette_blue[i] & 0xff; - - palette_16[i] = (((r >> rl) << rs) & rm) | (((g >> gl) << gs) & gm) | (((b >> bl) << bs) & bm); - palette_32[i] = (((r >> rl) << rs) & rm) | (((g >> gl) << gs) & gm) | (((b >> bl) << bs) & bm); - } - - for (int i=0; i<256; i++) - colors[i] = i & 0x0f; -} - - -/* - * Show a requester (error message) - */ - -long int ShowRequester(const char *a, const char *b, const char *) -{ - printf("%s: %s\n", a, b); - return 1; -} +/* + * Display.cpp - C64 graphics display, emulator window handling + * + * Frodo (C) 1994-1997,2002-2005 Christian Bauer + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#if defined(GEKKO) +# include +#endif + +#include "Display.h" +#include "Version.h" +#include "main.h" +#include "Prefs.h" +#include "C64.h" +#include "CIA.h" +#include "utils.hh" + +#include "gui/gui.hh" +#include "gui/status_bar.hh" +#include "gui/virtual_keyboard.hh" + +// LED states +enum { + LED_OFF, // LED off + LED_ON, // LED on (green) + LED_ERROR_ON, // LED blinking (red), currently on + LED_ERROR_OFF // LED blinking, currently off +}; + + +#define USE_PEPTO_COLORS 1 + +#ifdef USE_PEPTO_COLORS + +// C64 color palette +// Values based on measurements by Philip "Pepto" Timmermann +// (see http://www.pepto.de/projects/colorvic/) +const uint8 palette_red[16] = { + 0x00, 0xff, 0x86, 0x4c, 0x88, 0x35, 0x20, 0xcf, 0x88, 0x40, 0xcb, 0x34, 0x68, 0x8b, 0x68, 0xa1 +}; + +const uint8 palette_green[16] = { + 0x00, 0xff, 0x19, 0xc1, 0x17, 0xac, 0x07, 0xf2, 0x3e, 0x2a, 0x55, 0x34, 0x68, 0xff, 0x4a, 0xa1 +}; + +const uint8 palette_blue[16] = { + 0x00, 0xff, 0x01, 0xe3, 0xbd, 0x0a, 0xc0, 0x2d, 0x00, 0x00, 0x37, 0x34, 0x68, 0x59, 0xff, 0xa1 +}; + +#else + +// C64 color palette (traditional Frodo colors) +const uint8 palette_red[16] = { + 0x00, 0xff, 0x99, 0x00, 0xcc, 0x44, 0x11, 0xff, 0xaa, 0x66, 0xff, 0x40, 0x80, 0x66, 0x77, 0xc0 +}; + +const uint8 palette_green[16] = { + 0x00, 0xff, 0x00, 0xff, 0x00, 0xcc, 0x00, 0xdd, 0x55, 0x33, 0x66, 0x40, 0x80, 0xff, 0x77, 0xc0 +}; + +const uint8 palette_blue[16] = { + 0x00, 0xff, 0x00, 0xcc, 0xcc, 0x44, 0x99, 0x00, 0x00, 0x00, 0x66, 0x40, 0x80, 0x66, 0xff, 0xc0 +}; + +#endif + + +/* + * Update drive LED display (deferred until Update()) + */ + +void C64Display::UpdateLEDs(int l0, int l1, int l2, int l3) +{ + led_state[0] = l0; + led_state[1] = l1; + led_state[2] = l2; + led_state[3] = l3; +} + + +// Display surface +static Uint8 screen[DISPLAY_X * DISPLAY_Y]; +//static Uint16 *screen_16; +//static Uint32 *screen_32; +static int screen_bits_per_pixel; + +static SDL_Surface *sdl_screen; +SDL_Surface *real_screen = NULL; + +// Keyboard +static bool num_locked = false; + +// SDL joysticks +static SDL_Joystick *joy[2] = {NULL, NULL}; + +static Uint16 palette_16[PALETTE_SIZE]; +static Uint32 palette_32[PALETTE_SIZE]; +SDL_Color sdl_palette[PALETTE_SIZE]; + +/* + C64 keyboard matrix: + + Bit 7 6 5 4 3 2 1 0 + 0 CUD F5 F3 F1 F7 CLR RET DEL + 1 SHL E S Z 4 A W 3 + 2 X T F C 6 D R 5 + 3 V U H B 8 G Y 7 + 4 N O K M 0 J I 9 + 5 , @ : . - L P + + 6 / ^ = SHR HOM ; * � + 7 R/S Q C= SPC 2 CTL <- 1 +*/ + +#define MATRIX(a,b) (((a) << 3) | (b)) + + +/* + * Open window + */ + +int init_graphics(void) +{ + Uint32 rmask, gmask, bmask, amask; + const SDL_VideoInfo *info = SDL_GetVideoInfo(); + Uint32 flags = SDL_DOUBLEBUF; + + /* SDL interprets each pixel as a 32-bit number, so our masks must depend + on the endianness (byte order) of the machine */ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; +#else + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0xff000000; +#endif + + // Open window + SDL_ShowCursor(SDL_DISABLE); + + SDL_FreeSurface(sdl_screen); + //sdl_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, DISPLAY_X, DISPLAY_Y + 17, 8, rmask, gmask, bmask, amask); + screen_bits_per_pixel = info->vfmt->BitsPerPixel; + sdl_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, DISPLAY_X, DISPLAY_Y, screen_bits_per_pixel, rmask, gmask, bmask, amask); + + if (!sdl_screen) + { + fprintf(stderr, "Cannot allocate surface to draw on: %s\n", + SDL_GetError()); + exit(1); + } + + #ifndef WII_PORT + if (ThePrefs.DisplayType == DISPTYPE_SCREEN) + flags |= SDL_FULLSCREEN; + #endif + + screen_bits_per_pixel = info->vfmt->BitsPerPixel; + SDL_FreeSurface(real_screen); + real_screen = SDL_SetVideoMode(FULL_DISPLAY_X, FULL_DISPLAY_Y, screen_bits_per_pixel, + flags); + if (!real_screen) + { + fprintf(stderr, "\n\nCannot initialize video: %s\n", SDL_GetError()); + exit(1); + } + //this part of code seems useless + /* + free(screen_16); + free(screen_32); + + switch (screen_bits_per_pixel) + { + case 8: + + Default, no need to do anything further + break; + case 16: + Allocate a 16 bit screen + screen_16 = (Uint16*)calloc(real_screen->pitch * FULL_DISPLAY_Y, sizeof(Uint16) ); + break; + case 24: + case 32: + screen_32 = (Uint32*)calloc(real_screen->pitch * FULL_DISPLAY_Y, sizeof(Uint32) ); + break; + default: + printf("What is this???\n"); + break; + } + */ + + return 1; +} + + +/* + * Display constructor + */ + +C64Display::C64Display(C64 *the_c64) : TheC64(the_c64) +{ + quit_requested = false; + speedometer_string[0] = 0; + networktraffic_string[0] = 0; + this->text_message_send = NULL; + + // Open window + SDL_WM_SetCaption(VERSION_STRING, "Frodo"); + // LEDs off + for (int i=0; i<4; i++) + led_state[i] = old_led_state[i] = LED_OFF; +} + + +/* + * Display destructor + */ + +C64Display::~C64Display() +{ + SDL_Quit(); +} + + +/* + * Prefs may have changed + */ + +void C64Display::NewPrefs(Prefs *prefs) +{ +} + + +/* + * Redraw bitmap + */ +void C64Display::Update_32(uint8 *src_pixels) +{ + const Uint16 src_pitch = DISPLAY_X; + const int x_border = (DISPLAY_X - FULL_DISPLAY_X / 2) / 2; + const int y_border = (DISPLAY_Y - FULL_DISPLAY_Y / 2) / 2; + Uint32 *dst_pixels = (Uint32*)real_screen->pixels; + const int dst_pitch = real_screen->pitch / sizeof(Uint32); + + /* Center, double size */ + for (int y = y_border; y < (FULL_DISPLAY_Y/2) + y_border; y++) + { + for (int x = x_border; x < (FULL_DISPLAY_X / 2 + x_border); x++) + { + int src_off = y * src_pitch + x; + int dst_off = ((y * 2 - y_border * 2) * dst_pitch + (x * 2 - x_border * 2)); + Uint32 v = palette_32[src_pixels[src_off]]; + + dst_pixels[ dst_off ] = v; + dst_pixels[ dst_off + 1 ] = v; + dst_pixels[ dst_off + dst_pitch ] = v; + dst_pixels[ dst_off + dst_pitch + 1] = v; + } + } +} + +void C64Display::Update_16(uint8 *src_pixels) +{ + const Uint16 src_pitch = DISPLAY_X; + + #ifdef WII_PORT + + if (ThePrefs.DisplayType == DISPTYPE_WINDOW) + { + SDL_Rect srcrect = {0, 0, DISPLAY_X, DISPLAY_Y}; + SDL_Rect dstrect = {0, 8, FULL_DISPLAY_X, FULL_DISPLAY_Y-16}; + Uint16 *dst_pixels = (Uint16*)sdl_screen->pixels ; + const Uint16 src_pitch = DISPLAY_X; + const Uint16 dst_pitch = sdl_screen->pitch / sizeof(Uint16); + + /* Draw 1-1 */ + for (int y = 0; y < DISPLAY_Y; y++) + { + for (int x = 0; x < DISPLAY_X; x++) + { + int src_off = y * src_pitch + x; + int dst_off = y * dst_pitch + x; + Uint16 v = palette_16[src_pixels[src_off]]; + dst_pixels[ dst_off ] = v; + } + } + + /* Stretch */ + SDL_SoftStretch(sdl_screen, &srcrect, real_screen, &dstrect); + } + + else + + #endif + { + + const int x_border = (DISPLAY_X - FULL_DISPLAY_X / 2) / 2; + const int y_border = (DISPLAY_Y - FULL_DISPLAY_Y / 2) / 2; + Uint16 *dst_pixels = (Uint16*)real_screen->pixels; + const Uint16 dst_pitch = real_screen->pitch / sizeof(Uint16); + + /* Center, double size */ + for (int y = y_border; y < (FULL_DISPLAY_Y/2) + y_border; y++) + { + for (int x = x_border; x < (FULL_DISPLAY_X / 2 + x_border); x++) + { + int src_off = y * src_pitch + x; + int dst_off = ((y * 2 - y_border * 2) * dst_pitch + (x * 2 - x_border * 2)); + Uint16 v = palette_16[src_pixels[src_off]]; + + dst_pixels[ dst_off ] = v; + dst_pixels[ dst_off + 1 ] = v; + dst_pixels[ dst_off + dst_pitch ] = v; + dst_pixels[ dst_off + dst_pitch + 1] = v; + } + } + } + +} + +void C64Display::Update_8(uint8 *src_pixels) +{ + const Uint16 src_pitch = DISPLAY_X; + const int x_border = (DISPLAY_X - FULL_DISPLAY_X / 2) / 2; + const int y_border = (DISPLAY_Y - FULL_DISPLAY_Y / 2) / 2; + Uint8 *dst_pixels = (Uint8*)real_screen->pixels; + const Uint16 dst_pitch = real_screen->pitch; + + /* Center, double size */ + for (int y = y_border; y < (FULL_DISPLAY_Y/2) + y_border; y++) + { + for (int x = x_border; x < (FULL_DISPLAY_X / 2 + x_border); x++) + { + int src_off = y * src_pitch + x; + int dst_off = (y * 2 - y_border * 2) * dst_pitch + (x * 2 - x_border * 2); + Uint8 v = src_pixels[src_off]; + + dst_pixels[ dst_off ] = v; + dst_pixels[ dst_off + 1 ] = v; + dst_pixels[ dst_off + dst_pitch ] = v; + dst_pixels[ dst_off + dst_pitch + 1] = v; + } + } +} + +void C64Display::Update_stretched(uint8 *src_pixels) +{ + SDL_Rect srcrect = {0, 0, DISPLAY_X, DISPLAY_Y}; + SDL_Rect dstrect = {0, 0, FULL_DISPLAY_X, FULL_DISPLAY_Y}; + Uint8 *dst_pixels = (Uint8*)sdl_screen->pixels; + const Uint16 src_pitch = DISPLAY_X; + + /* Draw 1-1 */ + for (int y = 0; y < DISPLAY_Y; y++) + { + for (int x = 0; x < DISPLAY_X; x++) + { + int src_off = y * src_pitch + x; + int dst_off = src_off; + Uint8 v = src_pixels[src_off]; + + dst_pixels[ dst_off ] = v; + } + } + + /* Stretch */ + SDL_SoftStretch(sdl_screen, &srcrect, real_screen, &dstrect); +} + +void C64Display::Update(uint8 *src_pixels) +{ + if (0) + this->Update_stretched(src_pixels); + else + { + switch (screen_bits_per_pixel) + { + case 8: + this->Update_8(src_pixels); break; + case 16: + this->Update_16(src_pixels); break; + case 24: + case 32: + default: + this->Update_32((Uint8*)src_pixels); break; + } + } + Gui::gui->draw(real_screen); + + SDL_Flip(real_screen); +} + +void C64Display::Update() +{ + this->Update((Uint8*)screen); +} + +SDL_Surface *C64Display::SurfaceFromC64Display() +{ + Uint32 rmask,gmask,bmask,amask; + SDL_Surface *out; + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; +#else + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0xff000000; +#endif + + out = SDL_CreateRGBSurface(SDL_SWSURFACE, DISPLAY_X / 2, DISPLAY_Y / 2, 8, + rmask, gmask, bmask, amask); + if (!out) + return NULL; + + Uint8 *dst_pixels = (Uint8*)out->pixels; + const Uint16 src_pitch = DISPLAY_X; + + /* Draw 1-1 */ + for (int y = 0; y < DISPLAY_Y / 2; y++) + { + for (int x = 0; x < DISPLAY_X / 2; x++) + { + int src_off = (y * 2) * src_pitch + (x * 2); + int dst_off = y * out->pitch + x; + Uint8 v = screen[src_off]; + + dst_pixels[ dst_off ] = v; + } + } + SDL_SetColors(out, sdl_palette, 0, PALETTE_SIZE); + + return out; +} + +/* + * Draw string into surface using the C64 ROM font + */ + +/* + * Draw speedometer + */ + +void C64Display::Speedometer(int speed) +{ + static int delay = 0; + + if (delay >= 20) { + delay = 0; + sprintf(speedometer_string, "%d%%", speed); + } else + delay++; +} + +void C64Display::NetworkTrafficMeter(float kb_per_s, bool is_throttled) +{ + snprintf(this->networktraffic_string, sizeof(this->networktraffic_string), + "%6.2f KB/S%s", kb_per_s, is_throttled ? " THROTTLED" : ""); +} + +/* + * Return pointer to bitmap data + */ + +uint8 *C64Display::BitmapBase(void) +{ + return screen; +} + + +/* + * Return number of bytes per row + */ + +int C64Display::BitmapXMod(void) +{ + return DISPLAY_X; +} + +void C64Display::FakeKeyPress(int kc, uint8 *CIA_key_matrix, + uint8 *CIA_rev_matrix) +{ + // Clear matrices + for (int i = 0; i < 8; i ++) + { + CIA_key_matrix[i] = 0xFF; + CIA_rev_matrix[i] = 0xFF; + } + if (kc != -1) + this->UpdateKeyMatrix(kc, false, CIA_key_matrix, CIA_rev_matrix, + NULL); +} + +void C64Display::UpdateKeyMatrix(int c64_key, bool key_up, + uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick) +{ + bool shifted = c64_key & 0x80; + int c64_byte; + int c64_bit; + + c64_key &= ~0x80; + c64_byte = (c64_key >> 3) & 7; + c64_bit = c64_key & 7; + + // Handle joystick emulation + if (joystick && (c64_key & 0x40)) { + c64_key &= 0x1f; + if (key_up) + *joystick |= c64_key; + else + *joystick &= ~c64_key; + return; + } + + if (key_up) { + if (shifted) { + key_matrix[6] |= 0x10; + rev_matrix[4] |= 0x40; + } + key_matrix[c64_byte] |= (1 << c64_bit); + rev_matrix[c64_bit] |= (1 << c64_byte); + } else { + if (shifted) { + key_matrix[6] &= 0xef; + rev_matrix[4] &= 0xbf; + } + key_matrix[c64_byte] &= ~(1 << c64_bit); + rev_matrix[c64_bit] &= ~(1 << c64_byte); + } +} + +/* + * Poll the keyboard + */ + +void C64Display::TranslateKey(SDLKey key, bool key_up, uint8 *key_matrix, + uint8 *rev_matrix, uint8 *joystick) +{ + static bool shift_on = false; + int c64_key = -1; + + switch (key) { + case SDLK_a: c64_key = MATRIX(1,2); break; + case SDLK_b: c64_key = MATRIX(3,4); break; + case SDLK_c: c64_key = MATRIX(2,4); break; + case SDLK_d: c64_key = MATRIX(2,2); break; + case SDLK_e: c64_key = MATRIX(1,6); break; + case SDLK_f: c64_key = MATRIX(2,5); break; + case SDLK_g: c64_key = MATRIX(3,2); break; + case SDLK_h: c64_key = MATRIX(3,5); break; + case SDLK_i: c64_key = MATRIX(4,1); break; + case SDLK_j: c64_key = MATRIX(4,2); break; + case SDLK_k: c64_key = MATRIX(4,5); break; + case SDLK_l: c64_key = MATRIX(5,2); break; + case SDLK_m: c64_key = MATRIX(4,4); break; + case SDLK_n: c64_key = MATRIX(4,7); break; + case SDLK_o: c64_key = MATRIX(4,6); break; + case SDLK_p: c64_key = MATRIX(5,1); break; + case SDLK_q: c64_key = MATRIX(7,6); break; + case SDLK_r: c64_key = MATRIX(2,1); break; + case SDLK_s: c64_key = MATRIX(1,5); break; + case SDLK_t: c64_key = MATRIX(2,6); break; + case SDLK_u: c64_key = MATRIX(3,6); break; + case SDLK_v: c64_key = MATRIX(3,7); break; + case SDLK_w: c64_key = MATRIX(1,1); break; + case SDLK_x: c64_key = MATRIX(2,7); break; + case SDLK_y: c64_key = MATRIX(3,1); break; + case SDLK_z: c64_key = MATRIX(1,4); break; + + case SDLK_0: c64_key = MATRIX(4,3); break; + case SDLK_1: c64_key = MATRIX(7,0); break; + case SDLK_2: c64_key = MATRIX(7,3); break; + case SDLK_3: c64_key = MATRIX(1,0); break; + case SDLK_4: c64_key = MATRIX(1,3); break; + case SDLK_5: c64_key = MATRIX(2,0); break; + case SDLK_6: c64_key = MATRIX(2,3); break; + case SDLK_7: c64_key = MATRIX(3,0); break; + case SDLK_8: c64_key = MATRIX(3,3); break; + case SDLK_9: c64_key = MATRIX(4,0); break; + + case SDLK_SPACE: c64_key = MATRIX(7,4); break; + case SDLK_BACKQUOTE: c64_key = MATRIX(7,1); break; + case SDLK_BACKSLASH: c64_key = MATRIX(6,6); break; + case SDLK_COMMA: c64_key = MATRIX(5,7); break; + case SDLK_PERIOD: c64_key = MATRIX(5,4); break; + case SDLK_MINUS: c64_key = MATRIX(5,0); break; + case SDLK_EQUALS: c64_key = MATRIX(5,3); break; + case SDLK_LEFTBRACKET: c64_key = MATRIX(5,6); break; + case SDLK_RIGHTBRACKET: c64_key = MATRIX(6,1); break; + case SDLK_SEMICOLON: c64_key = MATRIX(5,5); break; + case SDLK_QUOTE: c64_key = MATRIX(6,2); break; + case SDLK_SLASH: c64_key = MATRIX(6,7); break; + + case SDLK_ESCAPE: c64_key = MATRIX(7,7); break; + case SDLK_RETURN: c64_key = MATRIX(0,1); break; + case SDLK_BACKSPACE: case SDLK_DELETE: c64_key = MATRIX(0,0); break; + case SDLK_INSERT: c64_key = MATRIX(6,3); break; + case SDLK_HOME: c64_key = MATRIX(6,3); break; + case SDLK_END: c64_key = MATRIX(6,0); break; + case SDLK_PAGEUP: c64_key = MATRIX(6,0); break; + case SDLK_PAGEDOWN: c64_key = MATRIX(6,5); break; + + case SDLK_LCTRL: c64_key = 0x10 | 0x40; break; + case SDLK_TAB: c64_key = MATRIX(7,2); break; + case SDLK_RCTRL: c64_key = MATRIX(7,5); break; + case SDLK_LSHIFT: c64_key = MATRIX(1,7); break; + case SDLK_RSHIFT: c64_key = MATRIX(6,4); break; + case SDLK_LALT: case SDLK_LMETA: c64_key = MATRIX(7,5); break; + case SDLK_RALT: case SDLK_RMETA: c64_key = MATRIX(7,5); break; + case SDLK_UP: + { + if (ThePrefs.CursorKeysForJoystick) + c64_key = 0x01 | 0x40; + else + c64_key = MATRIX(0,7) | 0x80; + break; + } + case SDLK_DOWN: + { + if (ThePrefs.CursorKeysForJoystick) + c64_key = 0x02 | 0x40; + else + c64_key = MATRIX(0,7); + break; + } + case SDLK_LEFT: + { + if (ThePrefs.CursorKeysForJoystick) + c64_key = 0x04 | 0x40; + else + c64_key = MATRIX(0,2) | 0x80; + break; + } + case SDLK_RIGHT: + { + if (ThePrefs.CursorKeysForJoystick) + c64_key = 0x08 | 0x40; + else + c64_key = MATRIX(0,2); + break; + } + case SDLK_F1: c64_key = MATRIX(0,4); break; + case SDLK_F2: c64_key = MATRIX(0,4) | 0x80; break; + case SDLK_F3: c64_key = MATRIX(0,5); break; + case SDLK_F4: c64_key = MATRIX(0,5) | 0x80; break; + case SDLK_F5: c64_key = MATRIX(0,6); break; + case SDLK_F6: c64_key = MATRIX(0,6) | 0x80; break; + case SDLK_F7: c64_key = MATRIX(0,3); break; + case SDLK_F8: c64_key = MATRIX(0,3) | 0x80; break; + + case SDLK_KP0: case SDLK_KP5: c64_key = 0x10 | 0x40; break; + case SDLK_KP1: c64_key = 0x06 | 0x40; break; + case SDLK_KP2: c64_key = 0x02 | 0x40; break; + case SDLK_KP3: c64_key = 0x0a | 0x40; break; + case SDLK_KP4: c64_key = 0x04 | 0x40; break; + case SDLK_KP6: c64_key = 0x08 | 0x40; break; + case SDLK_KP7: c64_key = 0x05 | 0x40; break; + case SDLK_KP8: c64_key = 0x01 | 0x40; break; + case SDLK_KP9: c64_key = 0x09 | 0x40; break; + + case SDLK_KP_DIVIDE: c64_key = MATRIX(6,7); break; + case SDLK_KP_ENTER: c64_key = MATRIX(0,1); break; + default: break; + } + + if (c64_key < 0) + return; + /* Ugly handling of shift. Sorry about that */ + if (!key_up && (c64_key == MATRIX(1,7) || c64_key == MATRIX(6,4))) + shift_on = true; + else if (c64_key == MATRIX(1,7) || c64_key == MATRIX(6,4)) + shift_on = false; + + this->UpdateKeyMatrix(c64_key, key_up, key_matrix, rev_matrix, joystick); +} + +const char *C64Display::GetTextMessage() +{ + const char *out = this->text_message_send; + + this->text_message_send = NULL; + + return out; +} + +class TypeNetworkMessageListener : public KeyboardListener +{ +public: + TypeNetworkMessageListener(const char **out) + { + this->out = out; + } + + virtual void stringCallback(const char *str) + { + *out = (const char *)xstrdup(str); + if (strlen(str) > 0) + Gui::gui->status_bar->queueMessage("Network message sent!"); + else + Gui::gui->status_bar->queueMessage("Not sending empty message"); + /* Remove thyself! */ + delete this; + } + +private: + const char **out; +}; + +void C64Display::TypeNetworkMessage(bool broadcast) +{ + TypeNetworkMessageListener *nl = new TypeNetworkMessageListener(&this->text_message_send); + + this->text_message_broadcast = broadcast; + Gui::gui->status_bar->queueMessage("Type message to send to peer"); + VirtualKeyboard::kbd->registerListener(nl); + VirtualKeyboard::kbd->activate(); +} + + +void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick) +{ + SDL_Event event; + while (SDL_PollEvent(&event)) { + Gui::gui->pushEvent(&event); + + /* Ignore keyboard input while the menu is active */ + if (Gui::gui->is_active || Gui::gui->kbd) + continue; + + switch (event.type) { + + // Key pressed + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + + case SDLK_F10: // F10/ScrLk: Enter text (for network taunts) + case SDLK_SCROLLOCK: + if (TheC64->network_connection_type == CLIENT || + TheC64->network_connection_type == MASTER) + this->TypeNetworkMessage(); + break; + + case SDLK_F11: // F11: NMI (Restore) + TheC64->NMI(); + break; + + case SDLK_F12: // F12: Reset + TheC64->Reset(); + break; + + case SDLK_HOME: // Home: Pause and enter menu + Gui::gui->activate(); + break; + + case SDLK_KP_PLUS: // '+' on keypad: Increase SkipFrames + ThePrefs.SkipFrames++; + break; + + case SDLK_KP_MINUS: // '-' on keypad: Decrease SkipFrames + if (ThePrefs.SkipFrames > 1) + ThePrefs.SkipFrames--; + break; + + case SDLK_KP_MULTIPLY: // '*' on keypad: Toggle speed limiter + ThePrefs.LimitSpeed = !ThePrefs.LimitSpeed; + break; + + default: + TranslateKey(event.key.keysym.sym, false, key_matrix, rev_matrix, joystick); + break; + } + break; + + // Key released + case SDL_KEYUP: + TranslateKey(event.key.keysym.sym, true, key_matrix, rev_matrix, joystick); + break; + + // Quit Frodo + case SDL_QUIT: + quit_requested = true; + break; + } + } +#if defined(GEKKO) + if (SYS_ResetButtonDown() != 0) + quit_requested = true; +#endif +} + + +/* + * Check if NumLock is down (for switching the joystick keyboard emulation) + */ + +bool C64Display::NumLock(void) +{ + return num_locked; +} + + +/* + * Open/close joystick drivers given old and new state of + * joystick preferences + */ +void C64::open_joystick(int port) +{ + joy_minx[port] = joy_miny[port] = -32767; // Reset calibration + joy_maxx[port] = joy_maxy[port] = 32768; + joy[port] = SDL_JoystickOpen(port); + if (joy[port] == NULL) + fprintf(stderr, "Couldn't open joystick %d\n", port + 1); +} + +void C64::close_joystick(int port) +{ + if (joy[port]) { + SDL_JoystickClose(joy[port]); + joy[port] = NULL; + } +} + +/* The implementation principles are borrowed from UAE */ +uint8 C64::poll_joystick_axes(int port, bool *has_event) +{ + SDL_Joystick *js = joy[port]; + unsigned int i, axes; + uint8 out = 0xff; + + axes = SDL_JoystickNumAxes (js); + for (i = 0; i < axes; i++) { + int axis; + + if (ThePrefs.JoystickAxes[i] == JOY_NONE) + continue; + + axis = SDL_JoystickGetAxis (js, i); + + /* Assume horizontal */ + int *max_axis = &this->joy_maxx[port]; + int *min_axis = &this->joy_minx[port]; + uint8 neg_val = 0xfb; + uint8 pos_val = 0xf7; + event_t gui_neg_val = KEY_LEFT; + event_t gui_pos_val = KEY_RIGHT; + + if (ThePrefs.JoystickAxes[i] == JOY_VERT) + { + max_axis = &this->joy_maxy[port]; + min_axis = &this->joy_miny[port]; + neg_val = 0xfe; + pos_val = 0xfd; + gui_neg_val = KEY_UP; + gui_pos_val = KEY_DOWN; + } + + /* Dynamic joystick calibration */ + if (axis > *max_axis) + *max_axis = axis; + if (axis < *min_axis) + *min_axis = axis; + + /* Too small as of yet */ + if (*max_axis - *min_axis < 1000) + continue; + + if (axis < (*min_axis + (*max_axis - *min_axis)/3)) { + out &= neg_val; + Gui::gui->pushJoystickEvent(gui_neg_val); + *has_event = true; + } + else if (axis > (*min_axis + 2*(*max_axis - *min_axis)/3)) { + out &= pos_val; + Gui::gui->pushJoystickEvent(gui_pos_val); + *has_event = true; + } + } + + return out; +} + +uint8 C64::poll_joystick_hats(int port, bool *has_event) +{ + SDL_Joystick *js = joy[port]; + unsigned int i, hats; + uint8 out = 0xff; + + hats = SDL_JoystickNumHats(js); + for (i = 0; i < hats; i++) { + + Uint8 v = SDL_JoystickGetHat (js, i); + Uint8 up_mask = 0xfe; + Uint8 down_mask = 0xfd; + Uint8 left_mask = 0xfb; + Uint8 right_mask = 0xf7; + event_t up_ev = KEY_UP; + event_t down_ev = KEY_DOWN; + event_t left_ev = KEY_LEFT; + event_t right_ev = KEY_RIGHT; + + if (ThePrefs.MenuJoystickHats[i] == HAT_ROTATED_90) + { + up_mask = 0xf7; + down_mask = 0xfb; + left_mask = 0xfe; + right_mask = 0xfd; + up_ev = KEY_RIGHT; + down_ev = KEY_LEFT; + left_ev = KEY_UP; + right_ev = KEY_DOWN; + } + + if ((v & (SDL_HAT_UP | SDL_HAT_DOWN | SDL_HAT_LEFT | SDL_HAT_RIGHT)) == 0) + continue; + *has_event = true; + + if (v & SDL_HAT_UP) { + out &= up_mask; + Gui::gui->pushJoystickEvent(up_ev); + } + if (v & SDL_HAT_DOWN) { + out &= down_mask; + Gui::gui->pushJoystickEvent(down_ev); + } + if (v & SDL_HAT_LEFT) { + out &= left_mask; + Gui::gui->pushJoystickEvent(left_ev); + } + if (v & SDL_HAT_RIGHT) { + out &= right_mask; + Gui::gui->pushJoystickEvent(right_ev); + } + } + + return out; +} + +uint8 C64::poll_joystick_buttons(int port, uint8 *table, bool *has_event) +{ + SDL_Joystick *js = joy[port]; + uint8 out = 0xff; + int i; + + for (i = 0; i < SDL_JoystickNumButtons (js); i++) { + bool cur = SDL_JoystickGetButton (js, i) ? true : false; + int kc = ThePrefs.JoystickButtons[i]; + event_t ev = (event_t)ThePrefs.MenuJoystickButtons[i]; + + if (cur && ev != EVENT_NONE) + { + Gui::gui->pushJoystickEvent(ev); + *has_event = true; + } + if (kc == JOY_NONE) + continue; + + if (table[kc] == 0) + table[kc] = cur ? 2 : 1; + /* Special case for joysticks: Each button can be pressed multiple times */ + if ((kc & 0x40) && cur) + table[kc] = 2; + } + + return out; +} + +/* + * Poll joystick port, return CIA mask + */ +uint8 C64::poll_joystick(int port) +{ + bool has_event = false; + uint8 out = 0xff; + static uint8 last_table_ports[2][0xff]; + uint8 table_ports[2][0xff]; + uint8 *last_table = last_table_ports[port]; + uint8 *table = table_ports[port]; + + if (!joy[port]) + return out; + + memset(table, 0, 0xff); + + out &= this->poll_joystick_axes(port, &has_event); + out &= this->poll_joystick_hats(port, &has_event); + out &= this->poll_joystick_buttons(port, table, &has_event); + + if (!has_event) + Gui::gui->pushJoystickEvent(EVENT_NONE); + + /* No joystick input when the Gui is active */ + if (Gui::gui->is_active || Gui::gui->kbd) + return 0xff; + + /* Handle keyboard codes */ + for (int i = 0; i < 0x51; i++) + { + if (table[i] == 0) + continue; + if ( !(i & 0x40) && table[i] == last_table[i] ) + continue; + + TheDisplay->UpdateKeyMatrix(i, table[i] == 1, + TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &out); + } + + memcpy(last_table, table, 0xff); + + return out; +} + + +/* + * Allocate C64 colors + */ + +void C64Display::InitColors(uint8 *colors) +{ + for (int i=0; i<16; i++) { + sdl_palette[i].r = palette_red[i]; + sdl_palette[i].g = palette_green[i]; + sdl_palette[i].b = palette_blue[i]; + } + sdl_palette[fill_gray].r = sdl_palette[fill_gray].g = sdl_palette[fill_gray].b = 0xd0; + sdl_palette[shine_gray].r = sdl_palette[shine_gray].g = sdl_palette[shine_gray].b = 0xf0; + sdl_palette[shadow_gray].r = sdl_palette[shadow_gray].g = sdl_palette[shadow_gray].b = 0x80; + sdl_palette[red].r = 0xf0; + sdl_palette[red].g = sdl_palette[red].b = 0; + sdl_palette[green].g = 0xf0; + sdl_palette[green].r = sdl_palette[green].b = 0; + + if (real_screen->format->BitsPerPixel == 8) + SDL_SetColors(real_screen, sdl_palette, 0, PALETTE_SIZE); + for (int i = 0; i < PALETTE_SIZE; i++) { + int rs = real_screen->format->Rshift; + int gs = real_screen->format->Gshift; + int bs = real_screen->format->Bshift; + int rl = real_screen->format->Rloss; + int gl = real_screen->format->Gloss; + int bl = real_screen->format->Bloss; + int rm = real_screen->format->Rmask; + int gm = real_screen->format->Gmask; + int bm = real_screen->format->Bmask; + uint32 r = palette_red[i] & 0xff; + uint32 g = palette_green[i] & 0xff; + uint32 b = palette_blue[i] & 0xff; + + palette_16[i] = (((r >> rl) << rs) & rm) | (((g >> gl) << gs) & gm) | (((b >> bl) << bs) & bm); + palette_32[i] = (((r >> rl) << rs) & rm) | (((g >> gl) << gs) & gm) | (((b >> bl) << bs) & bm); + } + + for (int i=0; i<256; i++) + colors[i] = i & 0x0f; +} + + +/* + * Show a requester (error message) + */ + +long int ShowRequester(const char *a, const char *b, const char *) +{ + printf("%s: %s\n", a, b); + return 1; +} diff --git a/Src/Prefs.cpp b/Src/Prefs.cpp index 9a98224..faba44a 100644 --- a/Src/Prefs.cpp +++ b/Src/Prefs.cpp @@ -1,629 +1,681 @@ -/* - * Prefs.cpp - Global preferences - * - * Frodo (C) 1994-1997,2002-2005 Christian Bauer - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include - -#include "sysdeps.h" - -#include "Prefs.h" -#include "Display.h" -#include "C64.h" -#include "main.h" -#include "gui/widget.hh" - - -// These are the active preferences -Prefs ThePrefs; - -// These are the preferences on disk -Prefs ThePrefsOnDisk; - -// These are the default preferences -Prefs TheDefaultPrefs; - -static void maybe_write(FILE *fp, bool do_write, const char *fmt, ...) -{ - va_list ap; - int r; - - if (!do_write) - return; - - va_start(ap, fmt); - r = vfprintf(fp, fmt, ap); - va_end(ap); -} - -/* - * Constructor: Set up preferences with defaults - */ - -Prefs::Prefs() -{ - NormalCycles = 63; - BadLineCycles = 23; - CIACycles = 63; - FloppyCycles = 64; - SkipFrames = 1; - LatencyMin = 80; - LatencyMax = 120; - LatencyAvg = 280; - ScalingNumerator = 2; - ScalingDenominator = 2; - -#if defined(GEKKO) - strcpy(BasePath, "/frodo/"); - strcpy(PrefsPath, "/frodo/frodorc"); -#else - strcpy(BasePath, ""); - strcpy(PrefsPath, "frodorc"); -#endif - - strcpy(DrivePath[0], "64prgs"); - strcpy(DrivePath[1], ""); - strcpy(DrivePath[2], ""); - strcpy(DrivePath[3], ""); - - strcpy(ViewPort, "Default"); - strcpy(DisplayMode, "Default"); - - SIDType = SIDTYPE_DIGITAL; - REUSize = REU_NONE; - DisplayType = DISPTYPE_WINDOW; - Joystick1Port = 0; /* Default to on */ - Joystick2Port = 1; - - SpritesOn = true; - SpriteCollisions = true; - JoystickSwap = false; - LimitSpeed = false; - FastReset = false; - CIAIRQHack = false; - MapSlash = true; - Emul1541Proc = false; - SIDFilters = true; - DoubleScan = true; - HideCursor = false; - DirectSound = true; - ExclusiveSound = false; - AutoPause = false; - PrefsAtStartup = false; - SystemMemory = false; - AlwaysCopy = false; - SystemKeys = true; - ShowLEDs = true; - - this->SetupJoystickDefaults(); - - this->MsPerFrame = SPEED_100; - this->NetworkKey = rand() % 0xffff; - this->NetworkAvatar = 0; - snprintf(this->NetworkName, 32, "Unset name"); - snprintf(this->NetworkServer, 64, "play.c64-network.org"); - this->NetworkPort = 46214; - this->NetworkRegion = REGION_UNKNOWN; - this->CursorKeysForJoystick = true; - - strcpy(this->Theme, "default"); -} - - -void Prefs::SetupJoystickDefaults() -{ - for (int i = 0; i < MAX_JOYSTICK_AXES; i++) - this->JoystickAxes[i] = JOY_NONE; - - for (int i = 0; i < MAX_JOYSTICK_HATS; i++) - { - this->JoystickHats[i] = HAT_PLAIN; - this->MenuJoystickHats[i] = HAT_PLAIN; - } - for (int i = 0; i < MAX_JOYSTICK_BUTTONS; i++) - { - this->JoystickButtons[i] = JOY_NONE; - this->MenuJoystickButtons[i] = EVENT_NONE; - } - - if (SDL_NumJoysticks() > 0) - { - const char *name = SDL_JoystickName(0); - - if (strncmp(name, "Wiimote", 7) == 0) - { - /* Wiimote/Classic hat */ - this->JoystickHats[0] = HAT_PLAIN; - this->MenuJoystickHats[0] = HAT_PLAIN; - - /* Nunchuk/classic analogue */ - this->JoystickAxes[0] = JOY_HORIZ; - this->JoystickAxes[1] = JOY_VERT; - this->JoystickAxes[2] = JOY_HORIZ; - this->JoystickAxes[3] = JOY_VERT; - - /* Wiimote 2, Nunchuk Z, classic a, b as fire */ - this->JoystickButtons[3] = 0x50; - this->JoystickButtons[7] = 0x50; - this->JoystickButtons[9] = 0x50; - this->JoystickButtons[10] = 0x50; - - this->MenuJoystickButtons[3] = KEY_SELECT; - this->MenuJoystickButtons[7] = KEY_SELECT; - this->MenuJoystickButtons[9] = KEY_SELECT; - this->MenuJoystickButtons[10] = KEY_SELECT; - - /* Wiimote +/- as page up, page down */ - this->MenuJoystickButtons[4] = KEY_PAGEDOWN; - this->MenuJoystickButtons[5] = KEY_PAGEUP; - this->MenuJoystickButtons[17] = KEY_PAGEDOWN; - this->MenuJoystickButtons[18] = KEY_PAGEUP; - - /* +/- as 1 and 2 */ - this->JoystickButtons[4] = (7 << 3) | 0; - this->JoystickButtons[5] = (7 << 3) | 3; - this->JoystickButtons[17] = (7 << 3) | 0; - this->JoystickButtons[18] = (7 << 3) | 3; - - /* Wiimote B, Nunchuk C, Classic Zr, Zl as space */ - this->JoystickButtons[1] = (7 << 3) | 4; - this->JoystickButtons[8] = (7 << 3) | 4; - this->JoystickButtons[15] = (7 << 3) | 4; - this->JoystickButtons[16] = (7 << 3) | 4; - - /* Wiimote A and Classic L as F1 */ - this->JoystickButtons[0] = (0 << 3) | 4; - this->JoystickButtons[13] = (0 << 3) | 4; - - /* Classic R as F3 */ - this->JoystickButtons[16] = (0 << 3) | 5; - - /* Wiimote 1 as R/S, classic X/Y */ - this->JoystickButtons[2] = (7 << 3) | 7; - this->JoystickButtons[11] = (7 << 3) | 7; - this->JoystickButtons[12] = (7 << 3) | 7; - - /* Wiimote 1, classic x, y as menu escape */ - this->MenuJoystickButtons[2] = KEY_ESCAPE; - this->MenuJoystickButtons[11] = KEY_ESCAPE; - this->MenuJoystickButtons[12] = KEY_ESCAPE; - - /* Wiimote, classic Home as enter menu */ - this->MenuJoystickButtons[6] = KEY_ENTER_MENU; - this->MenuJoystickButtons[19] = KEY_ENTER_MENU; - } - /* Saitek P380 */ - else if (strcmp(name, "Jess Tech Dual Analog Pad") == 0) - { - /* Pad */ - this->JoystickHats[0] = HAT_PLAIN; - this->MenuJoystickHats[0] = HAT_PLAIN; - - /* Analogue parts */ - this->JoystickAxes[0] = JOY_HORIZ; - this->JoystickAxes[1] = JOY_VERT; - this->JoystickAxes[2] = JOY_HORIZ; - this->JoystickAxes[3] = JOY_VERT; - - this->JoystickButtons[0] = (0 << 3) | 4; - this->JoystickButtons[1] = (0 << 3) | 5; - - /* Button 4 Fire */ - this->JoystickButtons[3] = 0x50; - this->MenuJoystickButtons[3] = KEY_SELECT; - - /* Upper left front button R/S */ - this->JoystickButtons[4] = (7 << 3) | 7; - /* Lower left front button space */ - this->JoystickButtons[5] = (7 << 3) | 4; - - /* Upper right 1, lower right 2 */ - this->JoystickButtons[6] = (7 << 3) | 0; - this->JoystickButtons[7] = (7 << 3) | 3; - - /* Start to enter the menu */ - this->MenuJoystickButtons[0] = KEY_PAGEDOWN; - this->MenuJoystickButtons[1] = KEY_PAGEUP; - this->MenuJoystickButtons[8] = KEY_ESCAPE; - this->MenuJoystickButtons[9] = KEY_ENTER_MENU; - } - - } -} - -/* - * Check if two Prefs structures are equal - */ - -bool Prefs::operator==(const Prefs &rhs) const -{ - for (int i = 0; i < MAX_JOYSTICK_AXES; i++) - { - if (this->JoystickAxes[i] != rhs.JoystickAxes[i]) - return false; - } - for (int i = 0; i < MAX_JOYSTICK_HATS; i++) - { - if (this->JoystickHats[i] != rhs.JoystickHats[i]) - return false; - if (this->MenuJoystickHats[i] != rhs.MenuJoystickHats[i]) - return false; - } - for (int i = 0; i < MAX_JOYSTICK_BUTTONS; i++) - { - if (this->JoystickButtons[i] != rhs.JoystickButtons[i]) - return false; - if (this->MenuJoystickButtons[i] != rhs.MenuJoystickButtons[i]) - return false; - } - - return (1 - && NormalCycles == rhs.NormalCycles - && BadLineCycles == rhs.BadLineCycles - && CIACycles == rhs.CIACycles - && FloppyCycles == rhs.FloppyCycles - && SkipFrames == rhs.SkipFrames - && LatencyMin == rhs.LatencyMin - && LatencyMax == rhs.LatencyMax - && LatencyAvg == rhs.LatencyAvg - && ScalingNumerator == rhs.ScalingNumerator - && ScalingDenominator == rhs.ScalingNumerator - && strcmp(DrivePath[0], rhs.DrivePath[0]) == 0 - && strcmp(DrivePath[1], rhs.DrivePath[1]) == 0 - && strcmp(DrivePath[2], rhs.DrivePath[2]) == 0 - && strcmp(DrivePath[3], rhs.DrivePath[3]) == 0 - && strcmp(ViewPort, rhs.ViewPort) == 0 - && strcmp(DisplayMode, rhs.DisplayMode) == 0 - && SIDType == rhs.SIDType - && REUSize == rhs.REUSize - && DisplayType == rhs.DisplayType - && SpritesOn == rhs.SpritesOn - && SpriteCollisions == rhs.SpriteCollisions - && Joystick1Port == rhs.Joystick1Port - && Joystick2Port == rhs.Joystick2Port - && JoystickSwap == rhs.JoystickSwap - && LimitSpeed == rhs.LimitSpeed - && FastReset == rhs.FastReset - && CIAIRQHack == rhs.CIAIRQHack - && MapSlash == rhs.MapSlash - && Emul1541Proc == rhs.Emul1541Proc - && SIDFilters == rhs.SIDFilters - && DoubleScan == rhs.DoubleScan - && HideCursor == rhs.HideCursor - && DirectSound == rhs.DirectSound - && ExclusiveSound == rhs.ExclusiveSound - && AutoPause == rhs.AutoPause - && PrefsAtStartup == rhs.PrefsAtStartup - && SystemMemory == rhs.SystemMemory - && AlwaysCopy == rhs.AlwaysCopy - && SystemKeys == rhs.SystemKeys - && ShowLEDs == rhs.ShowLEDs - && this->MsPerFrame == rhs.MsPerFrame - && this->NetworkKey == rhs.NetworkKey - && this->NetworkPort == rhs.NetworkPort - && this->NetworkRegion == rhs.NetworkRegion - && strcmp(this->NetworkServer, rhs.NetworkServer) == 0 - && strcmp(this->NetworkName, rhs.NetworkName) == 0 - && strcmp(this->Theme, rhs.Theme) == 0 - && this->NetworkAvatar == rhs.NetworkAvatar - && this->CursorKeysForJoystick == rhs.CursorKeysForJoystick - ); -} - -bool Prefs::operator!=(const Prefs &rhs) const -{ - return !operator==(rhs); -} - - -/* - * Check preferences for validity and correct if necessary - */ - -void Prefs::Check(void) -{ - if (SkipFrames <= 0) SkipFrames = 1; - - if (SIDType < SIDTYPE_NONE || SIDType > SIDTYPE_SIDCARD) - SIDType = SIDTYPE_NONE; - - if (REUSize < REU_NONE || REUSize > REU_512K) - REUSize = REU_NONE; - - if (DisplayType < DISPTYPE_WINDOW || DisplayType > DISPTYPE_SCREEN) - DisplayType = DISPTYPE_WINDOW; -} - - -/* - * Load preferences from file - */ - -void Prefs::Load(const char *filename) -{ - FILE *file; - char line[256], keyword[256], value[256]; - - if ((file = fopen(filename, "r")) != NULL) { - while(fgets(line, 255, file)) { - if (sscanf(line, "%s = %s\n", keyword, value) == 2) { - if (!strcmp(keyword, "NormalCycles")) - NormalCycles = atoi(value); - else if (!strcmp(keyword, "BadLineCycles")) - BadLineCycles = atoi(value); - else if (!strcmp(keyword, "CIACycles")) - CIACycles = atoi(value); - else if (!strcmp(keyword, "FloppyCycles")) - FloppyCycles = atoi(value); - else if (!strcmp(keyword, "SkipFrames")) - SkipFrames = atoi(value); - else if (!strcmp(keyword, "LatencyMin")) - LatencyMin = atoi(value); - else if (!strcmp(keyword, "LatencyMax")) - LatencyMax = atoi(value); - else if (!strcmp(keyword, "LatencyAvg")) - LatencyAvg = atoi(value); - else if (!strcmp(keyword, "ScalingNumerator")) - ScalingNumerator = atoi(value); - else if (!strcmp(keyword, "ScalingDenominator")) - ScalingDenominator = atoi(value); - else if (!strcmp(keyword, "DrivePath8")) - strcpy(DrivePath[0], value); - else if (!strcmp(keyword, "DrivePath9")) - strcpy(DrivePath[1], value); - else if (!strcmp(keyword, "DrivePath10")) - strcpy(DrivePath[2], value); - else if (!strcmp(keyword, "DrivePath11")) - strcpy(DrivePath[3], value); - else if (!strcmp(keyword, "ViewPort")) - strcpy(ViewPort, value); - else if (!strcmp(keyword, "DisplayMode")) - strcpy(DisplayMode, value); - else if (!strcmp(keyword, "SIDType")) - if (!strcmp(value, "DIGITAL")) - SIDType = SIDTYPE_DIGITAL; - else if (!strcmp(value, "SIDCARD")) - SIDType = SIDTYPE_SIDCARD; - else - SIDType = SIDTYPE_NONE; - else if (!strcmp(keyword, "REUSize")) { - if (!strcmp(value, "128K")) - REUSize = REU_128K; - else if (!strcmp(value, "256K")) - REUSize = REU_256K; - else if (!strcmp(value, "512K")) - REUSize = REU_512K; - else - REUSize = REU_NONE; - } else if (!strcmp(keyword, "DisplayType")) - DisplayType = strcmp(value, "SCREEN") ? DISPTYPE_WINDOW : DISPTYPE_SCREEN; - else if (!strcmp(keyword, "Joystick1Port")) - Joystick1Port = atoi(value); - else if (!strcmp(keyword, "Joystick2Port")) - Joystick2Port = atoi(value); - else if (!strcmp(keyword, "SpritesOn")) - SpritesOn = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "SpriteCollisions")) - SpriteCollisions = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "JoystickSwap")) - JoystickSwap = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "LimitSpeed")) - LimitSpeed = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "FastReset")) - FastReset = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "CIAIRQHack")) - CIAIRQHack = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "MapSlash")) - MapSlash = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "Emul1541Proc")) - Emul1541Proc = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "SIDFilters")) - SIDFilters = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "DoubleScan")) - DoubleScan = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "HideCursor")) - HideCursor = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "DirectSound")) - DirectSound = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "ExclusiveSound")) - ExclusiveSound = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "AutoPause")) - AutoPause = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "PrefsAtStartup")) - PrefsAtStartup = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "SystemMemory")) - SystemMemory = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "AlwaysCopy")) - AlwaysCopy = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "SystemKeys")) - SystemKeys = !strcmp(value, "TRUE"); - else if (!strcmp(keyword, "ShowLEDs")) - ShowLEDs = !strcmp(value, "TRUE"); - else if (!strncmp(keyword, "JoystickAxes", strlen("JoystickAxes"))) - { - int n = atoi(keyword + strlen("JoystickAxes")); - - if (n >= 0 && n < MAX_JOYSTICK_AXES) - this->JoystickAxes[n] = atoi(value); - } - else if (!strncmp(keyword, "JoystickHats", strlen("JoystickHats"))) - { - int n = atoi(keyword + strlen("JoystickHats")); - - if (n >= 0 && n < MAX_JOYSTICK_HATS) - this->JoystickHats[n] = atoi(value); - } - else if (!strncmp(keyword, "JoystickButtons", strlen("JoystickButtons"))) - { - int n = atoi(keyword + strlen("JoystickButtons")); - - if (n >= 0 && n < MAX_JOYSTICK_BUTTONS) - this->JoystickButtons[n] = atoi(value); - } - else if (!strncmp(keyword, "MenuJoystickHats", strlen("MenuJoystickHats"))) - { - int n = atoi(keyword + strlen("MenuJoystickHats")); - - if (n >= 0 && n < MAX_JOYSTICK_HATS) - this->MenuJoystickHats[n] = atoi(value); - } - else if (!strncmp(keyword, "MenuJoystickButtons", strlen("MenuJoystickButtons"))) - { - int n = atoi(keyword + strlen("MenuJoystickButtons")); - - if (n >= 0 && n < MAX_JOYSTICK_BUTTONS) - this->MenuJoystickButtons[n] = atoi(value); - } - else if (!strcmp(keyword, "MsPerFrame")) - MsPerFrame = atoi(value); - else if (!strcmp(keyword, "NetworkKey")) - NetworkKey = atoi(value); - else if (!strcmp(keyword, "NetworkName")) - strcpy(NetworkName, value); - else if (!strcmp(keyword, "NetworkServer")) - strcpy(NetworkServer, value); - else if (!strcmp(keyword, "NetworkPort")) - NetworkPort = atoi(value); - else if (!strcmp(keyword, "NetworkName")) - strcpy(NetworkName, value); - else if (!strcmp(keyword, "NetworkRegion")) - NetworkRegion = atoi(value); - else if (!strcmp(keyword, "NetworkAvatar")) - NetworkAvatar = atoi(value); - else if (!strcmp(keyword, "Theme")) - strcpy(Theme, value); - else if (!strcmp(keyword, "CursorKeysForJoystick")) - CursorKeysForJoystick = !strcmp(value, "TRUE"); - } - } - fclose(file); - } - Check(); - ThePrefsOnDisk = *this; -} - - -/* - * Save preferences to file - * true: success, false: error - */ - -bool Prefs::Save(const char *filename) -{ - FILE *file; - - Check(); - if ((file = fopen(filename, "w")) != NULL) { - maybe_write(file, NormalCycles != TheDefaultPrefs.NormalCycles, "NormalCycles = %d\n", NormalCycles); - maybe_write(file, BadLineCycles != TheDefaultPrefs.BadLineCycles, "BadLineCycles = %d\n", BadLineCycles); - maybe_write(file, CIACycles != TheDefaultPrefs.CIACycles, "CIACycles = %d\n", CIACycles); - maybe_write(file, FloppyCycles != TheDefaultPrefs.FloppyCycles, "FloppyCycles = %d\n", FloppyCycles); - maybe_write(file, SkipFrames != TheDefaultPrefs.SkipFrames, "SkipFrames = %d\n", SkipFrames); - maybe_write(file, LatencyMin != TheDefaultPrefs.LatencyMin, "LatencyMin = %d\n", LatencyMin); - maybe_write(file, LatencyMax != TheDefaultPrefs.LatencyMax, "LatencyMax = %d\n", LatencyMax); - maybe_write(file, LatencyAvg != TheDefaultPrefs.LatencyAvg, "LatencyAvg = %d\n", LatencyAvg); - maybe_write(file, ScalingNumerator != TheDefaultPrefs.ScalingNumerator, "ScalingNumerator = %d\n", ScalingNumerator); - maybe_write(file, ScalingDenominator != TheDefaultPrefs.ScalingDenominator, "ScalingDenominator = %d\n", ScalingDenominator); - for (int i=0; i<4; i++) { - maybe_write(file, strcmp(DrivePath[i], TheDefaultPrefs.DrivePath[i]) != 0, "DrivePath%d = %s\n", i+8, DrivePath[i]); - } - maybe_write(file, strcmp(ViewPort, TheDefaultPrefs.ViewPort) != 0, "ViewPort = %s\n", ViewPort); - maybe_write(file, strcmp(DisplayMode, TheDefaultPrefs.DisplayMode) != 0, "DisplayMode = %s\n", DisplayMode); - if (SIDType != TheDefaultPrefs.SIDType) - { - fprintf(file, "SIDType = "); - switch (SIDType) { - case SIDTYPE_NONE: - fprintf(file, "NONE\n"); - break; - case SIDTYPE_DIGITAL: - fprintf(file, "DIGITAL\n"); - break; - case SIDTYPE_SIDCARD: - fprintf(file, "SIDCARD\n"); - break; - } - } - if (REUSize != TheDefaultPrefs.REUSize) - { - fprintf(file, "REUSize = "); - switch (REUSize) { - case REU_NONE: - fprintf(file, "NONE\n"); - break; - case REU_128K: - fprintf(file, "128K\n"); - break; - case REU_256K: - fprintf(file, "256K\n"); - break; - case REU_512K: - fprintf(file, "512K\n"); - break; - }; - } - maybe_write(file, DisplayType != TheDefaultPrefs.DisplayType, "DisplayType = %s\n", DisplayType == DISPTYPE_WINDOW ? "WINDOW" : "SCREEN"); - maybe_write(file, Joystick1Port != TheDefaultPrefs.Joystick1Port, "Joystick1Port = %d\n", Joystick1Port); - maybe_write(file, Joystick2Port != TheDefaultPrefs.Joystick2Port, "Joystick1Port = %d\n", Joystick2Port); - maybe_write(file, SpritesOn != TheDefaultPrefs.SpritesOn, "SpritesOn = %s\n", SpritesOn ? "TRUE" : "FALSE"); - maybe_write(file, SpriteCollisions != TheDefaultPrefs.SpriteCollisions, "SpriteCollisions = %s\n", SpriteCollisions ? "TRUE" : "FALSE"); - maybe_write(file, JoystickSwap != TheDefaultPrefs.JoystickSwap, "JoystickSwap = %s\n", JoystickSwap ? "TRUE" : "FALSE"); - maybe_write(file, LimitSpeed != TheDefaultPrefs.LimitSpeed, "LimitSpeed = %s\n", LimitSpeed ? "TRUE" : "FALSE"); - maybe_write(file, FastReset != TheDefaultPrefs.FastReset, "FastReset = %s\n", FastReset ? "TRUE" : "FALSE"); - maybe_write(file, CIAIRQHack != TheDefaultPrefs.CIAIRQHack, "CIAIRQHack = %s\n", CIAIRQHack ? "TRUE" : "FALSE"); - maybe_write(file, MapSlash != TheDefaultPrefs.MapSlash, "MapSlash = %s\n", MapSlash ? "TRUE" : "FALSE"); - maybe_write(file, Emul1541Proc != TheDefaultPrefs.Emul1541Proc, "Emul1541Proc = %s\n", Emul1541Proc ? "TRUE" : "FALSE"); - maybe_write(file, SIDFilters != TheDefaultPrefs.SIDFilters, "SIDFilters = %s\n", SIDFilters ? "TRUE" : "FALSE"); - maybe_write(file, DoubleScan != TheDefaultPrefs.DoubleScan, "DoubleScan = %s\n", DoubleScan ? "TRUE" : "FALSE"); - maybe_write(file, HideCursor != TheDefaultPrefs.HideCursor, "HideCursor = %s\n", HideCursor ? "TRUE" : "FALSE"); - maybe_write(file, DirectSound != TheDefaultPrefs.DirectSound, "DirectSound = %s\n", DirectSound ? "TRUE" : "FALSE"); - maybe_write(file, ExclusiveSound != TheDefaultPrefs.ExclusiveSound, "ExclusiveSound = %s\n", ExclusiveSound ? "TRUE" : "FALSE"); - maybe_write(file, AutoPause != TheDefaultPrefs.AutoPause, "AutoPause = %s\n", AutoPause ? "TRUE" : "FALSE"); - maybe_write(file, PrefsAtStartup != TheDefaultPrefs.PrefsAtStartup, "PrefsAtStartup = %s\n", PrefsAtStartup ? "TRUE" : "FALSE"); - maybe_write(file, SystemMemory != TheDefaultPrefs.SystemMemory, "SystemMemory = %s\n", SystemMemory ? "TRUE" : "FALSE"); - maybe_write(file, AlwaysCopy != TheDefaultPrefs.AlwaysCopy, "AlwaysCopy = %s\n", AlwaysCopy ? "TRUE" : "FALSE"); - maybe_write(file, SystemKeys != TheDefaultPrefs.SystemKeys, "SystemKeys = %s\n", SystemKeys ? "TRUE" : "FALSE"); - maybe_write(file, ShowLEDs != TheDefaultPrefs.ShowLEDs, "ShowLEDs = %s\n", ShowLEDs ? "TRUE" : "FALSE"); - - for (int i = 0; i < MAX_JOYSTICK_AXES; i++) - maybe_write(file, JoystickAxes[i] != TheDefaultPrefs.JoystickAxes[i], "JoystickAxes%d = %d\n", i, JoystickAxes[i]); - for (int i = 0; i < MAX_JOYSTICK_HATS; i++) - { - maybe_write(file, JoystickHats[i] != TheDefaultPrefs.JoystickHats[i], "JoystickHats%d = %d\n", i, JoystickHats[i]); - maybe_write(file, MenuJoystickHats[i] != TheDefaultPrefs.MenuJoystickHats[i], "MenuJoystickHats%d = %d\n", i, MenuJoystickHats[i]); - } - for (int i = 0; i < MAX_JOYSTICK_BUTTONS; i++) - { - maybe_write(file, JoystickButtons[i] != TheDefaultPrefs.JoystickButtons[i], "JoystickButtons%d = %d\n", i, JoystickButtons[i]); - maybe_write(file, MenuJoystickButtons[i] != TheDefaultPrefs.MenuJoystickButtons[i], "MenuJoystickButtons%d = %d\n", i, MenuJoystickButtons[i]); - } - - maybe_write(file, MsPerFrame != TheDefaultPrefs.MsPerFrame, "MsPerFrame = %d\n", MsPerFrame); - maybe_write(file, NetworkKey != TheDefaultPrefs.NetworkKey, "NetworkKey = %d\n", NetworkKey); - maybe_write(file, NetworkAvatar != TheDefaultPrefs.NetworkAvatar, "NetworkAvatar = %d\n", NetworkAvatar); - maybe_write(file, strcmp(NetworkName, TheDefaultPrefs.NetworkName) != 0, "NetworkName = %s\n", NetworkName); - maybe_write(file, strcmp(NetworkServer, TheDefaultPrefs.NetworkServer) != 0, "NetworkServer = %s\n", NetworkServer); - maybe_write(file, NetworkPort != TheDefaultPrefs.NetworkPort, "NetworkPort = %d\n", NetworkPort); - maybe_write(file, NetworkRegion != TheDefaultPrefs.NetworkRegion, "NetworkRegion = %d\n", NetworkRegion); - maybe_write(file, strcmp(Theme, TheDefaultPrefs.Theme) != 0, "Theme = %s\n", Theme); - maybe_write(file, CursorKeysForJoystick != TheDefaultPrefs.CursorKeysForJoystick, "CursorKeysForJoystick = %s\n", CursorKeysForJoystick ? "TRUE" : "FALSE"); - fclose(file); - ThePrefsOnDisk = *this; - return true; - } - return false; -} +/* + * Prefs.cpp - Global preferences + * + * Frodo (C) 1994-1997,2002-2005 Christian Bauer + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#include "sysdeps.h" + +#include "Prefs.h" +#include "Display.h" +#include "C64.h" +#include "main.h" +#include "gui/widget.hh" + + +// These are the active preferences +Prefs ThePrefs; + +// These are the preferences on disk +Prefs ThePrefsOnDisk; + +// These are the default preferences +Prefs TheDefaultPrefs; + +static void maybe_write(FILE *fp, bool do_write, const char *fmt, ...) +{ + va_list ap; + int r; + + if (!do_write) + return; + + va_start(ap, fmt); + r = vfprintf(fp, fmt, ap); + va_end(ap); +} + +/* + * Constructor: Set up preferences with defaults + */ + +Prefs::Prefs() +{ + NormalCycles = 63; + BadLineCycles = 23; + CIACycles = 63; + FloppyCycles = 64; + SkipFrames = 1; + LatencyMin = 80; + LatencyMax = 120; + LatencyAvg = 280; + ScalingNumerator = 2; + ScalingDenominator = 2; + +#if defined(GEKKO) + strcpy(BasePath, "/frodo/"); + strcpy(PrefsPath, "/frodo/frodorc"); +#else + strcpy(BasePath, ""); + strcpy(PrefsPath, "frodorc"); +#endif + + strcpy(DrivePath[0], "64prgs"); + strcpy(DrivePath[1], ""); + strcpy(DrivePath[2], ""); + strcpy(DrivePath[3], ""); + + strcpy(ViewPort, "Default"); + strcpy(DisplayMode, "Default"); + + SIDType = SIDTYPE_DIGITAL; + REUSize = REU_NONE; + DisplayType = DISPTYPE_WINDOW; + Joystick1Port = 0; /* Default to on */ + Joystick2Port = 1; + + SpritesOn = true; + SpriteCollisions = true; + JoystickSwap = false; + LimitSpeed = false; + FastReset = false; + CIAIRQHack = false; + MapSlash = true; + Emul1541Proc = false; + SIDFilters = true; + DoubleScan = true; + HideCursor = false; + DirectSound = true; + ExclusiveSound = false; + AutoPause = false; + PrefsAtStartup = false; + SystemMemory = false; + AlwaysCopy = false; + SystemKeys = true; + ShowLEDs = true; + + this->SetupJoystickDefaults(); + + this->MsPerFrame = SPEED_100; + this->NetworkKey = rand() % 0xffff; + this->NetworkAvatar = 0; + snprintf(this->NetworkName, 32, "Unset name"); + snprintf(this->NetworkServer, 64, "play.c64-network.org"); + this->NetworkPort = 46214; + this->NetworkRegion = REGION_UNKNOWN; + this->CursorKeysForJoystick = true; + + strcpy(this->Theme, "DEFAULT"); +} + + +void Prefs::SetupJoystickDefaults() +{ + for (int i = 0; i < MAX_JOYSTICK_AXES; i++) + this->JoystickAxes[i] = JOY_NONE; + + for (int i = 0; i < MAX_JOYSTICK_HATS; i++) + { + this->JoystickHats[i] = HAT_PLAIN; + this->MenuJoystickHats[i] = HAT_PLAIN; + } + for (int i = 0; i < MAX_JOYSTICK_BUTTONS; i++) + { + this->JoystickButtons[i] = JOY_NONE; + this->MenuJoystickButtons[i] = EVENT_NONE; + } + + if (SDL_NumJoysticks() > 0) + { + const char *name = SDL_JoystickName(0); + + if (strncmp(name, "Wiimote", 7) == 0) + { + /* Wiimote/Classic hat */ + this->JoystickHats[0] = HAT_PLAIN; + this->MenuJoystickHats[0] = HAT_PLAIN; + + /* Nunchuk/classic analogue */ + this->JoystickAxes[0] = JOY_HORIZ; + this->JoystickAxes[1] = JOY_VERT; + this->JoystickAxes[2] = JOY_HORIZ; + this->JoystickAxes[3] = JOY_VERT; + + /* Wiimote 2, Nunchuk Z, classic a, b as fire */ + this->JoystickButtons[3] = 0x50; + this->JoystickButtons[7] = 0x50; + this->JoystickButtons[9] = 0x50; + this->JoystickButtons[10] = 0x50; + + this->MenuJoystickButtons[3] = KEY_SELECT; + this->MenuJoystickButtons[7] = KEY_SELECT; + this->MenuJoystickButtons[9] = KEY_SELECT; + this->MenuJoystickButtons[10] = KEY_SELECT; + + /* Wiimote +/- as page up, page down */ + this->MenuJoystickButtons[4] = KEY_PAGEDOWN; + this->MenuJoystickButtons[5] = KEY_PAGEUP; + this->MenuJoystickButtons[17] = KEY_PAGEDOWN; + this->MenuJoystickButtons[18] = KEY_PAGEUP; + + /* +/- as 1 and 2 */ + this->JoystickButtons[4] = (7 << 3) | 0; + this->JoystickButtons[5] = (7 << 3) | 3; + this->JoystickButtons[17] = (7 << 3) | 0; + this->JoystickButtons[18] = (7 << 3) | 3; + + /* Wiimote B, Nunchuk C, Classic Zr, Zl as space */ + this->JoystickButtons[1] = (7 << 3) | 4; + this->JoystickButtons[8] = (7 << 3) | 4; + this->JoystickButtons[15] = (7 << 3) | 4; + this->JoystickButtons[16] = (7 << 3) | 4; + + /* Wiimote A and Classic L as F1 */ + this->JoystickButtons[0] = (0 << 3) | 4; + this->JoystickButtons[13] = (0 << 3) | 4; + + /* Classic R as F3 */ + this->JoystickButtons[16] = (0 << 3) | 5; + + /* Wiimote 1 as R/S, classic X/Y */ + this->JoystickButtons[2] = (7 << 3) | 7; + this->JoystickButtons[11] = (7 << 3) | 7; + this->JoystickButtons[12] = (7 << 3) | 7; + + /* Wiimote 1, classic x, y as menu escape */ + this->MenuJoystickButtons[2] = KEY_ESCAPE; + this->MenuJoystickButtons[11] = KEY_ESCAPE; + this->MenuJoystickButtons[12] = KEY_ESCAPE; + + /* Wiimote, classic Home as enter menu */ + this->MenuJoystickButtons[6] = KEY_ENTER_MENU; + this->MenuJoystickButtons[19] = KEY_ENTER_MENU; + } + /* Saitek P380 */ + else if (strcmp(name, "Jess Tech Dual Analog Pad") == 0) + { + /* Pad */ + this->JoystickHats[0] = HAT_PLAIN; + this->MenuJoystickHats[0] = HAT_PLAIN; + + /* Analogue parts */ + this->JoystickAxes[0] = JOY_HORIZ; + this->JoystickAxes[1] = JOY_VERT; + this->JoystickAxes[2] = JOY_HORIZ; + this->JoystickAxes[3] = JOY_VERT; + + this->JoystickButtons[0] = (0 << 3) | 4; + this->JoystickButtons[1] = (0 << 3) | 5; + + /* Button 4 Fire */ + this->JoystickButtons[3] = 0x50; + this->MenuJoystickButtons[3] = KEY_SELECT; + + /* Upper left front button R/S */ + this->JoystickButtons[4] = (7 << 3) | 7; + /* Lower left front button space */ + this->JoystickButtons[5] = (7 << 3) | 4; + + /* Upper right 1, lower right 2 */ + this->JoystickButtons[6] = (7 << 3) | 0; + this->JoystickButtons[7] = (7 << 3) | 3; + + /* Start to enter the menu */ + this->MenuJoystickButtons[0] = KEY_PAGEDOWN; + this->MenuJoystickButtons[1] = KEY_PAGEUP; + this->MenuJoystickButtons[8] = KEY_ESCAPE; + this->MenuJoystickButtons[9] = KEY_ENTER_MENU; + } + + } +} + +/* + * Check if two Prefs structures are equal + */ + +bool Prefs::operator==(const Prefs &rhs) const +{ + for (int i = 0; i < MAX_JOYSTICK_AXES; i++) + { + if (this->JoystickAxes[i] != rhs.JoystickAxes[i]) + return false; + } + for (int i = 0; i < MAX_JOYSTICK_HATS; i++) + { + if (this->JoystickHats[i] != rhs.JoystickHats[i]) + return false; + if (this->MenuJoystickHats[i] != rhs.MenuJoystickHats[i]) + return false; + } + for (int i = 0; i < MAX_JOYSTICK_BUTTONS; i++) + { + if (this->JoystickButtons[i] != rhs.JoystickButtons[i]) + return false; + if (this->MenuJoystickButtons[i] != rhs.MenuJoystickButtons[i]) + return false; + } + + return (1 + && NormalCycles == rhs.NormalCycles + && BadLineCycles == rhs.BadLineCycles + && CIACycles == rhs.CIACycles + && FloppyCycles == rhs.FloppyCycles + && SkipFrames == rhs.SkipFrames + && LatencyMin == rhs.LatencyMin + && LatencyMax == rhs.LatencyMax + && LatencyAvg == rhs.LatencyAvg + && ScalingNumerator == rhs.ScalingNumerator + && ScalingDenominator == rhs.ScalingNumerator + && strcmp(DrivePath[0], rhs.DrivePath[0]) == 0 + && strcmp(DrivePath[1], rhs.DrivePath[1]) == 0 + && strcmp(DrivePath[2], rhs.DrivePath[2]) == 0 + && strcmp(DrivePath[3], rhs.DrivePath[3]) == 0 + && strcmp(ViewPort, rhs.ViewPort) == 0 + && strcmp(DisplayMode, rhs.DisplayMode) == 0 + && SIDType == rhs.SIDType + && REUSize == rhs.REUSize + && DisplayType == rhs.DisplayType + && SpritesOn == rhs.SpritesOn + && SpriteCollisions == rhs.SpriteCollisions + && Joystick1Port == rhs.Joystick1Port + && Joystick2Port == rhs.Joystick2Port + && JoystickSwap == rhs.JoystickSwap + && LimitSpeed == rhs.LimitSpeed + && FastReset == rhs.FastReset + && CIAIRQHack == rhs.CIAIRQHack + && MapSlash == rhs.MapSlash + && Emul1541Proc == rhs.Emul1541Proc + && SIDFilters == rhs.SIDFilters + && DoubleScan == rhs.DoubleScan + && HideCursor == rhs.HideCursor + && DirectSound == rhs.DirectSound + && ExclusiveSound == rhs.ExclusiveSound + && AutoPause == rhs.AutoPause + && PrefsAtStartup == rhs.PrefsAtStartup + && SystemMemory == rhs.SystemMemory + && AlwaysCopy == rhs.AlwaysCopy + && SystemKeys == rhs.SystemKeys + && ShowLEDs == rhs.ShowLEDs + && this->MsPerFrame == rhs.MsPerFrame + && this->NetworkKey == rhs.NetworkKey + && this->NetworkPort == rhs.NetworkPort + && this->NetworkRegion == rhs.NetworkRegion + && strcmp(this->NetworkServer, rhs.NetworkServer) == 0 + && strcmp(this->NetworkName, rhs.NetworkName) == 0 + && strcmp(this->Theme, rhs.Theme) == 0 + && this->NetworkAvatar == rhs.NetworkAvatar + && this->CursorKeysForJoystick == rhs.CursorKeysForJoystick + ); +} + +bool Prefs::operator!=(const Prefs &rhs) const +{ + return !operator==(rhs); +} + + +/* + * Check preferences for validity and correct if necessary + */ + +void Prefs::Check(void) +{ + if (SkipFrames <= 0) SkipFrames = 1; + + if (SIDType < SIDTYPE_NONE || SIDType > SIDTYPE_SIDCARD) + SIDType = SIDTYPE_NONE; + + if (REUSize < REU_NONE || REUSize > REU_512K) + REUSize = REU_NONE; + + if (DisplayType < DISPTYPE_WINDOW || DisplayType > DISPTYPE_SCREEN) + DisplayType = DISPTYPE_WINDOW; +} + +// Introduced to fix the file names with spaces +void search_name(char* line, char* value) +{ +char* ptrstr; +int length=0; + +if (!(ptrstr = strchr(line,'='))) return; + +ptrstr= ptrstr + 2; + +while (ptrstr [length] != '\n') length++; + +ptrstr [length] = '\0'; + +strncpy (value, ptrstr, length+1); + +} + +/* + * Load preferences from file + */ + +void Prefs::Load(const char *filename) +{ + FILE *file; + char line[256], keyword[256], value[256]; + + if ((file = fopen(filename, "r")) != NULL) { + while(fgets(line, 255, file)) { + // if the file name contains spaces sscanf cuts the name in DrivePath[8-11] + if (sscanf(line, "%s = %s\n", keyword, value) == 2) { + if (!strcmp(keyword, "NormalCycles")) + NormalCycles = atoi(value); + else if (!strcmp(keyword, "BadLineCycles")) + BadLineCycles = atoi(value); + else if (!strcmp(keyword, "CIACycles")) + CIACycles = atoi(value); + else if (!strcmp(keyword, "FloppyCycles")) + FloppyCycles = atoi(value); + else if (!strcmp(keyword, "SkipFrames")) + SkipFrames = atoi(value); + else if (!strcmp(keyword, "LatencyMin")) + LatencyMin = atoi(value); + else if (!strcmp(keyword, "LatencyMax")) + LatencyMax = atoi(value); + else if (!strcmp(keyword, "LatencyAvg")) + LatencyAvg = atoi(value); + else if (!strcmp(keyword, "ScalingNumerator")) + ScalingNumerator = atoi(value); + else if (!strcmp(keyword, "ScalingDenominator")) + ScalingDenominator = atoi(value); + //Work arround to fix the problem for files with spaces in the name + else if (!strcmp(keyword, "DrivePath8")) {search_name(line, value); + strcpy(DrivePath[0], value); } + else if (!strcmp(keyword, "DrivePath9")) { search_name(line, value); + strcpy(DrivePath[1], value);} + else if (!strcmp(keyword, "DrivePath10")) { search_name(line, value); + strcpy(DrivePath[2], value);} + else if (!strcmp(keyword, "DrivePath11")) { search_name(line, value); + strcpy(DrivePath[3], value);} + else if (!strcmp(keyword, "ViewPort")) + strcpy(ViewPort, value); + else if (!strcmp(keyword, "DisplayMode")) + strcpy(DisplayMode, value); + else if (!strcmp(keyword, "SIDType")) + if (!strcmp(value, "DIGITAL")) + SIDType = SIDTYPE_DIGITAL; + else if (!strcmp(value, "SIDCARD")) + SIDType = SIDTYPE_SIDCARD; + else + SIDType = SIDTYPE_NONE; + else if (!strcmp(keyword, "REUSize")) { + if (!strcmp(value, "128K")) + REUSize = REU_128K; + else if (!strcmp(value, "256K")) + REUSize = REU_256K; + else if (!strcmp(value, "512K")) + REUSize = REU_512K; + else + REUSize = REU_NONE; + } else if (!strcmp(keyword, "DisplayType")) + DisplayType = strcmp(value, "SCREEN") ? DISPTYPE_WINDOW : DISPTYPE_SCREEN; + else if (!strcmp(keyword, "Joystick1Port")) + Joystick1Port = atoi(value); + else if (!strcmp(keyword, "Joystick2Port")) + Joystick2Port = atoi(value); + else if (!strcmp(keyword, "SpritesOn")) + SpritesOn = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "SpriteCollisions")) + SpriteCollisions = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "JoystickSwap")) + JoystickSwap = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "LimitSpeed")) + LimitSpeed = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "FastReset")) + FastReset = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "CIAIRQHack")) + CIAIRQHack = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "MapSlash")) + MapSlash = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "Emul1541Proc")) + Emul1541Proc = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "SIDFilters")) + SIDFilters = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "DoubleScan")) + DoubleScan = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "HideCursor")) + HideCursor = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "DirectSound")) + DirectSound = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "ExclusiveSound")) + ExclusiveSound = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "AutoPause")) + AutoPause = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "PrefsAtStartup")) + PrefsAtStartup = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "SystemMemory")) + SystemMemory = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "AlwaysCopy")) + AlwaysCopy = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "SystemKeys")) + SystemKeys = !strcmp(value, "TRUE"); + else if (!strcmp(keyword, "ShowLEDs")) + ShowLEDs = !strcmp(value, "TRUE"); + else if (!strncmp(keyword, "JoystickAxes", strlen("JoystickAxes"))) + { + int n = atoi(keyword + strlen("JoystickAxes")); + + if (n >= 0 && n < MAX_JOYSTICK_AXES) + this->JoystickAxes[n] = atoi(value); + } + else if (!strncmp(keyword, "JoystickHats", strlen("JoystickHats"))) + { + int n = atoi(keyword + strlen("JoystickHats")); + + if (n >= 0 && n < MAX_JOYSTICK_HATS) + this->JoystickHats[n] = atoi(value); + } + else if (!strncmp(keyword, "JoystickButtons", strlen("JoystickButtons"))) + { + int n = atoi(keyword + strlen("JoystickButtons")); + + if (n >= 0 && n < MAX_JOYSTICK_BUTTONS) + this->JoystickButtons[n] = atoi(value); + } + else if (!strncmp(keyword, "MenuJoystickHats", strlen("MenuJoystickHats"))) + { + int n = atoi(keyword + strlen("MenuJoystickHats")); + + if (n >= 0 && n < MAX_JOYSTICK_HATS) + this->MenuJoystickHats[n] = atoi(value); + } + else if (!strncmp(keyword, "MenuJoystickButtons", strlen("MenuJoystickButtons"))) + { + int n = atoi(keyword + strlen("MenuJoystickButtons")); + + if (n >= 0 && n < MAX_JOYSTICK_BUTTONS) + this->MenuJoystickButtons[n] = atoi(value); + } + else if (!strcmp(keyword, "MsPerFrame")) + MsPerFrame = atoi(value); + else if (!strcmp(keyword, "NetworkKey")) + NetworkKey = atoi(value); + else if (!strcmp(keyword, "NetworkName")) + strcpy(NetworkName, value); + else if (!strcmp(keyword, "NetworkServer")) + strcpy(NetworkServer, value); + else if (!strcmp(keyword, "NetworkPort")) + NetworkPort = atoi(value); + else if (!strcmp(keyword, "NetworkName")) + strcpy(NetworkName, value); + else if (!strcmp(keyword, "NetworkRegion")) + NetworkRegion = atoi(value); + else if (!strcmp(keyword, "NetworkAvatar")) + NetworkAvatar = atoi(value); + else if (!strcmp(keyword, "Theme")) + strcpy(Theme, value); + else if (!strcmp(keyword, "CursorKeysForJoystick")) + CursorKeysForJoystick = !strcmp(value, "TRUE"); + } + } + fclose(file); + } + Check(); + ThePrefsOnDisk = *this; +} + + +/* + * Save preferences to file + * true: success, false: error + */ + +bool Prefs::Save(const char *filename) +{ + FILE *file; + + Check(); + if ((file = fopen(filename, "w")) != NULL) { + maybe_write(file, NormalCycles != TheDefaultPrefs.NormalCycles, "NormalCycles = %d\n", NormalCycles); + maybe_write(file, BadLineCycles != TheDefaultPrefs.BadLineCycles, "BadLineCycles = %d\n", BadLineCycles); + maybe_write(file, CIACycles != TheDefaultPrefs.CIACycles, "CIACycles = %d\n", CIACycles); + maybe_write(file, FloppyCycles != TheDefaultPrefs.FloppyCycles, "FloppyCycles = %d\n", FloppyCycles); + maybe_write(file, SkipFrames != TheDefaultPrefs.SkipFrames, "SkipFrames = %d\n", SkipFrames); + maybe_write(file, LatencyMin != TheDefaultPrefs.LatencyMin, "LatencyMin = %d\n", LatencyMin); + maybe_write(file, LatencyMax != TheDefaultPrefs.LatencyMax, "LatencyMax = %d\n", LatencyMax); + maybe_write(file, LatencyAvg != TheDefaultPrefs.LatencyAvg, "LatencyAvg = %d\n", LatencyAvg); + maybe_write(file, ScalingNumerator != TheDefaultPrefs.ScalingNumerator, "ScalingNumerator = %d\n", ScalingNumerator); + maybe_write(file, ScalingDenominator != TheDefaultPrefs.ScalingDenominator, "ScalingDenominator = %d\n", ScalingDenominator); + for (int i=0; i<4; i++) { + maybe_write(file, strcmp(DrivePath[i], TheDefaultPrefs.DrivePath[i]) != 0, "DrivePath%d = %s\n", i+8, DrivePath[i]); + } + maybe_write(file, strcmp(ViewPort, TheDefaultPrefs.ViewPort) != 0, "ViewPort = %s\n", ViewPort); + maybe_write(file, strcmp(DisplayMode, TheDefaultPrefs.DisplayMode) != 0, "DisplayMode = %s\n", DisplayMode); + if (SIDType != TheDefaultPrefs.SIDType) + { + fprintf(file, "SIDType = "); + switch (SIDType) { + case SIDTYPE_NONE: + fprintf(file, "NONE\n"); + break; + case SIDTYPE_DIGITAL: + fprintf(file, "DIGITAL\n"); + break; + case SIDTYPE_SIDCARD: + fprintf(file, "SIDCARD\n"); + break; + } + } + if (REUSize != TheDefaultPrefs.REUSize) + { + fprintf(file, "REUSize = "); + switch (REUSize) { + case REU_NONE: + fprintf(file, "NONE\n"); + break; + case REU_128K: + fprintf(file, "128K\n"); + break; + case REU_256K: + fprintf(file, "256K\n"); + break; + case REU_512K: + fprintf(file, "512K\n"); + break; + }; + } + maybe_write(file, DisplayType != TheDefaultPrefs.DisplayType, "DisplayType = %s\n", DisplayType == DISPTYPE_WINDOW ? "WINDOW" : "SCREEN"); + maybe_write(file, Joystick1Port != TheDefaultPrefs.Joystick1Port, "Joystick1Port = %d\n", Joystick1Port); + maybe_write(file, Joystick2Port != TheDefaultPrefs.Joystick2Port, "Joystick1Port = %d\n", Joystick2Port); + maybe_write(file, SpritesOn != TheDefaultPrefs.SpritesOn, "SpritesOn = %s\n", SpritesOn ? "TRUE" : "FALSE"); + maybe_write(file, SpriteCollisions != TheDefaultPrefs.SpriteCollisions, "SpriteCollisions = %s\n", SpriteCollisions ? "TRUE" : "FALSE"); + maybe_write(file, JoystickSwap != TheDefaultPrefs.JoystickSwap, "JoystickSwap = %s\n", JoystickSwap ? "TRUE" : "FALSE"); + maybe_write(file, LimitSpeed != TheDefaultPrefs.LimitSpeed, "LimitSpeed = %s\n", LimitSpeed ? "TRUE" : "FALSE"); + maybe_write(file, FastReset != TheDefaultPrefs.FastReset, "FastReset = %s\n", FastReset ? "TRUE" : "FALSE"); + maybe_write(file, CIAIRQHack != TheDefaultPrefs.CIAIRQHack, "CIAIRQHack = %s\n", CIAIRQHack ? "TRUE" : "FALSE"); + maybe_write(file, MapSlash != TheDefaultPrefs.MapSlash, "MapSlash = %s\n", MapSlash ? "TRUE" : "FALSE"); + maybe_write(file, Emul1541Proc != TheDefaultPrefs.Emul1541Proc, "Emul1541Proc = %s\n", Emul1541Proc ? "TRUE" : "FALSE"); + maybe_write(file, SIDFilters != TheDefaultPrefs.SIDFilters, "SIDFilters = %s\n", SIDFilters ? "TRUE" : "FALSE"); + maybe_write(file, DoubleScan != TheDefaultPrefs.DoubleScan, "DoubleScan = %s\n", DoubleScan ? "TRUE" : "FALSE"); + maybe_write(file, HideCursor != TheDefaultPrefs.HideCursor, "HideCursor = %s\n", HideCursor ? "TRUE" : "FALSE"); + maybe_write(file, DirectSound != TheDefaultPrefs.DirectSound, "DirectSound = %s\n", DirectSound ? "TRUE" : "FALSE"); + maybe_write(file, ExclusiveSound != TheDefaultPrefs.ExclusiveSound, "ExclusiveSound = %s\n", ExclusiveSound ? "TRUE" : "FALSE"); + maybe_write(file, AutoPause != TheDefaultPrefs.AutoPause, "AutoPause = %s\n", AutoPause ? "TRUE" : "FALSE"); + maybe_write(file, PrefsAtStartup != TheDefaultPrefs.PrefsAtStartup, "PrefsAtStartup = %s\n", PrefsAtStartup ? "TRUE" : "FALSE"); + maybe_write(file, SystemMemory != TheDefaultPrefs.SystemMemory, "SystemMemory = %s\n", SystemMemory ? "TRUE" : "FALSE"); + maybe_write(file, AlwaysCopy != TheDefaultPrefs.AlwaysCopy, "AlwaysCopy = %s\n", AlwaysCopy ? "TRUE" : "FALSE"); + maybe_write(file, SystemKeys != TheDefaultPrefs.SystemKeys, "SystemKeys = %s\n", SystemKeys ? "TRUE" : "FALSE"); + maybe_write(file, ShowLEDs != TheDefaultPrefs.ShowLEDs, "ShowLEDs = %s\n", ShowLEDs ? "TRUE" : "FALSE"); + + for (int i = 0; i < MAX_JOYSTICK_AXES; i++) + maybe_write(file, JoystickAxes[i] != TheDefaultPrefs.JoystickAxes[i], "JoystickAxes%d = %d\n", i, JoystickAxes[i]); + for (int i = 0; i < MAX_JOYSTICK_HATS; i++) + { + maybe_write(file, JoystickHats[i] != TheDefaultPrefs.JoystickHats[i], "JoystickHats%d = %d\n", i, JoystickHats[i]); + maybe_write(file, MenuJoystickHats[i] != TheDefaultPrefs.MenuJoystickHats[i], "MenuJoystickHats%d = %d\n", i, MenuJoystickHats[i]); + } + for (int i = 0; i < MAX_JOYSTICK_BUTTONS; i++) + { + maybe_write(file, JoystickButtons[i] != TheDefaultPrefs.JoystickButtons[i], "JoystickButtons%d = %d\n", i, JoystickButtons[i]); + maybe_write(file, MenuJoystickButtons[i] != TheDefaultPrefs.MenuJoystickButtons[i], "MenuJoystickButtons%d = %d\n", i, MenuJoystickButtons[i]); + } + + maybe_write(file, MsPerFrame != TheDefaultPrefs.MsPerFrame, "MsPerFrame = %d\n", MsPerFrame); + maybe_write(file, NetworkKey != TheDefaultPrefs.NetworkKey, "NetworkKey = %d\n", NetworkKey); + maybe_write(file, NetworkAvatar != TheDefaultPrefs.NetworkAvatar, "NetworkAvatar = %d\n", NetworkAvatar); + maybe_write(file, strcmp(NetworkName, TheDefaultPrefs.NetworkName) != 0, "NetworkName = %s\n", NetworkName); + maybe_write(file, strcmp(NetworkServer, TheDefaultPrefs.NetworkServer) != 0, "NetworkServer = %s\n", NetworkServer); + maybe_write(file, NetworkPort != TheDefaultPrefs.NetworkPort, "NetworkPort = %d\n", NetworkPort); + maybe_write(file, NetworkRegion != TheDefaultPrefs.NetworkRegion, "NetworkRegion = %d\n", NetworkRegion); + maybe_write(file, strcmp(Theme, TheDefaultPrefs.Theme) != 0, "Theme = %s\n", Theme); + maybe_write(file, CursorKeysForJoystick != TheDefaultPrefs.CursorKeysForJoystick, "CursorKeysForJoystick = %s\n", CursorKeysForJoystick ? "TRUE" : "FALSE"); + fclose(file); + ThePrefsOnDisk = *this; + return true; + } + return false; +} + +/* + * Save game preferences to file + * true: success, false: error + * Save only drivepath, displaytype, joystikswap, emule 1541, joystickbutton, cursorkeys for joystick + */ + + + +bool Prefs::Save_game(const char *filename) +{ + FILE *file; + + Check(); + if ((file = fopen(filename, "w")) != NULL) { + + for (int i=0; i<4; i++) + maybe_write(file, strcmp(DrivePath[i], TheDefaultPrefs.DrivePath[i]) != 0, "DrivePath%d = %s\n", i+8, DrivePath[i]); + + maybe_write(file, true, "DisplayType = %s\n", DisplayType == DISPTYPE_WINDOW ? "WINDOW" : "SCREEN"); + maybe_write(file, true, "JoystickSwap = %s\n", JoystickSwap ? "TRUE" : "FALSE"); + maybe_write(file, true, "Emul1541Proc = %s\n", Emul1541Proc ? "TRUE" : "FALSE"); + + for (int i = 0; i < MAX_JOYSTICK_BUTTONS; i++) + maybe_write(file, true, "JoystickButtons%d = %d\n", i, JoystickButtons[i]); + maybe_write(file, true, "CursorKeysForJoystick = %s\n", CursorKeysForJoystick ? "TRUE" : "FALSE"); + + fclose(file); + ThePrefsOnDisk = *this; + return true; + } + return false; +} diff --git a/Src/Prefs.h b/Src/Prefs.h index c1a618d..3d0fff9 100644 --- a/Src/Prefs.h +++ b/Src/Prefs.h @@ -1,189 +1,190 @@ -/* - * Prefs.h - Global preferences - * - * Frodo (C) 1994-1997,2002-2005 Christian Bauer - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _PREFS_H -#define _PREFS_H - -#define SPEED_95 30 -#define SPEED_100 25 -#define SPEED_110 18 - -#define MAX_JOYSTICK_AXES 16 -#define MAX_JOYSTICK_BUTTONS 32 -#define MAX_JOYSTICK_HATS 8 - -// SID types -enum { - SIDTYPE_NONE, // SID emulation off - SIDTYPE_DIGITAL, // Digital SID emulation - SIDTYPE_SIDCARD // SID card -}; - - -// REU sizes -enum { - REU_NONE, // No REU - REU_128K, // 128K - REU_256K, // 256K - REU_512K // 512K -}; - - -// Display types -enum { - DISPTYPE_WINDOW, // Window - DISPTYPE_SCREEN // Fullscreen -}; - -enum { - /* ASCII values before these */ - JOY_NONE = 0, - JOY_HORIZ = 256, - JOY_VERT = 258, - JOY_FIRE = 259, -}; - -enum { - HAT_PLAIN = 0, - HAT_ROTATED_90 = 1, - HAT_ROTATED_180 = 2, - HAT_ROTATED_270 = 2, -}; - -// Key bindings (WII) -enum { - WIIMOTE_UP, - WIIMOTE_DOWN, - WIIMOTE_LEFT, - WIIMOTE_RIGHT, - WIIMOTE_2, - WIIMOTE_1, - WIIMOTE_A, - WIIMOTE_B, - WIIMOTE_PLUS, - WIIMOTE_MINUS, - CLASSIC_UP, - CLASSIC_DOWN, - CLASSIC_LEFT, - CLASSIC_RIGHT, - CLASSIC_A, - CLASSIC_B, - CLASSIC_X, - CLASSIC_Y, - CLASSIC_L, - CLASSIC_R, - CLASSIC_ZR, - CLASSIC_ZL, - N_WIIMOTE_BINDINGS -}; - - - -// Preferences data -class Prefs { -public: - Prefs(); - bool ShowEditor(bool startup, char *prefs_name); - void Check(void); - void Load(const char *filename); - bool Save(const char *filename); - - bool operator==(const Prefs &rhs) const; - bool operator!=(const Prefs &rhs) const; - - void SetupJoystickDefaults(); - - char BasePath[256]; // Where theme data etc are found - char PrefsPath[256]; // Where the prefs will be stored - int NormalCycles; // Available CPU cycles in normal raster lines - int BadLineCycles; // Available CPU cycles in Bad Lines - int CIACycles; // CIA timer ticks per raster line - int FloppyCycles; // Available 1541 CPU cycles per line - int SkipFrames; // Draw every n-th frame - - char DrivePath[4][256]; // Path for drive 8..11 - - char ViewPort[256]; // Size of the C64 screen to display (Win32) - char DisplayMode[256]; // Video mode to use for full screen (Win32) - - int SIDType; // SID emulation type - int REUSize; // Size of REU - int DisplayType; // Display type (BeOS) - int Joystick1Port; // Port that joystick 1 is connected to (0 = no joystick, all other values are system dependant) - int Joystick2Port; // Port that joystick 2 is connected to - int LatencyMin; // Min msecs ahead of sound buffer (Win32) - int LatencyMax; // Max msecs ahead of sound buffer (Win32) - int LatencyAvg; // Averaging interval in msecs (Win32) - int ScalingNumerator; // Window scaling numerator (Win32) - int ScalingDenominator; // Window scaling denominator (Win32) - - bool SpritesOn; // Sprite display is on - bool SpriteCollisions; // Sprite collision detection is on - bool JoystickSwap; // Swap joysticks 1<->2 - bool LimitSpeed; // Limit speed to 100% - bool FastReset; // Skip RAM test on reset - bool CIAIRQHack; // Write to CIA ICR clears IRQ - bool MapSlash; // Map '/' in C64 filenames - bool Emul1541Proc; // Enable processor-level 1541 emulation - bool SIDFilters; // Emulate SID filters - bool DoubleScan; // Double scan lines (BeOS, if DisplayType == DISPTYPE_SCREEN) - bool JoystickGeekPort; // Enable GeekPort joystick adapter - bool HideCursor; // Hide mouse cursor when visible (Win32) - bool DirectSound; // Use direct sound (instead of wav) (Win32) - bool ExclusiveSound; // Use exclusive mode with direct sound (Win32) - bool AutoPause; // Auto pause when not foreground app (Win32) - bool PrefsAtStartup; // Show prefs dialog at startup (Win32) - bool SystemMemory; // Put view work surface in system mem (Win32) - bool AlwaysCopy; // Always use a work surface (Win32) - bool SystemKeys; // Enable system keys and menu keys (Win32) - bool ShowLEDs; // Show LEDs (Win32) - - uint32 MsPerFrame; - - int JoystickAxes[MAX_JOYSTICK_AXES]; - int JoystickHats[MAX_JOYSTICK_HATS]; - int JoystickButtons[MAX_JOYSTICK_BUTTONS]; - - int MenuJoystickHats[MAX_JOYSTICK_HATS]; - int MenuJoystickButtons[MAX_JOYSTICK_BUTTONS]; - - char NetworkName[32]; - char NetworkServer[64]; - int NetworkRegion; - int NetworkPort; - - int NetworkKey; - uint16 NetworkAvatar; - char Theme[128]; - - bool CursorKeysForJoystick; -}; - - -// These are the active preferences -extern Prefs ThePrefs; - -// Theses are the preferences on disk -extern Prefs ThePrefsOnDisk; - -// Theses are the default preferences -extern Prefs TheDefaultPrefs; - -#endif +/* + * Prefs.h - Global preferences + * + * Frodo (C) 1994-1997,2002-2005 Christian Bauer + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _PREFS_H +#define _PREFS_H + +#define SPEED_95 30 +#define SPEED_100 25 +#define SPEED_110 18 + +#define MAX_JOYSTICK_AXES 16 +#define MAX_JOYSTICK_BUTTONS 32 +#define MAX_JOYSTICK_HATS 8 + +// SID types +enum { + SIDTYPE_NONE, // SID emulation off + SIDTYPE_DIGITAL, // Digital SID emulation + SIDTYPE_SIDCARD // SID card +}; + + +// REU sizes +enum { + REU_NONE, // No REU + REU_128K, // 128K + REU_256K, // 256K + REU_512K // 512K +}; + + +// Display types +enum { + DISPTYPE_WINDOW, // Window + DISPTYPE_SCREEN // Fullscreen +}; + +enum { + /* ASCII values before these */ + JOY_NONE = 0, + JOY_HORIZ = 256, + JOY_VERT = 258, + JOY_FIRE = 259, +}; + +enum { + HAT_PLAIN = 0, + HAT_ROTATED_90 = 1, + HAT_ROTATED_180 = 2, + HAT_ROTATED_270 = 2, +}; + +// Key bindings (WII) +enum { + WIIMOTE_UP, + WIIMOTE_DOWN, + WIIMOTE_LEFT, + WIIMOTE_RIGHT, + WIIMOTE_2, + WIIMOTE_1, + WIIMOTE_A, + WIIMOTE_B, + WIIMOTE_PLUS, + WIIMOTE_MINUS, + CLASSIC_UP, + CLASSIC_DOWN, + CLASSIC_LEFT, + CLASSIC_RIGHT, + CLASSIC_A, + CLASSIC_B, + CLASSIC_X, + CLASSIC_Y, + CLASSIC_L, + CLASSIC_R, + CLASSIC_ZR, + CLASSIC_ZL, + N_WIIMOTE_BINDINGS +}; + + + +// Preferences data +class Prefs { +public: + Prefs(); + bool ShowEditor(bool startup, char *prefs_name); + void Check(void); + void Load(const char *filename); + bool Save(const char *filename); + bool Save_game(const char *filename); + + bool operator==(const Prefs &rhs) const; + bool operator!=(const Prefs &rhs) const; + + void SetupJoystickDefaults(); + + char BasePath[256]; // Where theme data etc are found + char PrefsPath[256]; // Where the prefs will be stored + int NormalCycles; // Available CPU cycles in normal raster lines + int BadLineCycles; // Available CPU cycles in Bad Lines + int CIACycles; // CIA timer ticks per raster line + int FloppyCycles; // Available 1541 CPU cycles per line + int SkipFrames; // Draw every n-th frame + + char DrivePath[4][256]; // Path for drive 8..11 + + char ViewPort[256]; // Size of the C64 screen to display (Win32) + char DisplayMode[256]; // Video mode to use for full screen (Win32) + + int SIDType; // SID emulation type + int REUSize; // Size of REU + int DisplayType; // Display type (BeOS) + int Joystick1Port; // Port that joystick 1 is connected to (0 = no joystick, all other values are system dependant) + int Joystick2Port; // Port that joystick 2 is connected to + int LatencyMin; // Min msecs ahead of sound buffer (Win32) + int LatencyMax; // Max msecs ahead of sound buffer (Win32) + int LatencyAvg; // Averaging interval in msecs (Win32) + int ScalingNumerator; // Window scaling numerator (Win32) + int ScalingDenominator; // Window scaling denominator (Win32) + + bool SpritesOn; // Sprite display is on + bool SpriteCollisions; // Sprite collision detection is on + bool JoystickSwap; // Swap joysticks 1<->2 + bool LimitSpeed; // Limit speed to 100% + bool FastReset; // Skip RAM test on reset + bool CIAIRQHack; // Write to CIA ICR clears IRQ + bool MapSlash; // Map '/' in C64 filenames + bool Emul1541Proc; // Enable processor-level 1541 emulation + bool SIDFilters; // Emulate SID filters + bool DoubleScan; // Double scan lines (BeOS, if DisplayType == DISPTYPE_SCREEN) + bool JoystickGeekPort; // Enable GeekPort joystick adapter + bool HideCursor; // Hide mouse cursor when visible (Win32) + bool DirectSound; // Use direct sound (instead of wav) (Win32) + bool ExclusiveSound; // Use exclusive mode with direct sound (Win32) + bool AutoPause; // Auto pause when not foreground app (Win32) + bool PrefsAtStartup; // Show prefs dialog at startup (Win32) + bool SystemMemory; // Put view work surface in system mem (Win32) + bool AlwaysCopy; // Always use a work surface (Win32) + bool SystemKeys; // Enable system keys and menu keys (Win32) + bool ShowLEDs; // Show LEDs (Win32) + + uint32 MsPerFrame; + + int JoystickAxes[MAX_JOYSTICK_AXES]; + int JoystickHats[MAX_JOYSTICK_HATS]; + int JoystickButtons[MAX_JOYSTICK_BUTTONS]; + + int MenuJoystickHats[MAX_JOYSTICK_HATS]; + int MenuJoystickButtons[MAX_JOYSTICK_BUTTONS]; + + char NetworkName[32]; + char NetworkServer[64]; + int NetworkRegion; + int NetworkPort; + + int NetworkKey; + uint16 NetworkAvatar; + char Theme[128]; + + bool CursorKeysForJoystick; +}; + + +// These are the active preferences +extern Prefs ThePrefs; + +// Theses are the preferences on disk +extern Prefs ThePrefsOnDisk; + +// Theses are the default preferences +extern Prefs TheDefaultPrefs; + +#endif diff --git a/Src/gui/bind_keys_menu.cpp b/Src/gui/bind_keys_menu.cpp index d69533f..28ebcfc 100644 --- a/Src/gui/bind_keys_menu.cpp +++ b/Src/gui/bind_keys_menu.cpp @@ -1,429 +1,429 @@ -#include "gui.hh" -#include "menu.hh" -#include "help_box.hh" -#include "dialogue_box.hh" -#include "virtual_keyboard.hh" - -class BindKeysMenu; - -class AnalogueBindListener : public DialogueListener -{ -public: - AnalogueBindListener(BindKeysMenu *menu) - { - this->menu = menu; - } - - void escapeCallback(DialogueBox *which, int selected) - { - delete this; - } - - void selectCallback(DialogueBox *which, int selected); - -private: - BindKeysMenu *menu; -}; - -class BindKeysView; -class BindKeysMenu : public Menu, public KeyboardListener -{ - /* This is a very popular class with many friends */ - friend class BindKeysView; - friend class AnalogueBindListener; - -public: - BindKeysMenu(Font *font, HelpBox *help) : Menu(font) - { - this->help = help; - memset(this->hm, 0, sizeof(this->hm)); - this->setText(bind_key_menu_messages); - } - - ~BindKeysMenu() - { - this->freeHelpMessages(); - } - - virtual void selectCallback(int which) - { - int *ck = NULL; - /* Either the virtual keyboard or the analogue menu */ - bool use_virtkbd = true; - - switch(which) - { - case 0: /* Wiimote */ - switch (this->p_submenus[0].sel) - { - case 0: ck = &Gui::gui->np->JoystickButtons[0]; break; - case 1: ck = &Gui::gui->np->JoystickButtons[1]; break; - case 2: ck = &Gui::gui->np->JoystickButtons[2]; break; - case 3: ck = &Gui::gui->np->JoystickButtons[3]; break; - case 4: ck = &Gui::gui->np->JoystickButtons[5]; break; - case 5: ck = &Gui::gui->np->JoystickButtons[4]; break; - default: - panic("Wiimote: impossible selection %d", this->p_submenus[0].sel); break; - } - break; - case 2: /* Nunchuk */ - switch (this->p_submenus[1].sel) - { - case 0: ck = &Gui::gui->np->JoystickButtons[7]; break; - case 1: ck = &Gui::gui->np->JoystickButtons[8]; break; - default: - panic("Nunchuk: impossible selection %d", this->p_submenus[1].sel); break; - } - break; - case 4: /* Classic */ - switch (this->p_submenus[2].sel) - { - case 0: ck = &Gui::gui->np->JoystickButtons[9]; break; - case 1: ck = &Gui::gui->np->JoystickButtons[10]; break; - case 2: ck = &Gui::gui->np->JoystickButtons[11]; break; - case 3: ck = &Gui::gui->np->JoystickButtons[12]; break; - case 4: ck = &Gui::gui->np->JoystickButtons[13]; break; - case 5: ck = &Gui::gui->np->JoystickButtons[14]; break; - case 6: ck = &Gui::gui->np->JoystickButtons[15]; break; - case 7: ck = &Gui::gui->np->JoystickButtons[16]; break; - case 8: ck = &Gui::gui->np->JoystickButtons[18]; break; - case 9: ck = &Gui::gui->np->JoystickButtons[17]; break; - default: - panic("Classic: impossible selection %d", this->p_submenus[2].sel); break; - } - break; - case 7: - Gui::gui->np->SetupJoystickDefaults(); - this->updateHelpMessages(); - return; - default: - panic("Impossible menu option\n"); - break; - } - this->cur_key = ck; - - if (use_virtkbd) - { - VirtualKeyboard::kbd->activate(false); - VirtualKeyboard::kbd->registerListener(this); - } - else - { - AnalogueBindListener *bl = new AnalogueBindListener(this); - DialogueBox *dlg = new DialogueBox(select_analogue_dlg); - - dlg->registerListener(bl); - Gui::gui->pushDialogueBox(dlg); - } - } - - virtual void hoverCallback(int which) - { - this->help->updateHelpMessage(which); - } - - virtual void escapeCallback(int which) - { - Gui::gui->popView(); - } - - virtual void keyCallback(bool shift, const char *str) - { - panic_if(!this->cur_key, "No key selected but keyboard active???\n"); - - *this->cur_key = this->stringToKeycode(str); - this->updateHelpMessages(); - this->help->updateHelpMessage(this->cur_sel); - VirtualKeyboard::kbd->deactivate(); - this->cur_key = NULL; - } - - void updateHelpMessages() - { - this->freeHelpMessages(); - - this->hm[0] = this->addOne(this->hm[0], this->allocOne("1: %s", stringToPtr_Wiimote("1"))); - this->hm[0] = this->addOne(this->hm[0], this->allocOne("2: %s", stringToPtr_Wiimote("2"))); - this->hm[0] = this->addOne(this->hm[0], this->allocOne("A: %s", stringToPtr_Wiimote("A"))); - this->hm[0] = this->addOne(this->hm[0], this->allocOne("B: %s", stringToPtr_Wiimote("B"))); - this->hm[0] = this->addOne(this->hm[0], this->allocOne("+: %s", stringToPtr_Wiimote("+"))); - this->hm[0] = this->addOne(this->hm[0], this->allocOne("-: %s", stringToPtr_Wiimote("-"))); - - /* Nunchuk */ - this->hm[2] = this->addOne(this->hm[2], this->allocOne("Z: %s", stringToPtr_Nunchuk("Z"))); - this->hm[2] = this->addOne(this->hm[2], this->allocOne("C: %s", stringToPtr_Nunchuk("C"))); - - /* Classic */ - this->hm[4] = this->addOne(this->hm[4], this->allocOne("a: %s", stringToPtr_Classic("a"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("b: %s", stringToPtr_Classic("b"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("x: %s", stringToPtr_Classic("x"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("y: %s", stringToPtr_Classic("y"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("L: %s", stringToPtr_Classic("L"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("R: %s", stringToPtr_Classic("R"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zl: %s", stringToPtr_Classic("Zl"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zr: %s", stringToPtr_Classic("Zr"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("+: %s", stringToPtr_Classic("+"))); - this->hm[4] = this->addOne(this->hm[4], this->allocOne("-: %s", stringToPtr_Classic("-"))); - - /* - this->hm[2] = this->addOne(this->hm[2], this->allocOne("l: %s", stringToPtr_Classic("l"))); - this->hm[2] = this->addOne(this->hm[2], this->allocOne("r: %s", stringToPtr_Classic("r"))); - this->hm[2] = this->addOne(this->hm[2], this->allocOne("R-toggle: %s", stringToPtr_Classic("RA"))); - this->hm[2] = this->addOne(this->hm[2], this->allocOne("L-toggle: %s", stringToPtr_Classic("LA"))); - */ - - this->hm[7] = this->addOne(this->hm[11], xstrdup("Revert to defaults")); - - this->help->setHelpMessages(this->hm); - } - -private: - void freeHelpMessages() - { - for (unsigned i = 0; i < ARRAY_SIZE(this->hm); i++) - { - if (this->hm[i]) - { - for (int j = 0; this->hm[i][j]; j++) - free((void*)this->hm[i][j]); - free(this->hm[i]); - } - this->hm[i] = NULL; - } - } - -#define EQ(b) (strcmp(str, b) == 0) - int *stringToPtr_Classic(const char *str) - { - if (EQ("Up")) - return &Gui::gui->np->JoystickHats[0]; - if (EQ("Down")) - return &Gui::gui->np->JoystickHats[1]; - if (EQ("Left")) - return &Gui::gui->np->JoystickHats[2]; - if (EQ("Right")) - return &Gui::gui->np->JoystickHats[3]; - if (EQ("LAH")) - return &Gui::gui->np->JoystickAxes[0]; - if (EQ("LAV")) - return &Gui::gui->np->JoystickAxes[1]; - if (EQ("RAH")) - return &Gui::gui->np->JoystickAxes[2]; - if (EQ("RAV")) - return &Gui::gui->np->JoystickAxes[3]; - if (EQ("RA")) - return &Gui::gui->np->JoystickAxes[4]; - if (EQ("LA")) - return &Gui::gui->np->JoystickAxes[5]; - if (EQ("a")) - return &Gui::gui->np->JoystickButtons[9]; - if (EQ("b")) - return &Gui::gui->np->JoystickButtons[10]; - if (EQ("x")) - return &Gui::gui->np->JoystickButtons[11]; - if (EQ("y")) - return &Gui::gui->np->JoystickButtons[12]; - if (EQ("L")) - return &Gui::gui->np->JoystickButtons[13]; - if (EQ("R")) - return &Gui::gui->np->JoystickButtons[14]; - if (EQ("Zl")) - return &Gui::gui->np->JoystickButtons[15]; - if (EQ("Zr")) - return &Gui::gui->np->JoystickButtons[16]; - if (EQ("-")) - return &Gui::gui->np->JoystickButtons[17]; - if (EQ("+")) - return &Gui::gui->np->JoystickButtons[18]; - if (EQ("Home")) - return &Gui::gui->np->JoystickButtons[19]; - - /* Shound never happen! */ - panic("Illegal string %s\n", str); - - return NULL; - } - - int *stringToPtr_Nunchuk(const char *str) - { - if (EQ("Horiz")) - return &Gui::gui->np->JoystickAxes[0]; - if (EQ("Vert")) - return &Gui::gui->np->JoystickAxes[1]; - if (EQ("Z")) - return &Gui::gui->np->JoystickButtons[7]; - if (EQ("C")) - return &Gui::gui->np->JoystickButtons[8]; - - /* Shound never happen! */ - panic("Illegal string %s\n", str); - - return NULL; - } - - int *stringToPtr_Wiimote(const char *str) - { - if (EQ("Up")) - return &Gui::gui->np->JoystickHats[0]; - if (EQ("Down")) - return &Gui::gui->np->JoystickHats[1]; - if (EQ("Left")) - return &Gui::gui->np->JoystickHats[2]; - if (EQ("Right")) - return &Gui::gui->np->JoystickHats[3]; - if (EQ("A")) - return &Gui::gui->np->JoystickButtons[0]; - if (EQ("B")) - return &Gui::gui->np->JoystickButtons[1]; - if (EQ("1")) - return &Gui::gui->np->JoystickButtons[2]; - if (EQ("2")) - return &Gui::gui->np->JoystickButtons[3]; - if (EQ("-")) - return &Gui::gui->np->JoystickButtons[4]; - if (EQ("+")) - return &Gui::gui->np->JoystickButtons[5]; - if (EQ("Home")) - return &Gui::gui->np->JoystickButtons[6]; - - /* Shound never happen! */ - panic("Illegal string %s\n", str); - - return NULL; - } -#undef EQ - - const char **addOne(const char **dst, const char *what) - { - int cur; - int n = 0; - - if (dst != NULL) - { - for (n = 0; dst[n]; n++) - ; - } - cur = n; - n++; - dst = (const char **)xrealloc(dst, (n+1) * sizeof(const char*)); - dst[cur] = what; - dst[n] = NULL; - - return dst; - } - - const char *allocOne(const char *fmt, int *what) - { - const char *str = this->bindingToString(*what); - size_t len = strlen(str) + strlen(fmt) + 2; - char *out = (char *)xmalloc(len); - - sprintf(out, fmt, str); - - return out; - } - - int stringToKeycode(const char *str) - { - if (strcmp(str, "None") == 0) - return 0; - - /* default: */ - return VirtualKeyboard::kbd->stringToKeycode(str); - } - - const char *bindingToString(int val) - { - switch(val) - { - case JOY_NONE: - return "None"; - case JOY_HORIZ: - return "Horizontal"; - case JOY_VERT: - return "Vertical"; - case JOY_FIRE: - return "Fire"; - default: - break; - } - - /* default: */ - return VirtualKeyboard::kbd->keycodeToString(val); - } - - HelpBox *help; - int *cur_key; - const char **hm[14]; -}; - -void AnalogueBindListener::selectCallback(DialogueBox *which, int selected) -{ - switch(selected) - { - case 1: - *menu->cur_key = JOY_HORIZ; break; - case 2: - *menu->cur_key = JOY_VERT; break; - case 0: - default: - *menu->cur_key = JOY_NONE; break; - } - - this->menu->updateHelpMessages(); - this->menu->help->updateHelpMessage(this->menu->cur_sel); - - delete this; -} - - -class BindKeysView : public GuiView -{ -public: - BindKeysView() : GuiView() - { - this->help = new HelpBox(Gui::gui->small_font, NULL); - this->menu = new BindKeysMenu(Gui::gui->small_font, this->help); - } - - ~BindKeysView() - { - delete this->help; - delete this->menu; - } - - void viewPushCallback() - { - this->menu->updateHelpMessages(); - this->help->updateHelpMessage(0); - } - - void runLogic() - { - this->menu->runLogic(); - } - - void pushEvent(event_t ev) - { - this->menu->pushEvent(ev); - } - - void draw(SDL_Surface *where) - { - SDL_Rect dst; - - /* Blit the backgrounds */ - dst = (SDL_Rect){20,45,300,400}; - SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst); - - dst = (SDL_Rect){350,13,0,0}; - SDL_BlitSurface(Gui::gui->bind_key_box, NULL, where, &dst); - - this->menu->draw(where, 50, 70, 300, 400); - this->help->draw(where, 358, 28, 264, 210); - } - -protected: - BindKeysMenu *menu; - HelpBox *help; -}; +#include "gui.hh" +#include "menu.hh" +#include "help_box.hh" +#include "dialogue_box.hh" +#include "virtual_keyboard.hh" + +class BindKeysMenu; + +class AnalogueBindListener : public DialogueListener +{ +public: + AnalogueBindListener(BindKeysMenu *menu) + { + this->menu = menu; + } + + void escapeCallback(DialogueBox *which, int selected) + { + delete this; + } + + void selectCallback(DialogueBox *which, int selected); + +private: + BindKeysMenu *menu; +}; + +class BindKeysView; +class BindKeysMenu : public Menu, public KeyboardListener +{ + /* This is a very popular class with many friends */ + friend class BindKeysView; + friend class AnalogueBindListener; + +public: + BindKeysMenu(Font *font, HelpBox *help) : Menu(font) + { + this->help = help; + memset(this->hm, 0, sizeof(this->hm)); + this->setText(bind_key_menu_messages); + } + + ~BindKeysMenu() + { + this->freeHelpMessages(); + } + + virtual void selectCallback(int which) + { + int *ck = NULL; + /* Either the virtual keyboard or the analogue menu */ + bool use_virtkbd = true; + + switch(which) + { + case 0: /* Wiimote */ + switch (this->p_submenus[0].sel) + { + case 0: ck = &Gui::gui->np->JoystickButtons[0]; break; + case 1: ck = &Gui::gui->np->JoystickButtons[1]; break; + case 2: ck = &Gui::gui->np->JoystickButtons[2]; break; + case 3: ck = &Gui::gui->np->JoystickButtons[3]; break; + case 4: ck = &Gui::gui->np->JoystickButtons[5]; break; + case 5: ck = &Gui::gui->np->JoystickButtons[4]; break; + default: + panic("Wiimote: impossible selection %d", this->p_submenus[0].sel); break; + } + break; + case 2: /* Nunchuk */ + switch (this->p_submenus[1].sel) + { + case 0: ck = &Gui::gui->np->JoystickButtons[7]; break; + case 1: ck = &Gui::gui->np->JoystickButtons[8]; break; + default: + panic("Nunchuk: impossible selection %d", this->p_submenus[1].sel); break; + } + break; + case 4: /* Classic */ + switch (this->p_submenus[2].sel) + { + case 0: ck = &Gui::gui->np->JoystickButtons[9]; break; + case 1: ck = &Gui::gui->np->JoystickButtons[10]; break; + case 2: ck = &Gui::gui->np->JoystickButtons[11]; break; + case 3: ck = &Gui::gui->np->JoystickButtons[12]; break; + case 4: ck = &Gui::gui->np->JoystickButtons[13]; break; + case 5: ck = &Gui::gui->np->JoystickButtons[14]; break; + case 6: ck = &Gui::gui->np->JoystickButtons[15]; break; + case 7: ck = &Gui::gui->np->JoystickButtons[16]; break; + case 8: ck = &Gui::gui->np->JoystickButtons[18]; break; + case 9: ck = &Gui::gui->np->JoystickButtons[17]; break; + default: + panic("Classic: impossible selection %d", this->p_submenus[2].sel); break; + } + break; + case 7: + Gui::gui->np->SetupJoystickDefaults(); + this->updateHelpMessages(); + return; + default: + panic("Impossible menu option\n"); + break; + } + this->cur_key = ck; + + if (use_virtkbd) + { + VirtualKeyboard::kbd->activate(false); + VirtualKeyboard::kbd->registerListener(this); + } + else + { + AnalogueBindListener *bl = new AnalogueBindListener(this); + DialogueBox *dlg = new DialogueBox(select_analogue_dlg); + + dlg->registerListener(bl); + Gui::gui->pushDialogueBox(dlg); + } + } + + virtual void hoverCallback(int which) + { + this->help->updateHelpMessage(which); + } + + virtual void escapeCallback(int which) + { + Gui::gui->popView(); + } + + virtual void keyCallback(bool shift, const char *str) + { + panic_if(!this->cur_key, "No key selected but keyboard active???\n"); + + *this->cur_key = this->stringToKeycode(str); + this->updateHelpMessages(); + this->help->updateHelpMessage(this->cur_sel); + VirtualKeyboard::kbd->deactivate(); + this->cur_key = NULL; + } + + void updateHelpMessages() + { + this->freeHelpMessages(); + + this->hm[0] = this->addOne(this->hm[0], this->allocOne("1: %s", stringToPtr_Wiimote("1"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("2: %s", stringToPtr_Wiimote("2"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("A: %s", stringToPtr_Wiimote("A"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("B: %s", stringToPtr_Wiimote("B"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("+: %s", stringToPtr_Wiimote("+"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("-: %s", stringToPtr_Wiimote("-"))); + + /* Nunchuk */ + this->hm[2] = this->addOne(this->hm[2], this->allocOne("Z: %s", stringToPtr_Nunchuk("Z"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("C: %s", stringToPtr_Nunchuk("C"))); + + /* Classic */ + this->hm[4] = this->addOne(this->hm[4], this->allocOne("a: %s", stringToPtr_Classic("a"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("b: %s", stringToPtr_Classic("b"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("x: %s", stringToPtr_Classic("x"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("y: %s", stringToPtr_Classic("y"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("L: %s", stringToPtr_Classic("L"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("R: %s", stringToPtr_Classic("R"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zl: %s", stringToPtr_Classic("Zl"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zr: %s", stringToPtr_Classic("Zr"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("+: %s", stringToPtr_Classic("+"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("-: %s", stringToPtr_Classic("-"))); + + /* + this->hm[2] = this->addOne(this->hm[2], this->allocOne("l: %s", stringToPtr_Classic("l"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("r: %s", stringToPtr_Classic("r"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("R-toggle: %s", stringToPtr_Classic("RA"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("L-toggle: %s", stringToPtr_Classic("LA"))); + */ + + this->hm[7] = this->addOne(this->hm[11], xstrdup("Revert to defaults")); + + this->help->setHelpMessages(this->hm); + } + +private: + void freeHelpMessages() + { + for (unsigned i = 0; i < ARRAY_SIZE(this->hm); i++) + { + if (this->hm[i]) + { + for (int j = 0; this->hm[i][j]; j++) + free((void*)this->hm[i][j]); + free(this->hm[i]); + } + this->hm[i] = NULL; + } + } + +#define EQ(b) (strcmp(str, b) == 0) + int *stringToPtr_Classic(const char *str) + { + if (EQ("Up")) + return &Gui::gui->np->JoystickHats[0]; + if (EQ("Down")) + return &Gui::gui->np->JoystickHats[1]; + if (EQ("Left")) + return &Gui::gui->np->JoystickHats[2]; + if (EQ("Right")) + return &Gui::gui->np->JoystickHats[3]; + if (EQ("LAH")) + return &Gui::gui->np->JoystickAxes[0]; + if (EQ("LAV")) + return &Gui::gui->np->JoystickAxes[1]; + if (EQ("RAH")) + return &Gui::gui->np->JoystickAxes[2]; + if (EQ("RAV")) + return &Gui::gui->np->JoystickAxes[3]; + if (EQ("RA")) + return &Gui::gui->np->JoystickAxes[4]; + if (EQ("LA")) + return &Gui::gui->np->JoystickAxes[5]; + if (EQ("a")) + return &Gui::gui->np->JoystickButtons[9]; + if (EQ("b")) + return &Gui::gui->np->JoystickButtons[10]; + if (EQ("x")) + return &Gui::gui->np->JoystickButtons[11]; + if (EQ("y")) + return &Gui::gui->np->JoystickButtons[12]; + if (EQ("L")) + return &Gui::gui->np->JoystickButtons[13]; + if (EQ("R")) + return &Gui::gui->np->JoystickButtons[14]; + if (EQ("Zl")) + return &Gui::gui->np->JoystickButtons[15]; + if (EQ("Zr")) + return &Gui::gui->np->JoystickButtons[16]; + if (EQ("-")) + return &Gui::gui->np->JoystickButtons[17]; + if (EQ("+")) + return &Gui::gui->np->JoystickButtons[18]; + if (EQ("Home")) + return &Gui::gui->np->JoystickButtons[19]; + + /* Shound never happen! */ + panic("Illegal string %s\n", str); + + return NULL; + } + + int *stringToPtr_Nunchuk(const char *str) + { + if (EQ("Horiz")) + return &Gui::gui->np->JoystickAxes[0]; + if (EQ("Vert")) + return &Gui::gui->np->JoystickAxes[1]; + if (EQ("Z")) + return &Gui::gui->np->JoystickButtons[7]; + if (EQ("C")) + return &Gui::gui->np->JoystickButtons[8]; + + /* Shound never happen! */ + panic("Illegal string %s\n", str); + + return NULL; + } + + int *stringToPtr_Wiimote(const char *str) + { + if (EQ("Up")) + return &Gui::gui->np->JoystickHats[0]; + if (EQ("Down")) + return &Gui::gui->np->JoystickHats[1]; + if (EQ("Left")) + return &Gui::gui->np->JoystickHats[2]; + if (EQ("Right")) + return &Gui::gui->np->JoystickHats[3]; + if (EQ("A")) + return &Gui::gui->np->JoystickButtons[0]; + if (EQ("B")) + return &Gui::gui->np->JoystickButtons[1]; + if (EQ("1")) + return &Gui::gui->np->JoystickButtons[2]; + if (EQ("2")) + return &Gui::gui->np->JoystickButtons[3]; + if (EQ("-")) + return &Gui::gui->np->JoystickButtons[4]; + if (EQ("+")) + return &Gui::gui->np->JoystickButtons[5]; + if (EQ("Home")) + return &Gui::gui->np->JoystickButtons[6]; + + /* Shound never happen! */ + panic("Illegal string %s\n", str); + + return NULL; + } +#undef EQ + + const char **addOne(const char **dst, const char *what) + { + int cur; + int n = 0; + + if (dst != NULL) + { + for (n = 0; dst[n]; n++) + ; + } + cur = n; + n++; + dst = (const char **)xrealloc(dst, (n+1) * sizeof(const char*)); + dst[cur] = what; + dst[n] = NULL; + + return dst; + } + + const char *allocOne(const char *fmt, int *what) + { + const char *str = this->bindingToString(*what); + size_t len = strlen(str) + strlen(fmt) + 2; + char *out = (char *)xmalloc(len); + + sprintf(out, fmt, str); + + return out; + } + + int stringToKeycode(const char *str) + { + if (strcmp(str, "None") == 0) + return 0; + + /* default: */ + return VirtualKeyboard::kbd->stringToKeycode(str); + } + + const char *bindingToString(int val) + { + switch(val) + { + case JOY_NONE: + return "None"; + case JOY_HORIZ: + return "Horizontal"; + case JOY_VERT: + return "Vertical"; + case JOY_FIRE: + return "Fire"; + default: + break; + } + + /* default: */ + return VirtualKeyboard::kbd->keycodeToString(val); + } + + HelpBox *help; + int *cur_key; + const char **hm[14]; +}; + +void AnalogueBindListener::selectCallback(DialogueBox *which, int selected) +{ + switch(selected) + { + case 1: + *menu->cur_key = JOY_HORIZ; break; + case 2: + *menu->cur_key = JOY_VERT; break; + case 0: + default: + *menu->cur_key = JOY_NONE; break; + } + + this->menu->updateHelpMessages(); + this->menu->help->updateHelpMessage(this->menu->cur_sel); + + delete this; +} + + +class BindKeysView : public GuiView +{ +public: + BindKeysView() : GuiView() + { + this->help = new HelpBox(Gui::gui->small_font, NULL); + this->menu = new BindKeysMenu(Gui::gui->small_font, this->help); + } + + ~BindKeysView() + { + delete this->help; + delete this->menu; + } + + void viewPushCallback() + { + this->menu->updateHelpMessages(); + this->help->updateHelpMessage(0); + } + + void runLogic() + { + this->menu->runLogic(); + } + + void pushEvent(event_t ev) + { + this->menu->pushEvent(ev); + } + + void draw(SDL_Surface *where) + { + SDL_Rect dst; + + /* Blit the backgrounds */ + dst = (SDL_Rect){20,45,300,400}; + SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst); + + dst = (SDL_Rect){350,13,0,0}; + SDL_BlitSurface(Gui::gui->bind_key_box, NULL, where, &dst); + + this->menu->draw(where, 50, 70, 300, 400); + this->help->draw(where, 358, 28, 264, 230); + } + +protected: + BindKeysMenu *menu; + HelpBox *help; +}; diff --git a/Src/gui/disc_menu.cpp b/Src/gui/disc_menu.cpp index 55c8e12..ea53870 100644 --- a/Src/gui/disc_menu.cpp +++ b/Src/gui/disc_menu.cpp @@ -72,6 +72,7 @@ class StartGameListener : public TimeoutHandler public: StartGameListener() { + Gui::gui->status_bar->queueMessage("Resetting the C64"); TheC64->Reset(); TimerController::controller->arm(this, 4500); diff --git a/Src/gui/game_info.cpp b/Src/gui/game_info.cpp index 2259638..550233f 100644 --- a/Src/gui/game_info.cpp +++ b/Src/gui/game_info.cpp @@ -228,7 +228,8 @@ GameInfo::GameInfo(GameInfo *gi) this->genre = gi->genre; if (gi->screenshot) - this->screenshot = SDL_DisplayFormat(gi->screenshot); + // this->screenshot = SDL_DisplayFormat(gi->screenshot); + this->screenshot = sdl_surface_8bit_copy(gi->screenshot); } GameInfo::~GameInfo() diff --git a/Src/gui/gui.cpp b/Src/gui/gui.cpp index f977f98..624436a 100644 --- a/Src/gui/gui.cpp +++ b/Src/gui/gui.cpp @@ -355,8 +355,8 @@ void Gui::exitMenu() prefs_changed = ThePrefs != *this->np; ThePrefs = *this->np; - if (prefs_changed) - ThePrefs.Save(ThePrefs.PrefsPath); + //if (prefs_changed) + // ThePrefs.Save(ThePrefs.PrefsPath); this->saveGameInfo(this->metadata_base_path, this->cur_gameInfo->filename); } diff --git a/Src/gui/main_menu.cpp b/Src/gui/main_menu.cpp index f608e72..4a13412 100644 --- a/Src/gui/main_menu.cpp +++ b/Src/gui/main_menu.cpp @@ -70,7 +70,7 @@ public: case 0: /* Insert disc */ Gui::gui->dv->setDirectory(Gui::gui->game_base_path); Gui::gui->pushView(Gui::gui->dv); - + Gui::gui->dv->runStartSequence(this->p_submenus[0].sel == 0); break; case 2: /* Load/save states */ @@ -115,6 +115,11 @@ public: case 9: /* Options */ Gui::gui->pushView(Gui::gui->ov); break; + case 10: /* Save Prefs */ + ThePrefs = *Gui::gui->np; + ThePrefs.Save(ThePrefs.PrefsPath); + Gui::gui->pushDialogueBox(new DialogueBox(save_prefs_done)); + break; case 11: /* Exit */ DialogueBox *exit_dialogue = new DialogueBox(exit_dialogue_messages); exit_dialogue->registerListener(new ExitListener()); diff --git a/Src/gui/menu_messages.c b/Src/gui/menu_messages.c index c4a722d..10593e1 100644 --- a/Src/gui/menu_messages.c +++ b/Src/gui/menu_messages.c @@ -13,6 +13,17 @@ const char *exit_dialogue_messages[8] = { NULL }; +const char *save_prefs_done[8] = { + /*00*/ "Preferences saved!", + /*01*/ "#", + /*02*/ "#", /* Empty line */ + /*03*/ "#", + /*04*/ "#", + /*05*/ "#", + /*06*/ "^|OK", + NULL +}; + const char *save_state_done[8] = { /*00*/ "Game state saved!", /*01*/ "#", @@ -138,7 +149,7 @@ const char *main_menu_messages[14] = { /*07*/ "Game info", /*08*/ "Networking", /*09*/ "Options", - /*10*/ " ", + /*10*/ "Save prefs", /*11*/ "Quit", NULL }; @@ -182,7 +193,10 @@ const char **main_menu_help[14] = { "Configure Frodo", NULL, }, - NULL, + (const char*[]){ + "Save general preferences", + NULL, + }, (const char*[]){ "Quit Frodo", NULL, @@ -244,13 +258,9 @@ const char **options_menu_help[14] = { NULL, (const char*[]){ "Select display settings.", - "Fullscreen attemts to run", - "in fullscreen mode, while.", - "windowed uses a window.", - "Activated on next restart.", - " ", - "On the Wii, fullscreen is", - "always used", + "Fullscreen runs in", + "double size mode, while", + "window in streched mode.", NULL, }, NULL, @@ -262,7 +272,10 @@ const char **options_menu_help[14] = { NULL, }, NULL, - NULL, + (const char*[]){ + "Reset the c64.", + NULL, + }, NULL, (const char*[]){ "Setup theme for the Frodo", @@ -320,6 +333,7 @@ const char **network_menu_help[9] = { }; + const char *game_info_menu_messages[11] = { /*00*/ "Capture game screenshot", /*01*/ " ", @@ -334,6 +348,8 @@ const char *game_info_menu_messages[11] = { NULL }; + + const char *genre_dlg[8] = { /*00*/ "Action", /*01*/ "Adventure", diff --git a/Src/gui/menu_messages.hh b/Src/gui/menu_messages.hh index 393564d..1681cc1 100644 --- a/Src/gui/menu_messages.hh +++ b/Src/gui/menu_messages.hh @@ -26,5 +26,6 @@ extern const char *game_info_bad_number_dlg[]; extern const char *genre_dlg[]; extern const char *players_dlg[]; extern const char *save_state_done[]; +extern const char *save_prefs_done[]; #endif diff --git a/Src/gui/network_user_menu.hh b/Src/gui/network_user_menu.hh index 8f68a57..0b3f4af 100644 --- a/Src/gui/network_user_menu.hh +++ b/Src/gui/network_user_menu.hh @@ -2,7 +2,7 @@ #define NETWORK_USER_MENU_HH #include -#include +#include "../Network.h" class GuiView; class NetworkUserMenu; diff --git a/Src/gui/save_game_menu.cpp b/Src/gui/save_game_menu.cpp index ff6616d..1762af0 100644 --- a/Src/gui/save_game_menu.cpp +++ b/Src/gui/save_game_menu.cpp @@ -77,15 +77,16 @@ public: if (this->loadSnapshot) { - int display_type = Gui::gui->np->DisplayType; + //int display_type = Gui::gui->np->DisplayType; + TheC64->Reset(); TheC64->LoadSnapshot(new_path); this->updateGameInfo(fileName); Gui::gui->updateGameInfo(Gui::gui->sgv->gameInfo->gi); Gui::gui->np->Load(prefs_path); /* Don't change display type */ - Gui::gui->np->DisplayType = display_type; + //Gui::gui->np->DisplayType = display_type; } else unlink(new_path); free(prefs_path); @@ -162,6 +163,7 @@ void SaveGameView::saveSnapshot() char *prefs_name; char *save; + /* if (strlen(Gui::gui->np->DrivePath[0]) != 0) name = Gui::gui->np->DrivePath[0]; out_name = strrchr(name, '/'); @@ -169,6 +171,12 @@ void SaveGameView::saveSnapshot() out_name = name; else out_name++; + */ + //take the filename from gameinfo instead from drivepath + out_name = Gui::gui->cur_gameInfo->filename; + if (!out_name) + out_name = name; + save = (char*)xmalloc( strlen(Gui::gui->save_game_path) + strlen(out_name) + 6 ); prefs_name = (char*)xmalloc( strlen(Gui::gui->save_game_path) + strlen(out_name) + 12 ); @@ -182,9 +190,12 @@ void SaveGameView::saveSnapshot() if (!was_paused) TheC64->Resume(); + //Take the screenshot from the one saved when the gui was activacted Gui::gui->cur_gameInfo->setScreenshot(sdl_surface_8bit_copy(Gui::gui->screenshot)); Gui::gui->saveGameInfo(Gui::gui->save_game_path, out_name); - ThePrefs.Save(prefs_name); + + ThePrefs = *Gui::gui->np; + ThePrefs.Save_game(prefs_name); Gui::gui->pushDialogueBox(new DialogueBox(save_state_done)); diff --git a/Src/main.cpp b/Src/main.cpp index b1483d5..e561a81 100644 --- a/Src/main.cpp +++ b/Src/main.cpp @@ -1,278 +1,303 @@ -/* - * main.cpp - Main program - * - * Frodo (C) 1994-1997,2002-2005 Christian Bauer - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include - -#include "sysdeps.h" - -#include "main.h" -#include "C64.h" -#include "Display.h" -#include "Prefs.h" -#include "SAM.h" -#include "gui/gui.hh" -#include "data_store.hh" -#include "utils.hh" - -#if defined(GEKKO) -#include "fat.h" -#endif - - -// Global variables -extern int init_graphics(void); - - -// Global variables -C64 *TheC64 = NULL; // Global C64 object -char AppDirPath[1024]; // Path of application directory - - -// ROM file names -#ifndef DATADIR -#define DATADIR -#endif - -#ifdef __riscos__ -#define BASIC_ROM_FILE "FrodoRsrc:Basic_ROM" -#define KERNAL_ROM_FILE "FrodoRsrc:Kernal_ROM" -#define CHAR_ROM_FILE "FrodoRsrc:Char_ROM" -#define DRIVE_ROM_FILE "FrodoRsrc:1541_ROM" -#elif GEKKO -#define WII_FRODO_BASE_PATH "/apps/frodo/" -#define BASIC_ROM_FILE WII_FRODO_BASE_PATH"Basic_ROM" -#define KERNAL_ROM_FILE WII_FRODO_BASE_PATH"Kernal_ROM" -#define CHAR_ROM_FILE WII_FRODO_BASE_PATH"Char_ROM" -#define DRIVE_ROM_FILE WII_FRODO_BASE_PATH"1541_ROM" -#else -#define BASIC_ROM_FILE DATADIR "Basic ROM" -#define KERNAL_ROM_FILE DATADIR "Kernal ROM" -#define CHAR_ROM_FILE DATADIR "Char ROM" -#define DRIVE_ROM_FILE DATADIR "1541 ROM" -#endif - - -// Builtin ROMs -#include "Basic_ROM.h" -#include "Kernal_ROM.h" -#include "Char_ROM.h" -#include "1541_ROM.h" - - -/* - * Load C64 ROM files - */ - -void Frodo::load_rom(const char *which, const char *path, uint8 *where, size_t size, const uint8 *builtin) -{ - FILE *f = fopen(path, "rb"); - if (f) { - size_t actual = fread(where, 1, size, f); - fclose(f); - if (actual == size) - return; - } - - // Use builtin ROM - printf("%s ROM file (%s) not readable, using builtin.\n", which, path); - memcpy(where, builtin, size); -} - -void Frodo::load_rom_files() -{ - load_rom("Basic", BASIC_ROM_FILE, TheC64->Basic, BASIC_ROM_SIZE, builtin_basic_rom); - load_rom("Kernal", KERNAL_ROM_FILE, TheC64->Kernal, KERNAL_ROM_SIZE, builtin_kernal_rom); - load_rom("Char", CHAR_ROM_FILE, TheC64->Char, CHAR_ROM_SIZE, builtin_char_rom); - load_rom("1541", DRIVE_ROM_FILE, TheC64->ROM1541, DRIVE_ROM_SIZE, builtin_drive_rom); -} - -/* - * Create application object and start it - */ - -extern "C" int main(int argc, char **argv) -{ - timeval tv; - gettimeofday(&tv, NULL); - srand(tv.tv_usec); - - // Init SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK) < 0) { - fprintf(stderr, "Couldn't initialize SDL (%s)\n", SDL_GetError()); - return 1; - } - if (TTF_Init() < 0) - { - fprintf(stderr, "Unable to init TTF: %s\n", TTF_GetError() ); - return 1; - } - - fflush(stdout); - - Frodo *the_app = new Frodo(); - the_app->ArgvReceived(argc, argv); - the_app->ReadyToRun(); - delete the_app; - - return 0; -} - - -/* - * Constructor: Initialize member variables - */ - -Frodo::Frodo() -{ - Prefs p; - - TheC64 = NULL; - ThePrefs = p; /* Silly workaround to fix joystick bug */ - TheDefaultPrefs = p; -} - - -/* - * Process command line arguments - */ -char *network_server_connect = 0; - -void Frodo::ArgvReceived(int argc, char **argv) -{ - if (argc == 2) - network_server_connect = argv[1]; -} - -const char *try_path(const char *path, const char *file) -{ - if (path == NULL || file == NULL) - return NULL; - - char *what = (char *)xmalloc(strlen(path) + strlen(file) + 3); - struct stat st; - const char *out = NULL; - - sprintf(what, "%s/%s", path, file); - if (stat(what, &st) == 0) - out = what; - - return out; -} - -void Frodo::LoadFrodorc() -{ - const char *paths[] = { - "/frodo", // Wii - ".", - "/apps/frodo", // Wii - "frodo", - NULL, // Filled in below - NULL, // also filled in below - "/usr/share/frodo", - NULL, - }; - const char *prefs_path = NULL; - const char *prefs_name = NULL; - const char *total_name = NULL; - char home_1[255]; - char home_2[255]; - int i; - - if (getenv("HOME")) - { - snprintf(home_1, sizeof(home_1), "%s/.frodo", getenv("HOME")); - snprintf(home_2, sizeof(home_2), "%s/frodo", getenv("HOME")); - } - else - { - strcpy(home_1, ""); - strcpy(home_2, ""); - } - paths[4] = home_1; - paths[5] = home_2; - - for (i = 0; paths[i]; i++) - { - const char *p; - const char *name = "frodorc"; - - p = try_path(paths[i], name); - - if (p) - { - prefs_path = paths[i]; - prefs_name = name; - total_name = p; - break; - } - free((void*)p); - } - - // Load preferences - if (total_name) - { - ThePrefs.Load(total_name); - strncpy(ThePrefs.PrefsPath, total_name, sizeof(ThePrefs.PrefsPath)); - } else - printf("No frodorc, using default\n"); - - free((void*)total_name); -} - -/* - * Arguments processed, run emulation - */ - -void Frodo::ReadyToRun(void) -{ - if (getcwd(AppDirPath, 256) == NULL) - strcpy(AppDirPath, ""); - - this->LoadFrodorc(); - if (network_server_connect) - strncpy(ThePrefs.NetworkServer, network_server_connect, - sizeof(ThePrefs.NetworkServer)); - panic_if (!init_graphics(), - "Can't initialize graphics!\n"); - - // Create and start C64 - TheC64 = new C64; - DataStore::ds = new DataStore(); - TimerController::init(); - Gui::init(); - load_rom_files(); - TheC64->Run(); - - delete TheC64; - -#if defined(GEKKO) - fatUnmount("sd:"); -#endif -} - -/* - * Determine whether path name refers to a directory - */ - -bool IsDirectory(const char *path) -{ - struct stat st; - return stat(path, &st) == 0 && S_ISDIR(st.st_mode); -} +/* + * main.cpp - Main program + * + * Frodo (C) 1994-1997,2002-2005 Christian Bauer + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include "sysdeps.h" + +#include "main.h" +#include "C64.h" +#include "Display.h" +#include "Prefs.h" +#include "SAM.h" +#include "gui/gui.hh" +#include "data_store.hh" +#include "utils.hh" +#include + +#if defined(GEKKO) +#include "fat.h" +#endif + + +// Global variables +extern int init_graphics(void); + + +// Global variables +C64 *TheC64 = NULL; // Global C64 object +char AppDirPath[1024]; // Path of application directory + + +// ROM file names +#ifndef DATADIR +#define DATADIR +#endif + +#ifdef __riscos__ +#define BASIC_ROM_FILE "FrodoRsrc:Basic_ROM" +#define KERNAL_ROM_FILE "FrodoRsrc:Kernal_ROM" +#define CHAR_ROM_FILE "FrodoRsrc:Char_ROM" +#define DRIVE_ROM_FILE "FrodoRsrc:1541_ROM" +#elif GEKKO +#define WII_FRODO_BASE_PATH "/apps/frodo/" +#define BASIC_ROM_FILE WII_FRODO_BASE_PATH"Basic_ROM" +#define KERNAL_ROM_FILE WII_FRODO_BASE_PATH"Kernal_ROM" +#define CHAR_ROM_FILE WII_FRODO_BASE_PATH"Char_ROM" +#define DRIVE_ROM_FILE WII_FRODO_BASE_PATH"1541_ROM" +#else +#define BASIC_ROM_FILE DATADIR "Basic ROM" +#define KERNAL_ROM_FILE DATADIR "Kernal ROM" +#define CHAR_ROM_FILE DATADIR "Char ROM" +#define DRIVE_ROM_FILE DATADIR "1541 ROM" +#endif + + +// Builtin ROMs +#include "Basic_ROM.h" +#include "Kernal_ROM.h" +#include "Char_ROM.h" +#include "1541_ROM.h" + + +/* + * Load C64 ROM files + */ + +void Frodo::load_rom(const char *which, const char *path, uint8 *where, size_t size, const uint8 *builtin) +{ + FILE *f = fopen(path, "rb"); + if (f) { + size_t actual = fread(where, 1, size, f); + fclose(f); + if (actual == size) + return; + } + + // Use builtin ROM + printf("%s ROM file (%s) not readable, using builtin.\n", which, path); + memcpy(where, builtin, size); +} + +void Frodo::load_rom_files() +{ + load_rom("Basic", BASIC_ROM_FILE, TheC64->Basic, BASIC_ROM_SIZE, builtin_basic_rom); + load_rom("Kernal", KERNAL_ROM_FILE, TheC64->Kernal, KERNAL_ROM_SIZE, builtin_kernal_rom); + load_rom("Char", CHAR_ROM_FILE, TheC64->Char, CHAR_ROM_SIZE, builtin_char_rom); + load_rom("1541", DRIVE_ROM_FILE, TheC64->ROM1541, DRIVE_ROM_SIZE, builtin_drive_rom); +} + +/* + * Create application object and start it + */ + +extern "C" int main(int argc, char **argv) +{ + DIR_ITER *dir_tmp; + timeval tv; + gettimeofday(&tv, NULL); + srand(tv.tv_usec); + + // Init SDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK) < 0) { + fprintf(stderr, "Couldn't initialize SDL (%s)\n", SDL_GetError()); + return 1; + } + if (TTF_Init() < 0) + { + fprintf(stderr, "Unable to init TTF: %s\n", TTF_GetError() ); + return 1; + } + + fflush(stdout); + + #ifdef WII_PORT + + printf("\x1b[2;0H"); + + //initialize libfat library + if (!fatInitDefault()) + { + printf("Couldn't initialize fat subsytem\n"); + sleep(3); + exit(0); + } + + //create tmp directory if it does not exist + dir_tmp = diropen("/frodo/tmp"); + if (!dir_tmp) {mkdir("/frodo/tmp",0777);printf("Making tmp directory\n");sleep(3);} else dirclose(dir_tmp); + + + #endif + + Frodo *the_app = new Frodo(); + the_app->ArgvReceived(argc, argv); + the_app->ReadyToRun(); + delete the_app; + + #ifdef WII_PORT + fatUnmount(0); + #endif + + return 0; +} + + +/* + * Constructor: Initialize member variables + */ + +Frodo::Frodo() +{ + Prefs p; + + TheC64 = NULL; + ThePrefs = p; /* Silly workaround to fix joystick bug */ + TheDefaultPrefs = p; +} + + +/* + * Process command line arguments + */ +char *network_server_connect = 0; + +void Frodo::ArgvReceived(int argc, char **argv) +{ + if (argc == 2) + network_server_connect = argv[1]; +} + +const char *try_path(const char *path, const char *file) +{ + if (path == NULL || file == NULL) + return NULL; + + char *what = (char *)xmalloc(strlen(path) + strlen(file) + 3); + struct stat st; + const char *out = NULL; + + sprintf(what, "%s/%s", path, file); + if (stat(what, &st) == 0) + out = what; + + return out; +} + +void Frodo::LoadFrodorc() +{ + const char *paths[] = { + "/frodo", // Wii + ".", + "/apps/frodo", // Wii + "frodo", + NULL, // Filled in below + NULL, // also filled in below + "/usr/share/frodo", + NULL, + }; + const char *prefs_path = NULL; + const char *prefs_name = NULL; + const char *total_name = NULL; + char home_1[255]; + char home_2[255]; + int i; + + if (getenv("HOME")) + { + snprintf(home_1, sizeof(home_1), "%s/.frodo", getenv("HOME")); + snprintf(home_2, sizeof(home_2), "%s/frodo", getenv("HOME")); + } + else + { + strcpy(home_1, ""); + strcpy(home_2, ""); + } + paths[4] = home_1; + paths[5] = home_2; + + for (i = 0; paths[i]; i++) + { + const char *p; + const char *name = "frodorc"; + + p = try_path(paths[i], name); + + if (p) + { + prefs_path = paths[i]; + prefs_name = name; + total_name = p; + break; + } + free((void*)p); + } + + // Load preferences + if (total_name) + { + ThePrefs.Load(total_name); + strncpy(ThePrefs.PrefsPath, total_name, sizeof(ThePrefs.PrefsPath)); + } else + printf("No frodorc, using default\n"); + + free((void*)total_name); +} + +/* + * Arguments processed, run emulation + */ + +void Frodo::ReadyToRun(void) +{ + if (getcwd(AppDirPath, 256) == NULL) + strcpy(AppDirPath, ""); + + this->LoadFrodorc(); + if (network_server_connect) + strncpy(ThePrefs.NetworkServer, network_server_connect, + sizeof(ThePrefs.NetworkServer)); + panic_if (!init_graphics(), + "Can't initialize graphics!\n"); + + // Create and start C64 + TheC64 = new C64; + DataStore::ds = new DataStore(); + TimerController::init(); + Gui::init(); + load_rom_files(); + TheC64->Run(); + + delete TheC64; + +#if defined(GEKKO) + fatUnmount("sd:"); +#endif +} + +/* + * Determine whether path name refers to a directory + */ + +bool IsDirectory(const char *path) +{ + struct stat st; + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); +} diff --git a/themes/simonk/disc_info.png b/themes/simonk/disc_info.png index 862574a..5af9844 100644 Binary files a/themes/simonk/disc_info.png and b/themes/simonk/disc_info.png differ