]> Shamusworld >> Repos - virtualjaguar/commitdiff
Fixed controller profile system.
authorShamus Hammons <jlhamm@acm.org>
Fri, 3 Oct 2014 14:48:02 +0000 (09:48 -0500)
committerShamus Hammons <jlhamm@acm.org>
Fri, 3 Oct 2014 14:48:02 +0000 (09:48 -0500)
What this means is that you have to set up profiles for controllers you
plug in now. Virtual Jaguar will try to do the right thing, but it's
still possible to make it screw up and do the wrong thing. Hopefully
this will be fixed in a future update. :-P

22 files changed:
cross-compile
src/dsp.cpp
src/file.cpp
src/filedb.cpp
src/gui/configdialog.cpp
src/gui/controllertab.cpp
src/gui/controllerwidget.cpp
src/gui/gamepad.cpp
src/gui/gamepad.h
src/gui/glwidget.h
src/gui/mainwin.cpp
src/gui/profile.cpp
src/gui/profile.h
src/jerry.cpp
src/jerry.h
src/memory.cpp
src/mmu.cpp
src/settings.cpp
src/settings.h
src/tom.cpp
src/tom.h
virtualjaguar.pro

index 896ef11243d1fe2fc66b6f1f5dca0bcf068ae883..4a8c4438499a0fc319c62dc5086eb8c908e4ce2c 100755 (executable)
@@ -5,10 +5,14 @@
 # by James Hammons
 # (C) 2012 Underground Software
 #
-echo "Cross compiling for Win32..."
+#PREFIX=i686-pc-mingw32.static
+#echo "Cross compiling for Win32..."
+echo "Cross compiling for Win64..."
 export PATH=/opt/mxe/usr/bin:$PATH
 rm makefile-qt
-make CROSS=i686-pc-mingw32-
+#make CROSS=i686-pc-mingw32.static-
+make CROSS=x86_64-w64-mingw32.static-
 #rel=`svn info | grep Revision | cut -f 2 -d ' '`
 rel=`git log -1 --pretty=format:%ci | cut -d ' ' -f 1 | tr -d -`
 cd release && upx -9v virtualjaguar.exe && zip -9v vj-$rel.zip virtualjaguar.exe
+
index b3ca25e6f88698807edc0c09f77b3540d8ae7829..e255cdef6ba64f4104a6e4b8655ffbcf4f2a9213 100644 (file)
@@ -457,12 +457,14 @@ void dsp_reset_stats(void)
                dsp_opcode_use[i] = 0;
 }
 
+
 void DSPReleaseTimeslice(void)
 {
 //This does absolutely nothing!!! !!! FIX !!!
        dsp_releaseTimeSlice_flag = 1;
 }
 
+
 void dsp_build_branch_condition_table(void)
 {
        // Fill in the mirror table
@@ -502,6 +504,7 @@ void dsp_build_branch_condition_table(void)
        }
 }
 
+
 uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
 {
        if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
@@ -522,22 +525,20 @@ uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
        {
                uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
 
-               if ((offset&0x03)==0)
-                       return(data>>24);
-               else
-               if ((offset&0x03)==1)
-                       return((data>>16)&0xff);
-               else
-               if ((offset&0x03)==2)
-                       return((data>>8)&0xff);
-               else
-               if ((offset&0x03)==3)
-                       return(data&0xff);
+               if ((offset & 0x03) == 0)
+                       return (data >> 24);
+               else if ((offset & 0x03) == 1)
+                       return ((data >> 16) & 0xFF);
+               else if ((offset & 0x03) == 2)
+                       return ((data >> 8) & 0xFF);
+               else if ((offset & 0x03) == 3)
+                       return (data & 0xFF);
        }
 
        return JaguarReadByte(offset, who);
 }
 
+
 uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
 {
        if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
@@ -565,6 +566,7 @@ uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
        return JaguarReadWord(offset, who);
 }
 
+
 uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
 {
        if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
@@ -609,12 +611,13 @@ uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
        return JaguarReadLong(offset, who);
 }
 
+
 void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
 {
        if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
                WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
 
-       if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
+       if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
        {
                offset -= DSP_WORK_RAM_BASE;
                dsp_ram_8[offset] = data;
@@ -626,7 +629,7 @@ void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
                }*/
                return;
        }
-       if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
+       if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
        {
                uint32_t reg = offset & 0x1C;
                int bytenum = offset & 0x03;
@@ -645,9 +648,11 @@ void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
        }
 //     WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
+// Well, yes, it can. There are 3 MMU users after all: 68K, GPU & DSP...!
        JaguarWriteByte(offset, data, who);
 }
 
+
 void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
 {
        if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
@@ -709,6 +714,7 @@ SET16(ram2, offset, data);
        JaguarWriteWord(offset, data, who);
 }
 
+
 //bool badWrite = false;
 void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
 {
@@ -889,6 +895,7 @@ WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
        JaguarWriteLong(offset, data, who);
 }
 
+
 //
 // Update the DSP register file pointers depending on REGPAGE bit
 //
@@ -909,6 +916,7 @@ void DSPUpdateRegisterBanks(void)
 #endif
 }
 
+
 //
 // Check for and handle any asserted DSP IRQs
 //
@@ -1054,6 +1062,7 @@ ctrl2[0] = regs2[30] = dsp_pc;
        FlushDSPPipeline();
 }
 
+
 //
 // Non-pipelined version...
 //
@@ -1159,6 +1168,7 @@ ctrl1[0] = regs1[30] = dsp_pc;
 //!!!!!!!!
 }
 
+
 //
 // Set the specified DSP IRQ line to a given state
 //
@@ -1193,11 +1203,13 @@ DSPHandleIRQsNP();
 //     GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
 }
 
+
 bool DSPIsRunning(void)
 {
        return (DSP_RUNNING ? true : false);
 }
 
+
 void DSPInit(void)
 {
 //     memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
@@ -1208,6 +1220,7 @@ void DSPInit(void)
        DSPReset();
 }
 
+
 void DSPReset(void)
 {
        dsp_pc                            = 0x00F1B000;
@@ -1238,6 +1251,7 @@ void DSPReset(void)
                *((uint32_t *)(&dsp_ram_8[i])) = rand();
 }
 
+
 void DSPDumpDisassembly(void)
 {
        char buffer[512];
@@ -1253,6 +1267,7 @@ void DSPDumpDisassembly(void)
        }
 }
 
+
 void DSPDumpRegisters(void)
 {
 //Shoud add modulus, etc to dump here...
@@ -1280,6 +1295,7 @@ void DSPDumpRegisters(void)
        }
 }
 
+
 void DSPDone(void)
 {
        int i, j;
index 00ef5f3eff749632b11b3d9618784111167bc92c..4586245656f9e9b4832299bed7ea44c100cb20e6 100644 (file)
@@ -8,9 +8,10 @@
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  01/16/2010  Created this log ;-)
-// JLH  02/28/2010  Added functions to look inside .ZIP files and handle contents
+// JLH  02/28/2010  Added functions to look inside .ZIP files and handle
+//                  contents
 // JLH  06/01/2012  Added function to check ZIP file CRCs against file DB
 //
 
@@ -107,8 +108,9 @@ uint32_t JaguarLoadROM(uint8_t * &rom, char * path)
 
 //
 // Jaguar file loading
-// We do a more intelligent file analysis here instead of relying on (possible false)
-// file extensions which people don't seem to give two shits about anyway. :-(
+// We do a more intelligent file analysis here instead of relying on (possible
+// false) file extensions which people don't seem to give two shits about
+// anyway. :-(
 //
 bool JaguarLoadFile(char * path)
 {
@@ -287,7 +289,8 @@ bool AlpineLoadFile(char * path)
        delete[] buffer;
 
 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
-       // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
+       // Try setting the vector to say, $1000 and putting an instruction there
+       // that loops forever:
        // This kludge works! Yeah!
        SET32(jaguarMainRAM, 0x10, 0x00001000);         // Set Exception #4 (Illegal Instruction)
        SET16(jaguarMainRAM, 0x1000, 0x60FE);           // Here: bra Here
index ee128468aff8c14ead41c69e653503064af71ace..dd64da5bcf1b7616420781c5b0bd17df9e79917c 100644 (file)
@@ -7,7 +7,7 @@
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  02/15/2010  Created this file
 //
 
index f8c8d4f6050603331945ec0851ad0901c259230e..3f870fcc95b7ec6c0fa4f14a3b2a5c9cbec562b2 100644 (file)
@@ -7,7 +7,7 @@
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  01/29/2010  Created this file
 // JLH  06/23/2011  Added initial implementation
 // JLH  10/14/2011  Fixed possibly missing final slash in paths
@@ -87,6 +87,7 @@ void ConfigDialog::LoadDialogFromSettings(void)
        }
 
 #warning "!!! Need to load settings from controller profile !!!"
+// We do this now, but not here. Need to fix this...
 #if 0
        for(int i=0; i<21; i++)
        {
@@ -122,12 +123,15 @@ void ConfigDialog::UpdateVJSettings(void)
        }
 
 #warning "!!! Need to save settings to controller profile !!!"
+// We do this now, but not here. Need to fix this...
+#if 0
        for(int i=0; i<21; i++)
        {
 // We need to find the right profile and load it up here...
                vjs.p1KeyBindings[i] = controllerTab1->controllerWidget->keys[i];
 //             vjs.p2KeyBindings[i] = controllerTab2->controllerWidget->keys[i];
        }
+#endif
 }
 
 
index 98080032851a6d9168816c52ba8e5aad25411654..7ff002f1dbc1902457092deeddbae3510856c422 100644 (file)
 // ---  ----------  ------------------------------------------------------------
 // JLH  06/23/2011  Created this file
 // JLH  07/20/2011  Fixed a bunch of stuff
+// JLH  10/02/2014  Fixed even more stuff, related to the profile system
 //
 
+/*
+To really fix this shit, we have to straighten out some stuff. So here goes:
+
+We have a database of profiles consisting of a device list (devices that have
+been seen already) and map list (consisting of a key into the device list, a
+human readable name, a preferred slot #, and a key/button mapping). This is a
+list that can hold up to 64 different profiles.
+
+We have a a list of attached gamepads in Gamepad::. There can be 8 at most
+attached any one time.
+
+There are two game port slots that a controller can be hooked into.
+
+So, what we need to do when configuring and/or using this system is this.
+
+ - Populate the device combobox with the list of attached devices from the
+   profile database.
+ - Populate the map to combobox with the profiles associated with that profile
+   device number.
+ - Save stuff when the user changes stuff (this happens already)
+*/
+
 #include "controllertab.h"
 
 #include "controllerwidget.h"
@@ -84,42 +107,6 @@ ControllerTab::ControllerTab(QWidget * parent/*= 0*/): QWidget(parent),
        mapToList->addItem(tr("Controller #2"), CONTROLLER2);
        mapToList->addItem(tr("Either one that's free"), CONTROLLER1 | CONTROLLER2);
 }
-/*
-So now we come to implementation. When changing devices, could have a helper function
-in profile.cpp that fills the mapNameList combobox with the appropriate names/profile
-numbers.
-
-There needs to be some way of getting data from the ControllerWidget and the current
-profile.
-
-Gamepad will have to have some way of knowing which profile is mapped to which
-Jaguar controllers and filtering out everything else.
-
-Will have to have some intelligent handling of profiles when first run, to see first
-what is connected and second, to assign profiles to Jaguar controllers. In this
-case, keyboard is the lowest priority--if a controller is plugged in and assigned to
-the same Jaguar controller as a keyboard, the controller is used. Not sure what to
-do in the case of multiple controllers plugged in and assigned to the same Jaguar
-controller.
-
-Also, need a way to load/save profiles.
-
-Meaning of checkboxes: None checked == profile not used.
-1 checked == prefer connection to Jaguar controller X.
-2 checked == no preference, use any available.
-
-Single mapping cannot be deleted ("-" will be disabled). Can always add, up to the max
-limit of profiles (MAX_PROFILES).
-
-------------------------------
-
-Now the main window passes in/removes the last edited profile #. From here, when starting
-up, we need to pull that number from the profile store and populate all our boxes.
-
--------------------------------
-
-Need to do AutoConnectProfiles from here, and detect any conflicts
-*/
 
 
 ControllerTab::~ControllerTab()
@@ -135,9 +122,6 @@ void ControllerTab::SetupLastUsedProfile(void)
        if (deviceNumIndex == -1 || mapNumIndex == -1)
        {
                // We're doing the default, so set it up...
-//             mapToList->setCurrentIndex(mapToList->findData(profile[0].preferredController));
-//printf("ControllerTab::SetupLastUsedProfile: [FAILED] profileNum=%i, controllerIndex=%i, preferredController=%i\n", profileNum, controllerIndex, profile[0].preferredController);
-//             return;
                deviceNumIndex = 0;
                mapNumIndex = 0;
                profileNum = 0;
@@ -145,11 +129,9 @@ void ControllerTab::SetupLastUsedProfile(void)
 
        deviceList->setCurrentIndex(deviceNumIndex);
        mapNameList->setCurrentIndex(mapNumIndex);
-//no more: #warning "!!! bug in here where it doesn't save your preferred controller !!!"
 
-       int controllerIndex = mapToList->findData(profile[profileNum].preferredController);
+       int controllerIndex = mapToList->findData(profile[profileNum].preferredSlot);
        mapToList->setCurrentIndex(controllerIndex);
-//printf("ControllerTab::SetupLastUsedProfile: profileNum=%i, controllerIndex=%i, preferredController=%i\n", profileNum, controllerIndex, profile[profileNum].preferredController);
 
        // We have to do this manually, since it's no longer done automagically...
        ChangeDevice(deviceNumIndex);
@@ -190,36 +172,32 @@ void ControllerTab::UpdateProfileKeys(int mapPosition, uint32_t key)
 
 void ControllerTab::UpdateProfileConnections(int selection)
 {
-//     profile[profileNum].preferredController = (controller1->isChecked() ? CONTROLLER1 : 0) | (controller2->isChecked() ? CONTROLLER2 : 0);
-       profile[profileNum].preferredController = mapToList->itemData(selection).toInt();
-//printf("Setting profile #%i 'Maps To' to %i...\n", profileNum, mapToList->itemData(selection).toInt());
+       profile[profileNum].preferredSlot = mapToList->itemData(selection).toInt();
 }
 
 
 void ControllerTab::ChangeDevice(int selection)
 {
-//printf("ControllerTab::ChangeDevice\n");
        int deviceNum = deviceList->itemData(selection).toInt();
        mapNameList->clear();
        int numberOfMappings = FindMappingsForDevice(deviceNum, mapNameList);
+       // Make sure to disable the "-" button is there's only one mapping for this
+       // device...
        deleteMapName->setDisabled(numberOfMappings == 1 ? true : false);
-//printf("Found %i mappings for device #%u...\n", numberOfMappings, deviceNum);
+       // Set up new profile #...
+       ChangeMapName(0);
 }
 
 
 void ControllerTab::ChangeMapName(int selection)
 {
-//printf("ControllerTab::ChangeMapName\n");
        profileNum = mapNameList->itemData(selection).toInt();
-//printf("You selected mapping: %s (profile #%u)\n", (mapNameList->itemText(selection)).toAscii().data(), profileNum);
 
        for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
                controllerWidget->keys[i] = profile[profileNum].map[i];
 
        controllerWidget->update();
-//     controller1->setChecked(profile[profileNum].preferredController & CONTROLLER1);
-//     controller2->setChecked(profile[profileNum].preferredController & CONTROLLER2);
-       mapToList->setCurrentIndex(mapToList->findData(profile[profileNum].preferredController));
+       mapToList->setCurrentIndex(mapToList->findData(profile[profileNum].preferredSlot));
 }
 
 
@@ -230,16 +208,7 @@ void ControllerTab::AddMapName(void)
        if (freeProfile == -1)
        {
                // Oh crap, we're out of room! Alert the media!
-               // (Really, tho, we should pop this up *before* asking for user input.
-               // Which we now do!)
-#if 0
-               QMessageBox msg;
-               msg.setText(QString(tr("Can't create any more profiles!")));
-               msg.setIcon(QMessageBox::Warning);
-               msg.exec();
-#else
                QMessageBox::warning(this, tr("Houston, we have a problem..."), tr("Can't create any more profiles!"));
-#endif
 
                return;
        }
@@ -254,7 +223,7 @@ void ControllerTab::AddMapName(void)
        profile[profileNum].device = deviceList->itemData(deviceList->currentIndex()).toInt();
        strncpy(profile[profileNum].mapName, text.toAscii().data(), 31);
        profile[profileNum].mapName[31] = 0;
-       profile[profileNum].preferredController = CONTROLLER1;
+       profile[profileNum].preferredSlot = CONTROLLER1;
 
        for(int i=BUTTON_FIRST; i<BUTTON_LAST; i++)
                profile[profileNum].map[i] = '*';
@@ -266,11 +235,6 @@ void ControllerTab::AddMapName(void)
 
 void ControllerTab::DeleteMapName(void)
 {
-//printf("Delete current mapping (TODO)...\n");
-
-       // hmm, don't need to check this... Because presumably, it's already been checked for.
-//     if (mapNameList->count() == 1) ;
-
        QMessageBox::StandardButton retVal = QMessageBox::question(this, tr("Remove Mapping"), tr("Are you sure you want to remove this mapping?"), QMessageBox::No | QMessageBox::Yes, QMessageBox::No);
 
        if (retVal == QMessageBox::No)
@@ -282,76 +246,3 @@ void ControllerTab::DeleteMapName(void)
        DeleteProfile(profileToRemove);
 }
 
-
-/*
-The profiles need the following:
-
- - The name of the controller
- - A unique human readable ID
- - The key definitions for that controller (keyboard keys can be mixed in)
-
-So there can be more than one profile for each unique controller; the
-relationship is many-to-one. So basically, how it works it like this: SDL
-reports all connected controllers. If there are none connected, the default
-controller is the keyboard (which can have multiple profiles). The UI only
-presents those profiles which are usuable with the controllers that are plugged
-in, all else is ignored. The user can pick the profile for the controller and
-configure the keys for it; the UI automagically saves everything.
-
-How to handle the case of identical controllers being plugged in? How does the
-UI know which is which? Each controller will have a mapping to a default
-Jaguar controller (#1 or #2). Still doesn't prevent confusion though. Actually,
-it can: The profile can have a field that maps it to a preferred Jaguar
-controller, which can also be both (#1 AND #2--in this case we can set it to
-zero which means no preference). If the UI detects two of the same controller
-and each can be mapped to the same profile, it assigns them in order since it
-doesn't matter, the profiles are identical.
-
-The default profile is always available and is the keyboard (hey, we're PC
-centric here). The default profile is usually #0.
-
-Can there be more than one keyboard profile? Why not? You will need separate
-ones for controller #1 and controller #2.
-
-A profile might look like this:
-
-Field 1: Nostomo N45 Analog
-Field 2: Dad's #1
-Field 3: Jaguar controller #1
-Field 4: The button/stick mapping
-
-Profile # would be implicit in the order that they are stored in the internal
-data structure.
-
-When a new controller is plugged in with no profiles attached, it defaults to
-a set keyboard layout which the user can change. So every new controller will
-always have at least one profile.
-
-Data structures:
-The Gamepad class has the name of the controller (except for Keyboard)
-The profile list is just a list
-The controller name index + profile index makes a unique key
-Probably the best way to deal with it is to stuff the name/profile indices
-into the key definition structure.
-
-#define CONTROLLER1 0x01
-#define CONTROLLER2 0x02
-
-struct Profile
-{
-       int device;                                     // Host device number
-       char mapName[32];                       // Human readable map name
-       int preferredController;        // CONTROLLER1 and/or CONTROLLER2
-       int map[21];                            // Keys/buttons/axes
-};
-
-NOTE that device is an int, and the list is maintained elsewhere. It is
-*not* the same as what you see in GetJoystickName(); the device names have
-to be able to persist even when not available.
-
-Where to store the master profile list? It has to be accessible to this class.
-vjs.profile[x] would be good, but it's not really a concern for the Jaguar core.
-So it shouldn't go there. There should be a separate global setting place for
-GUI stuff...
-*/
-
index 53a747a01d62e2f919ffe3a55fdf2a454525fce5..ca27cb5cb360b90dc3da33b3041bf0b056314c73 100644 (file)
@@ -19,8 +19,8 @@
 #include "keygrabber.h"
 
 
-// These tables are used to convert Qt keycodes into human readable form. Note that
-// a lot of these are just filler.
+// These tables are used to convert Qt keycodes into human readable form. Note
+// that a lot of these are just filler.
 char ControllerWidget::keyName1[96][16] = {
        "Space",
        "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
index 93989eed7ae7a975ecdec6d39469f23e06809da6..b8ebdde5c21a8bf9827d906b2ac92508c2e0c3b2 100644 (file)
@@ -7,7 +7,7 @@
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  01/05/2013  Created this file
 //
 
@@ -18,7 +18,7 @@
 // Class member initialization
 /*static*/ int Gamepad::numJoysticks = 0;
 /*static*/ SDL_Joystick * Gamepad::pad[8];
-/*static*/ const char * Gamepad::padName[8];
+/*static*/ char Gamepad::padName[8][128];
 /*static*/ int Gamepad::numButtons[8];
 /*static*/ int Gamepad::numHats[8];
 /*static*/ int Gamepad::numAxes[8];
@@ -51,18 +51,27 @@ void Gamepad::AllocateJoysticks(void)
        for(int i=0; i<numJoysticks; i++)
        {
                pad[i] = SDL_JoystickOpen(i);
-               padName[i] = SDL_JoystickName(i);
                numButtons[i] = numHats[i] = numAxes[i] = 0;
+               // We need to copy the contents of this pointer, as SDL will change it
+               // willy nilly to suit itself
+//             padName[i] = SDL_JoystickName(i);
+               strncpy(padName[i], SDL_JoystickName(i), 127);
+               padName[i][127] = 0;    // Just in case name's length > 127
 
                if (pad[i])
                {
                        numButtons[i] = SDL_JoystickNumButtons(pad[i]);
                        numHats[i] = SDL_JoystickNumHats(pad[i]);
                        numAxes[i] = SDL_JoystickNumAxes(pad[i]);
+                       WriteLog("Gamepad: Joystick #%i: %s\n", i, padName[i]);
                }
        }
 
        WriteLog("Gamepad: Found %u joystick%s.\n", numJoysticks, (numJoysticks == 1 ? "" : "s"));
+#if 0
+for(int i=0; i<numJoysticks; i++)
+       printf("GAMEPAD::AllocateJoysticks: stick #%i = %s\n", i, padName[i]);
+#endif
 }
 
 
@@ -79,6 +88,7 @@ const char * Gamepad::GetJoystickName(int joystickID)
        if (joystickID >= 8)
                return NULL;
 
+//printf("GAMEPAD: Getting name (%s) for joystick #%i...\n", padName[joystickID], joystickID);
        return padName[joystickID];
 }
 
@@ -127,6 +137,7 @@ bool Gamepad::GetState(int joystickID, int buttonID)
 }
 
 
+//UNUSED
 int Gamepad::CheckButtonPressed(void)
 {
        // This translates the hat direction to a mask index.
@@ -165,6 +176,7 @@ int Gamepad::CheckButtonPressed(void)
 }
 
 
+// UNUSED
 int Gamepad::GetButtonID(void)
 {
        // Return single button ID being pressed (if any)
@@ -172,6 +184,7 @@ int Gamepad::GetButtonID(void)
 }
 
 
+// UNUSED
 int Gamepad::GetJoystickID(void)
 {
        // Return joystick ID of button being pressed (if any)
@@ -198,6 +211,7 @@ void Gamepad::Update(void)
 }
 
 
+// However, SDL 2 *does* support hot-plugging! :-D
 #if 0
 // Need to test this. It may be that the only time joysticks are detected is
 // when the program is first run. That would suck.
index a7085a416e12af6bdd108db1842bdfe2b9d14e08..73aaef8261554f3566df3f29b8b804efeeb07628 100644 (file)
@@ -30,7 +30,7 @@
 class Gamepad
 {
 // really should make all methods and members be static so that we can
-// call this stuff without instantiating one. :-)
+// call this stuff without instantiating one. :-) [DONE]
        public:
                Gamepad();
                ~Gamepad();
@@ -48,7 +48,7 @@ class Gamepad
                // Support up to 8 gamepads
                static int numJoysticks;
                static SDL_Joystick * pad[8];
-               static const char * padName[8];
+               static char padName[8][128];
                static int numButtons[8];
                static int numAxes[8];
                static int numHats[8];
index e7d7406811410168c4c5eefd3d82eb7d7d445e1b..7557ea68629830abff7353f100634fafd81c3742 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <QtGui>
 #include <QGLWidget>
+#include <stdint.h>
 
 class GLWidget: public QGLWidget
 {
index f4dda13e411a9ad2443e79d107e0aba3fdd96a07..713ec11abe9ec101dfe151d4abd71b1c6ed7741b 100644 (file)
@@ -6,7 +6,7 @@
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  12/23/2009  Created this file
 // JLH  12/20/2010  Added settings, menus & toolbars
 // JLH  07/05/2011  Added CD BIOS functionality to GUI
 //
 // - Add dbl click/enter to select in cart list, ESC to dimiss [DONE]
 // - Autoscan/autoload all available BIOS from 'software' folder [DONE]
-// - Add 1 key jumping in cartridge list (press 'R', jumps to carts starting with 'R', etc) [DONE]
+// - Add 1 key jumping in cartridge list (press 'R', jumps to carts starting
+//   with 'R', etc) [DONE]
 // - Controller configuration [DONE]
 //
 // STILL TO BE DONE:
 //
 // - Fix bug in switching between PAL & NTSC in fullscreen mode.
 // - Remove SDL dependencies (sound, mainly) from Jaguar core lib
-// - Fix inconsistency with trailing slashes in paths (eeproms needs one, software doesn't)
+// - Fix inconsistency with trailing slashes in paths (eeproms needs one,
+//   software doesn't)
 //
 // SFDX CODE: S1E9T8H5M23YS
 
@@ -562,6 +564,9 @@ void MainWin::HandleKeys(QKeyEvent * e, bool state)
 }
 
 
+//
+// N.B.: The profile system AutoConnect functionality sets the gamepad IDs here.
+//
 void MainWin::HandleGamepads(void)
 {
        Gamepad::Update();
@@ -569,13 +574,10 @@ void MainWin::HandleGamepads(void)
        for(int i=BUTTON_FIRST; i<=BUTTON_LAST; i++)
        {
                if (vjs.p1KeyBindings[i] & (JOY_BUTTON | JOY_HAT | JOY_AXIS))
-                       joypad0Buttons[i] = (Gamepad::GetState(0, vjs.p1KeyBindings[i]) ? 0x01 : 0x00);
-/*{
-if (vjs.p1KeyBindings[i] & JOY_AXIS)
-       printf("Axis state (HandleGamepads): %i\n", joypad0Buttons[i]);
-}*/
+                       joypad0Buttons[i] = (Gamepad::GetState(gamepadIDSlot1, vjs.p1KeyBindings[i]) ? 0x01 : 0x00);
+
                if (vjs.p2KeyBindings[i] & (JOY_BUTTON | JOY_HAT | JOY_AXIS))
-                       joypad1Buttons[i] = (Gamepad::GetState(1, vjs.p2KeyBindings[i]) ? 0x01 : 0x00);
+                       joypad1Buttons[i] = (Gamepad::GetState(gamepadIDSlot2, vjs.p2KeyBindings[i]) ? 0x01 : 0x00);
        }
 }
 
@@ -593,9 +595,15 @@ void MainWin::Configure(void)
        dlg.generalTab->useUnknownSoftware->setChecked(allowUnknownSoftware);
        dlg.controllerTab1->profileNum = lastEditedProfile;
        dlg.controllerTab1->SetupLastUsedProfile();
+// maybe instead of this, we tell the controller tab to work on a copy that gets
+// written if the user hits 'OK'.
+       SaveProfiles();         // Just in case user cancels
 
        if (dlg.exec() == false)
+       {
+               RestoreProfiles();
                return;
+       }
 
        QString before = vjs.ROMPath;
        QString alpineBefore = vjs.alpineROMPath;
@@ -613,6 +621,7 @@ void MainWin::Configure(void)
        //ick.
        allowUnknownSoftware = dlg.generalTab->useUnknownSoftware->isChecked();
        lastEditedProfile = dlg.controllerTab1->profileNum;
+       AutoConnectProfiles();
 
        // We rescan the "software" folder if the user either changed the path or
        // checked/unchecked the "Allow unknown files" option in the config dialog.
index 71e694666f1567bab13d0fefb61a95b24b2ec5d5..114b98c9059cb59e520a08fb87de1c2897a9286f 100644 (file)
@@ -7,10 +7,27 @@
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  05/01/2013  Created this file
+// JLH  10/02/2014  Finally fixed stuff so it works the way it should
+//
+// This is a profile database with two parts: One, a list of devices, and two,
+// a list of profiles each containing a pointer to the device list, and map
+// name, a preferred slot #, and a key/button map. All the heavy lifting (incl.
+// autoconnection of devices to profiles to slots) is done here.
+//
+// Basically, how this works is that we connect the device the user plugs into
+// the computer to a profile in the database to a slot in the virtual Jaguar.
+// Hopefully the configuration that the user gives us is sane enough for us to
+// figure out how to do the right thing! By default, there is always a keyboard
+// device plugged in; any other device that gets plugged in and wants to be in
+// slot #0 can override it. This is so there is always a sane configuration if
+// nothing is plugged in.
+//
+// Devices go into the database when the user plugs them in and runs VJ, and
+// subsequently does anything to alter any of the existing profiles. Once a
+// device has been seen, it can't be unseen!
 //
-
 
 #include "profile.h"
 #include <QtGui>
 #include "settings.h"
 
 
+//#define DEBUG_PROFILES
 #define MAX_DEVICES  64
 
 
 Profile profile[MAX_PROFILES];
+Profile profileBackup[MAX_PROFILES];
 int controller1Profile;
 int controller2Profile;
-int gamepad1Slot;
-int gamepad2Slot;
+int gamepadIDSlot1;
+int gamepadIDSlot2;
 int numberOfProfiles;
 int numberOfDevices;
 char deviceNames[MAX_DEVICES][128];
@@ -37,11 +56,28 @@ uint32_t defaultMap[21] = {
        '3', 'L', 'K', 'J', 'O', 'P'
 };
 
+
 // Function Prototypes
-int ConnectProfileToDevice(int deviceNum);
+int ConnectProfileToDevice(int deviceNum, int gamepadID = -1);
 int FindProfileForDevice(int deviceNum, int preferred, int * found);
 
 
+//
+// These two functions are mainly to support the controller configuration GUI.
+// Could just as easily go there as well (and be better placed there).
+//
+void SaveProfiles(void)
+{
+       memcpy(&profileBackup, &profile, sizeof(Profile) * MAX_PROFILES);
+}
+
+
+void RestoreProfiles(void)
+{
+       memcpy(&profile, &profileBackup, sizeof(Profile) * MAX_PROFILES);
+}
+
+
 void ReadProfiles(QSettings * set)
 {
        // Assume no profiles, until we read them
@@ -59,39 +95,49 @@ void ReadProfiles(QSettings * set)
        {
                set->setArrayIndex(i - 1);
                strcpy(deviceNames[i], set->value("deviceName").toString().toAscii().data());
-//printf("Read device name: %s\n", deviceNames[i]);
+#ifdef DEBUG_PROFILES
+printf("Read device name: %s\n", deviceNames[i]);
+#endif
        }
 
        set->endArray();
        numberOfProfiles = set->beginReadArray("profiles");
-//printf("Number of profiles: %u\n", numberOfProfiles);
+#ifdef DEBUG_PROFILES
+printf("Number of profiles: %u\n", numberOfProfiles);
+#endif
 
        for(int i=0; i<numberOfProfiles; i++)
        {
                set->setArrayIndex(i);
                profile[i].device = set->value("deviceNum").toInt();
                strcpy(profile[i].mapName, set->value("mapName").toString().toAscii().data());
-               profile[i].preferredController = set->value("preferredController").toInt();
+               profile[i].preferredSlot = set->value("preferredSlot").toInt();
 
                for(int j=0; j<21; j++)
                {
                        QString string = QString("map%1").arg(j);
                        profile[i].map[j] = set->value(string).toInt();
                }
-//printf("Profile #%u: device=%u (%s)\n", i, profile[i].device, deviceNames[profile[i].device]);
+#ifdef DEBUG_PROFILES
+printf("Profile #%u: device=%u (%s)\n", i, profile[i].device, deviceNames[profile[i].device]);
+#endif
        }
 
        set->endArray();
 
-//printf("Number of profiles found: %u\n", numberOfProfiles);
+#ifdef DEBUG_PROFILES
+printf("Number of profiles found: %u\n", numberOfProfiles);
+#endif
        // Set up a reasonable default if no profiles were found
        if (numberOfProfiles == 0)
        {
-//printf("Setting up default profile...\n");
+#ifdef DEBUG_PROFILES
+printf("Setting up default profile...\n");
+#endif
                numberOfProfiles++;
                profile[0].device = 0;  // Keyboard is always device #0
                strcpy(profile[0].mapName, "Default");
-               profile[0].preferredController = CONTROLLER1;
+               profile[0].preferredSlot = CONTROLLER1;
 
                for(int i=0; i<21; i++)
                        profile[0].map[i] = defaultMap[i];
@@ -123,7 +169,7 @@ void WriteProfiles(QSettings * set)
                set->setArrayIndex(i);
                set->setValue("deviceNum", profile[i].device);
                set->setValue("mapName", profile[i].mapName);
-               set->setValue("preferredController", profile[i].preferredController);
+               set->setValue("preferredSlot", profile[i].preferredSlot);
 
                for(int j=0; j<21; j++)
                {
@@ -172,12 +218,22 @@ int FindDeviceNumberForName(const char * name)
        for(int i=0; i<numberOfDevices; i++)
        {
                if (strcmp(deviceNames[i], name) == 0)
+#ifdef DEBUG_PROFILES
+{
+printf("PROFILE: Found device #%i for name (%s)...\n", i, name);
+#endif
                        return i;
+#ifdef DEBUG_PROFILES
+}
+#endif
        }
 
        if (numberOfDevices == MAX_DEVICES)
                return -1;
 
+#ifdef DEBUG_PROFILES
+printf("Device '%s' not found, creating device...\n", name);
+#endif
        // If the device wasn't found, it must be new; so add it to the list.
        int deviceNum = numberOfDevices;
        deviceNames[deviceNum][127] = 0;
@@ -210,7 +266,7 @@ int FindMappingsForDevice(int deviceNum, QComboBox * combo)
        {
                profile[numberOfProfiles].device = deviceNum;
                strcpy(profile[numberOfProfiles].mapName, "Default");
-               profile[numberOfProfiles].preferredController = CONTROLLER1;
+               profile[numberOfProfiles].preferredSlot = CONTROLLER1;
 
                for(int i=0; i<21; i++)
                        profile[numberOfProfiles].map[i] = defaultMap[i];
@@ -224,6 +280,7 @@ int FindMappingsForDevice(int deviceNum, QComboBox * combo)
 }
 
 
+// N.B.: Unused
 int FindUsableProfiles(QComboBox * combo)
 {
        int found = 0;
@@ -232,7 +289,7 @@ int FindUsableProfiles(QComboBox * combo)
        for(int j=0; j<numberOfProfiles; j++)
        {
                // Check for device *and* usable configuration
-               if ((profile[j].device == 0) && (profile[j].preferredController))
+               if ((profile[j].device == 0) && (profile[j].preferredSlot))
                {
                        combo->addItem(QString("Keyboard::%1").arg(profile[j].mapName), j);
                        found++;
@@ -246,7 +303,7 @@ int FindUsableProfiles(QComboBox * combo)
 
                for(int j=0; j<numberOfProfiles; j++)
                {
-                       if ((profile[j].device == deviceNum) && (profile[j].preferredController))
+                       if ((profile[j].device == deviceNum) && (profile[j].preferredSlot))
                        {
                                combo->addItem(QString("%1::%2").arg(Gamepad::GetJoystickName(i)).arg(profile[j].mapName), j);
                                found++;
@@ -260,6 +317,10 @@ int FindUsableProfiles(QComboBox * combo)
 
 bool ConnectProfileToController(int profileNum, int controllerNum)
 {
+       // Sanity checks...
+       if (profileNum < 0)
+               return false;
+
        if (profile[profileNum].device == -1)
                return false;
 
@@ -276,141 +337,113 @@ bool ConnectProfileToController(int profileNum, int controllerNum)
 }
 
 
-//
-// This is a pretty crappy way of doing autodetection. What it does is scan for
-// keyboard profiles first, then look for plugged in gamepads next. If more
-// than one plugged in gamepad matches a preferred controller slot, the last
-// one found is chosen.
-//
-// There has to be a better way to do this, I just can't think of what it
-// should be ATM... :-P
-//
 /*
-Here's the rules: If preferred Jaguar controller is not checked, the profile is
-skipped. If one or the other is checked, it's put into that slot. If *both* are
-checked, it will take over any slot that isn't claimed by another gamepad. If
-there are ties, present it to the user *once* and ask them which gamepad should
-be #1; don't ask again unless a), they change the profiles and b), the
-situation warrants it.
-
-Also, there is a problem with this approach and having multiple devices
-that are the same. Currently, if two of the same device are plugged in
-and the profile is set to both controllers, it will broadcast buttons
-pressed from either gamepad, no matter who is pressing them. This is
-BAD(tm). [Not true, but there's a different problem described under 'How to
-solve?', so GOOD(tm).]
-
-Also, the gamepad logic doesn't distinguish inputs by controller, it just
-grabs them all regardless. This is also BAD(tm). [Actually, it doesn't. It
-properly segregates the inputs. So this is GOOD(tm).]
-
-How to solve?
-
-Seems there's yet ANOTHER dimension to all this: The physical gamepads
-plugged into their ports. Now the device # can map these fine if they're
-different, but we still run into problems with the handling in the MainWin
-because it's hardwired to take pad 0 in slot 0 and pad 1 in slot 1. If you have
-them configured other than this, you won't get anything. So we need to also
-map the physical devices to their respective slots.
-
-
-Steps:
-
-1) Make a list of all devices attached to the system.
-
-2) Make a list of all profiles belonging to those devices, as long as they have
-   one or more Jaguar controllers that are "mapped to".
-
-3) See if there are any conflicts. If there are, see if the user has already
-   been asked to resolve and chosen a resolution; otherwise, ask the user to
-   resolve.
-
-   a) Loop through all found profiles. If they are set to a single controller,
-      set it in the appropriate list (one list for controller 1, another for
-      controller 2).
-
-   b) Loop through all found profiles. If they are set to both controllers,
-      ... (first stab at it:)
-      Check for list #1. If nothing there, assign it to list #1.
-      Else, check for List #2. If nothing there, assign to list #2.
-      [But the wording of it implies that it will assign it to both.
-       Does that mean we should make another combobox will all the possible
-       combinations laid out? Probably. Not many people will understand that
-       checking both means "assign to either one that's free".]
-
-4) Connect profiles to controllers, and set gamepad slots (for the MainWin
-   handler).
-
+One more stab at this...
+
+ -  Connect keyboard to slot #0.
+ -  Loop thru all connected devices. For each device:
+    -  Grab all profiles for the device. For each profile:
+       -  Check to see what its preferred device is.
+       -  If PD is slot #0, see if slot is already taken (gamepadIDSlot1 != -1).
+          If not taken, take it; otherwise put in list to tell user to solve the
+          conflict for us.
+          -  If the slot is already taken and *it's the same device* as the one
+             we're looking at, set it in slot #1.
+       -  If PD is slot #1, see if slot is already taken. If not, take it;
+          otherwise, put in list to tell user to solve conflict for us.
+       -  If PD is slot #0 & #1, see if either is already taken. Try #0 first,
+          then try #1. If both are already taken, skip it. Do this *after* we've
+          connected devices with preferred slots.
 */
 void AutoConnectProfiles(void)
 {
        int foundProfiles[MAX_PROFILES];
-       int controller1Profile = -1;
-       int controller2Profile = -1;
+       controller1Profile = -1;
+       controller2Profile = -1;
+       gamepadIDSlot1 = -1;
+       gamepadIDSlot2 = -1;
 
-       // Check for Keyboard device profiles first, if anything else is plugged in
-       // it will default to it instead.
-#if 0
-       for(int i=0; i<numberOfProfiles; i++)
-       {
-               // Skip profile if it's not Keyboard device
-               if (profile[i].device != 0)
-                       continue;
-
-               if (profile[i].preferredController & CONTROLLER1)
-                       controller1Profile = i;
-
-               if (profile[i].preferredController & CONTROLLER2)
-                       controller2Profile = i;
-       }
-#else
-       // Connect keyboard devices first...
+       // Connect keyboard devices first... (N.B.: this leaves gampadIDSlot1 at -1,
+       // so it can be overridden by plugged-in gamepads.)
        ConnectProfileToDevice(0);
-#endif
 
-       // Next, check for the "don't care" condition of both jaguar controllers
-       // checked for connected host devices
+       // Connect the profiles that prefer a slot, if any.
+       // N.B.: Conflicts are detected, but ignored. 1st controller to grab a
+       //       preferred slot gets it. :-P
        for(int i=0; i<Gamepad::numJoysticks; i++)
        {
                int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
-               int numberProfilesFound = FindProfileForDevice(deviceNum, CONTROLLER1 | CONTROLLER2, foundProfiles);
+//             bool p1Overwriteable = 
+
+               for(int j=0; j<numberOfProfiles; j++)
+               {
+                       if (deviceNum != profile[j].device)
+                               continue;
+
+                       int slot = profile[j].preferredSlot;
 
-               // We need to grab pairs here, host device # paired up with profiles
-               // so we can then determine if there are any conflicts that can't be
-               // resolved...
+                       if (slot == CONTROLLER1)
+                       {
+                               if (gamepadIDSlot1 == -1)
+                                       controller1Profile = j, gamepadIDSlot1 = i;
+                               else
+                               {
+                                       // Autoresolve simple conflict: two controllers sharing one
+                                       // profile mapped to slot #0.
+                                       if ((deviceNum == profile[controller1Profile].device) && (controller2Profile == -1))
+                                               controller2Profile = j, gamepadIDSlot2 = i;
+                                       else
+                                               ; // Alert user to conflict and ask to resolve
+                               }
+                       }
+                       else if (slot == CONTROLLER2)
+                       {
+                               if (gamepadIDSlot2 == -1)
+                                       controller2Profile = j, gamepadIDSlot2 = i;
+                               else
+                               {
+                                       // Autoresolve simple conflict: two controllers sharing one
+                                       // profile mapped to slot #1.
+                                       if ((deviceNum == profile[controller2Profile].device) && (controller1Profile == -1))
+                                               controller1Profile = j, gamepadIDSlot1 = i;
+                                       else
+                                               ; // Alert user to conflict and ask to resolve
+                               }
+                       }
+               }
        }
 
+       // Connect the "don't care" states, if any. We don't roll it into the above,
+       // because it can override the profiles that have a definite preference.
+       // These should be lowest priority.
        for(int i=0; i<Gamepad::numJoysticks; i++)
        {
                int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
 
-#if 0
                for(int j=0; j<numberOfProfiles; j++)
                {
-                       // Skip profile if it's not discovered device
-                       if (profile[j].device != deviceNum)
+                       if (deviceNum != profile[j].device)
                                continue;
 
-                       if (profile[j].preferredController & CONTROLLER1)
-                               controller1Profile = j;
+                       int slot = profile[j].preferredSlot;
 
-                       if (profile[j].preferredController & CONTROLLER2)
-                               controller2Profile = j;
+                       if (slot == (CONTROLLER1 | CONTROLLER2))
+                       {
+                               if (gamepadIDSlot1 == -1)
+                                       controller1Profile = j, gamepadIDSlot1 = i;
+                               else if (gamepadIDSlot2 == -1)
+                                       controller2Profile = j, gamepadIDSlot2 = i;
+                       }
                }
-#else
-               ConnectProfileToDevice(deviceNum);
-#endif
        }
 
-       if (controller1Profile != -1)
-               ConnectProfileToController(controller1Profile, 0);
-
-       if (controller2Profile != -1)
-               ConnectProfileToController(controller2Profile, 1);
+       // Finally, attempt to connect profiles to controllers
+       ConnectProfileToController(controller1Profile, 0);
+       ConnectProfileToController(controller2Profile, 1);
 }
 
 
-int ConnectProfileToDevice(int deviceNum)
+int ConnectProfileToDevice(int deviceNum, int gamepadID/*= -1*/)
 {
 //     bool found1 = false;
 //     bool found2 = false;
@@ -423,16 +456,18 @@ int ConnectProfileToDevice(int deviceNum)
                if (profile[i].device != deviceNum)
                        continue;
 
-               if (profile[i].preferredController & CONTROLLER1)
+               if (profile[i].preferredSlot & CONTROLLER1)
                {
                        controller1Profile = i;
+                       gamepadIDSlot1 = gamepadID;
 //                     found1 = true;
                        numberFoundForController1++;
                }
 
-               if (profile[i].preferredController & CONTROLLER2)
+               if (profile[i].preferredSlot & CONTROLLER2)
                {
                        controller2Profile = i;
+                       gamepadIDSlot2 = gamepadID;
 //                     found2 = true;
                        numberFoundForController2++;
                }
@@ -442,22 +477,8 @@ int ConnectProfileToDevice(int deviceNum)
        return numberFoundForController1 + numberFoundForController2;
 }
 
-/*
-int FindProfileForDevice(int deviceNum)
-{
-       for(int i=0; i<numberOfProfiles; i++)
-       {
-               // Skip profile if it's not our device
-               if (profile[i].device != deviceNum)
-                       continue;
-
-               return i;
-       }
-
-       return -1;
-}
-*/
 
+// N.B.: Unused
 int FindProfileForDevice(int deviceNum, int preferred, int * found)
 {
        int numFound = 0;
@@ -465,11 +486,42 @@ int FindProfileForDevice(int deviceNum, int preferred, int * found)
        for(int i=0; i<numberOfProfiles; i++)
        {
                // Return the profile only if it matches the passed in device and
-               // matches the passed in prefence...
-               if ((profile[i].device == deviceNum) && (profile[i].preferredController == preferred))
+               // matches the passed in preference...
+               if ((profile[i].device == deviceNum) && (profile[i].preferredSlot == preferred))
                        found[numFound++] = i;
        }
 
        return numFound;
 }
 
+
+//
+// Also note that we have the intersection of three things here: One the one
+// hand, we have the detected joysticks with their IDs (typically in the range
+// of 0-7), we have our gamepad profiles and their IDs (typically can have up to
+// 64 of them), and we have our gamepad slots that the detected joysticks can be
+// connected to.
+//
+// So, when the user plugs in a gamepad, it gets a joystick ID, then the profile
+// manager checks to see if a profile (or profiles) for it exists. If so, then
+// it assigns that joystick ID to a gamepad slot, based upon what the user
+// requested for that profile.
+//
+// A problem (perhaps) arises when you have more than one profile for a certain
+// device, how do you know which one to use? Perhaps you have a field in the
+// profile saying that you use this profile 1st, that one 2nd, and so on...
+//
+// Some use cases, and how to resolve them:
+//
+// - User has two of the same device, and plugs them both in. There is only one
+//   profile. In this case, the sane thing to do is ignore the "preferred slot"
+//   of the dialog and use the same profile for both controllers, and plug them
+//   both into slot #0 and #1.
+// - User has one device, and plugs it in. There are two profiles. In this case,
+//   the profile chosen should be based upon the "preferred slot", with slot #0
+//   being the winner. If both profiles are set for slot #0, ask the user which
+//   profile to use, and set a flag in the profile to say that it is a preferred
+//   profile for that device.
+// - In any case where there are conflicts, the user must be consulted and sane
+//   defaults used.
+//
index 473d8320231889df69119109b543f4be07047fa5..211a8a52857398a3bb6a7bcf7b87322366c24b73 100644 (file)
@@ -6,7 +6,7 @@
 class QComboBox;
 class QSettings;
 
-#define MAX_PROFILES  64
+#define MAX_PROFILES  64               // 64 profiles ought to be enough for everybody
 #define CONTROLLER1   0x01
 #define CONTROLLER2   0x02
 
@@ -15,12 +15,14 @@ struct Profile
 {
        int device;                                     // Host device number (-1 == invalid profile)
        char mapName[32];                       // Human readable map name
-       int preferredController;        // CONTROLLER1 and/or CONTROLLER2
+       int preferredSlot;                      // CONTROLLER1 and/or CONTROLLER2
        uint32_t map[21];                       // Keys/buttons/axes
 };
 
 
 // Function prototypes
+void SaveProfiles(void);
+void RestoreProfiles(void);
 void ReadProfiles(QSettings *);
 void WriteProfiles(QSettings *);
 int GetFreeProfile(void);
@@ -36,8 +38,8 @@ void AutoConnectProfiles(void);
 extern Profile profile[];
 extern int controller1Profile;
 extern int controller2Profile;
-extern int gamepad1Slot;
-extern int gamepad2Slot;
+extern int gamepadIDSlot1;
+extern int gamepadIDSlot2;
 //extern int numberOfProfiles;
 
 #endif // __PROFILE_H__
index e0255c49d394b071e5e290711a282d37a274996a..32f8c92c85582af67ad833d3e9aefd8dc2037bac 100644 (file)
 
 //#define JERRY_CONFIG 0x4002                                          // ??? What's this ???
 
+// JERRY Registers (write, offset from $F10000)
+#define JPIT1          0x00
+#define JPIT2          0x02
+#define JPIT3          0x04
+#define JPIT4          0x08
+#define CLK1           0x10
+#define CLK2           0x12
+#define CLK3           0x14
+#define JINTCTRL       0x20
+#define ASIDATA                0x30
+#define ASICTRL                0x32
+#define ASICLK         0x34
+#define SCLK           0xA150
+#define SMODE          0xA154
+
+
 uint8_t analog_x, analog_y;
 
 static uint32_t JERRYPIT1Prescaler;
@@ -377,6 +393,7 @@ void JERRYReset(void)
 
 void JERRYDone(void)
 {
+       JERRYDumpIORegistersToLog();
        WriteLog("JERRY: M68K Interrupt control ($F10020) = %04X\n", GET16(jerry_ram_8, 0x20));
        JoystickDone();
        DACDone();
@@ -399,6 +416,30 @@ void JERRYSetPendingIRQ(int irq)
        jerryPendingInterrupt |= irq;
 }
 
+//
+// Dump all JERRY register values to the log
+//
+void JERRYDumpIORegistersToLog(void)
+{
+       WriteLog("\n\n---------------------------------------------------------------------\n");
+       WriteLog("JERRY I/O Registers\n");
+       WriteLog("---------------------------------------------------------------------\n");
+       WriteLog("F1%04X    (JPIT1): $%04X\n", JPIT1,    GET16(jerry_ram_8, JPIT1));
+       WriteLog("F1%04X    (JPIT2): $%04X\n", JPIT2,    GET16(jerry_ram_8, JPIT2));
+       WriteLog("F1%04X    (JPIT3): $%04X\n", JPIT3,    GET16(jerry_ram_8, JPIT3));
+       WriteLog("F1%04X    (JPIT4): $%04X\n", JPIT4,    GET16(jerry_ram_8, JPIT4));
+       WriteLog("F1%04X     (CLK1): $%04X\n", CLK1,     GET16(jerry_ram_8, CLK1));
+       WriteLog("F1%04X     (CLK2): $%04X\n", CLK2,     GET16(jerry_ram_8, CLK2));
+       WriteLog("F1%04X     (CLK3): $%04X\n", CLK3,     GET16(jerry_ram_8, CLK3));
+       WriteLog("F1%04X (JINTCTRL): $%04X\n", JINTCTRL, GET16(jerry_ram_8, JINTCTRL));
+       WriteLog("F1%04X  (ASIDATA): $%04X\n", ASIDATA,  GET16(jerry_ram_8, ASIDATA));
+       WriteLog("F1%04X  (ASICTRL): $%04X\n", ASICTRL,  GET16(jerry_ram_8, ASICTRL));
+       WriteLog("F1%04X   (ASICLK): $%04X\n", ASICLK,   GET16(jerry_ram_8, ASICLK));
+       WriteLog("F1%04X     (SCLK): $%04X\n", SCLK,     GET16(jerry_ram_8, SCLK));
+       WriteLog("F1%04X    (SMODE): $%04X\n", SMODE,    GET16(jerry_ram_8, SMODE));
+       WriteLog("---------------------------------------------------------------------\n\n\n");
+}
+
 
 //
 // JERRY byte access (read)
@@ -509,15 +550,18 @@ WriteLog("JERRY: Unhandled timer read (WORD) at %08X...\n", offset);
 //
 void JERRYWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
 {
+       // Moved here tentatively, so we can see everything written to JERRY.
+       jerry_ram_8[offset & 0xFFFF] = data;
+
 #ifdef JERRY_DEBUG
        WriteLog("jerry: writing byte %.2x at 0x%.6x\n",data,offset);
 #endif
-       if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
+       if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
        {
                DSPWriteByte(offset, data, who);
                return;
        }
-       else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
+       else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
        {
                DSPWriteByte(offset, data, who);
                return;
@@ -596,7 +640,7 @@ WriteLog("JERRYWriteByte: Unhandled byte write to JOYSTICK by %s.\n", whoName[wh
        if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
                return;
 
-       jerry_ram_8[offset & 0xFFFF] = data;
+//     jerry_ram_8[offset & 0xFFFF] = data;
 }
 
 
@@ -605,6 +649,10 @@ WriteLog("JERRYWriteByte: Unhandled byte write to JOYSTICK by %s.\n", whoName[wh
 //
 void JERRYWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
 {
+       // Moved here tentatively, so we can see everything written to JERRY.
+       jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF;
+       jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF;
+
 #ifdef JERRY_DEBUG
        WriteLog( "JERRY: Writing word %04X at %06X\n", data, offset);
 #endif
@@ -634,12 +682,12 @@ else if (offset == 0xF10020)
                (data & 0x10 ? "ASI " : ""), (data & 0x20 ? "I2S " : ""));
 #endif
 
-       if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
+       if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
        {
                DSPWriteWord(offset, data, who);
                return;
        }
-       else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
+       else if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
        {
                DSPWriteWord(offset, data, who);
                return;
@@ -694,11 +742,6 @@ else if (offset == 0xF10020)
 
                return;
        }
-/*     else if (offset >= 0xF10010 && offset < 0xF10016)
-       {
-               clock_word_write(offset, data);
-               return;
-       }//*/
        // JERRY -> 68K interrupt enables/latches (need to be handled!)
        else if (offset >= 0xF10020 && offset <= 0xF10022)
        {
@@ -708,12 +751,6 @@ else if (offset == 0xF10020)
 //WriteLog("JERRY: (Previous is partially handled... IRQMask=$%04X)\n", jerryInterruptMask);
                return;
        }
-/*     else if (offset >= 0xF17C00 && offset < 0xF17C02)
-       {
-//I think this was removed from the Jaguar. If so, then we don't need this...!
-               anajoy_word_write(offset, data);
-               return;
-       }*/
        else if (offset >= 0xF14000 && offset < 0xF14003)
        {
                JoystickWriteWord(offset, data);
@@ -730,8 +767,8 @@ else if (offset == 0xF10020)
        if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
                return;
 
-       jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF;
-       jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF;
+//     jerry_ram_8[(offset+0) & 0xFFFF] = (data >> 8) & 0xFF;
+//     jerry_ram_8[(offset+1) & 0xFFFF] = data & 0xFF;
 }
 
 
index cff1c25f56c3bbc6189cec81ee8e06dfdfb9f15e..868c5a0efc68452c8ff02af645b677e847b847f0 100644 (file)
@@ -11,6 +11,7 @@
 void JERRYInit(void);
 void JERRYReset(void);
 void JERRYDone(void);
+void JERRYDumpIORegistersToLog(void);
 
 uint8_t JERRYReadByte(uint32_t offset, uint32_t who = UNKNOWN);
 uint16_t JERRYReadWord(uint32_t offset, uint32_t who = UNKNOWN);
index 7ebdb2fc6e4ef99317c2e5be98c41acc08eaccf4..3782200db00fc401548a17820f699b3c10750b4d 100644 (file)
@@ -23,6 +23,8 @@ the I/O function would take care of any weird stuff...
 Actually: writes would tuck in the value, but reads would have to be handled
 correctly since some registers do not fall on the same address as far as reading
 goes... Still completely doable though. :-)
+
+N.B.: Jaguar RAM is only 2 megs. ROM is 6 megs max, IO is 128K
 */
 
 #include "memory.h"
index 3897389529f2650a0cf89280ef07fa7e709b9e95..3eaf312aec528dd055f484203b375df13e34d41c 100644 (file)
@@ -197,7 +197,10 @@ struct MemDesc {
 
 
 MemDesc memoryMap[] = {
-       { 0x000000, 0x3FFFFF, MM_RAM,  jaguarMainRAM },
+       { 0x000000, 0x1FFFFF, MM_RAM,  jaguarMainRAM },
+       { 0x200000, 0x3FFFFF, MM_RAM,  jaguarMainRAM }, // Mirror of 1st 2 megs
+       { 0x400000, 0x5FFFFF, MM_RAM,  jaguarMainRAM }, // "         "
+       { 0x600000, 0x7FFFFF, MM_RAM,  jaguarMainRAM }, // "         "
        { 0x800000, 0xDFFEFF, MM_ROM,  jaguarMainROM },
 
        { 0xDFFF00, 0xDFFF03, MM_IO,   &butch }, // base of Butch == interrupt control register, R/W
index 078bc4a999b01e686592348fb7be6140ba8f93f2..7cf1efaea435a236a02bcba09f6571388671c3b6 100644 (file)
@@ -7,7 +7,7 @@
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  01/16/2010  Created this log
 // JLH  02/23/2013  Finally removed commented out stuff :-P
 //
index 8c2d226821e9fecd5d0c0bc01190fd454805567b..efd1306646a3564d820f5265da03d3eb923f7912 100644 (file)
 #include <limits.h>
 #define MAX_PATH               _POSIX_PATH_MAX
 #else
-#include <stdlib.h>                                                            // for MAX_PATH on MinGW/Darwin
+#include <stdlib.h>                            // for MAX_PATH on MinGW/Darwin
+// Kludge for Win64
+#ifndef MAX_PATH
+#define MAX_PATH _MAX_PATH             // Urgh.
+#endif
 #endif
 #include <stdint.h>
 
@@ -19,8 +23,8 @@
 struct VJSettings
 {
        bool useJoystick;
-       int32_t joyport;                                                                // Joystick port
-       bool hardwareTypeNTSC;                                          // Set to false for PAL
+       int32_t joyport;                        // Joystick port
+       bool hardwareTypeNTSC;          // Set to false for PAL
        bool useJaguarBIOS;
        bool GPUEnabled;
        bool DSPEnabled;
index cefee647b4b9eb8e4605969ee8f32d2685fd150d..34d7696f6fc6c9cd9241050dfa0d73d33ed54884 100644 (file)
 #define HEQ                    0x54            // Horizontal equalization end
 #define BG                     0x58            // Background color
 #define INT1           0xE0
+#define INT2           0xE2
 
 //NOTE: These arbitrary cutoffs are NOT taken into account for PAL jaguar screens. !!! FIX !!! [DONE]
 
@@ -1083,6 +1084,7 @@ void TOMInit(void)
 
 void TOMDone(void)
 {
+       TOMDumpIORegistersToLog();
        OPDone();
        BlitterDone();
        WriteLog("TOM: Resolution %i x %i %s\n", TOMGetVideoModeWidth(), TOMGetVideoModeHeight(),
@@ -1090,10 +1092,6 @@ void TOMDone(void)
 //     WriteLog("\ntom: object processor:\n");
 //     WriteLog("tom: pointer to object list: 0x%.8x\n",op_get_list_pointer());
 //     WriteLog("tom: INT1=0x%.2x%.2x\n",TOMReadByte(0xf000e0),TOMReadByte(0xf000e1));
-//     gpu_done();
-//     dsp_done();
-//     memory_free(tomRam8);
-//     memory_free(tom_cry_rgb_mix_lut);
 }
 
 
@@ -1249,6 +1247,7 @@ void TOMReset(void)
        if (vjs.hardwareTypeNTSC)
        {
                SET16(tomRam8, MEMCON1, 0x1861);
+//             SET16(tomRam8, MEMCON1, 0x1865);//Bunch of BS
                SET16(tomRam8, MEMCON2, 0x35CC);
                SET16(tomRam8, HP, 844);                        // Horizontal Period (1-based; HP=845)
                SET16(tomRam8, HBB, 1713);                      // Horizontal Blank Begin
@@ -1296,6 +1295,50 @@ void TOMReset(void)
 }
 
 
+//
+// Dump all TOM register values to the log
+//
+void TOMDumpIORegistersToLog(void)
+{
+       WriteLog("\n\n---------------------------------------------------------------------\n");
+       WriteLog("TOM I/O Registers\n");
+       WriteLog("---------------------------------------------------------------------\n");
+       WriteLog("F000%02X (MEMCON1): $%04X\n", MEMCON1, GET16(tomRam8, MEMCON1));
+       WriteLog("F000%02X (MEMCON2): $%04X\n", MEMCON2, GET16(tomRam8, MEMCON2));
+       WriteLog("F000%02X      (HC): $%04X\n", HC,      GET16(tomRam8, HC));
+       WriteLog("F000%02X      (VC): $%04X\n", VC,      GET16(tomRam8, VC));
+       WriteLog("F000%02X     (OLP): $%08X\n", OLP,     GET32(tomRam8, OLP));
+       WriteLog("F000%02X     (OBF): $%04X\n", OBF,     GET16(tomRam8, OBF));
+       WriteLog("F000%02X   (VMODE): $%04X\n", VMODE,   GET16(tomRam8, VMODE));
+       WriteLog("F000%02X   (BORD1): $%04X\n", BORD1,   GET16(tomRam8, BORD1));
+       WriteLog("F000%02X   (BORD2): $%04X\n", BORD2,   GET16(tomRam8, BORD2));
+       WriteLog("F000%02X      (HP): $%04X\n", HP,      GET16(tomRam8, HP));
+       WriteLog("F000%02X     (HBB): $%04X\n", HBB,     GET16(tomRam8, HBB));
+       WriteLog("F000%02X     (HBE): $%04X\n", HBE,     GET16(tomRam8, HBE));
+       WriteLog("F000%02X      (HS): $%04X\n", HS,      GET16(tomRam8, HS));
+       WriteLog("F000%02X     (HVS): $%04X\n", HVS,     GET16(tomRam8, HVS));
+       WriteLog("F000%02X    (HDB1): $%04X\n", HDB1,    GET16(tomRam8, HDB1));
+       WriteLog("F000%02X    (HDB2): $%04X\n", HDB2,    GET16(tomRam8, HDB2));
+       WriteLog("F000%02X     (HDE): $%04X\n", HDE,     GET16(tomRam8, HDE));
+       WriteLog("F000%02X      (VP): $%04X\n", VP,      GET16(tomRam8, VP));
+       WriteLog("F000%02X     (VBB): $%04X\n", VBB,     GET16(tomRam8, VBB));
+       WriteLog("F000%02X     (VBE): $%04X\n", VBE,     GET16(tomRam8, VBE));
+       WriteLog("F000%02X      (VS): $%04X\n", VS,      GET16(tomRam8, VS));
+       WriteLog("F000%02X     (VDB): $%04X\n", VDB,     GET16(tomRam8, VDB));
+       WriteLog("F000%02X     (VDE): $%04X\n", VDE,     GET16(tomRam8, VDE));
+       WriteLog("F000%02X     (VEB): $%04X\n", VEB,     GET16(tomRam8, VEB));
+       WriteLog("F000%02X     (VEE): $%04X\n", VEE,     GET16(tomRam8, VEE));
+       WriteLog("F000%02X      (VI): $%04X\n", VI,      GET16(tomRam8, VI));
+       WriteLog("F000%02X    (PIT0): $%04X\n", PIT0,    GET16(tomRam8, PIT0));
+       WriteLog("F000%02X    (PIT1): $%04X\n", PIT1,    GET16(tomRam8, PIT1));
+       WriteLog("F000%02X     (HEQ): $%04X\n", HEQ,     GET16(tomRam8, HEQ));
+       WriteLog("F000%02X      (BG): $%04X\n", BG,      GET16(tomRam8, BG));
+       WriteLog("F000%02X    (INT1): $%04X\n", INT1,    GET16(tomRam8, INT1));
+       WriteLog("F000%02X    (INT2): $%04X\n", INT2,    GET16(tomRam8, INT2));
+       WriteLog("---------------------------------------------------------------------\n\n\n");
+}
+
+
 //
 // TOM byte access (read)
 //
@@ -1396,6 +1439,9 @@ if (offset >= 0xF02000 && offset <= 0xF020FF)
 //
 void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
 {
+       // Moved here tentatively, so we can see everything written to TOM.
+       tomRam8[offset & 0x3FFF] = data;
+
 #ifdef TOM_DEBUG
        WriteLog("TOM: Writing byte %02X at %06X", data, offset);
 #endif
@@ -1470,7 +1516,7 @@ void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
                tomRam8[offset] = data, tomRam8[offset + 0x200] = data;
        }
 
-       tomRam8[offset & 0x3FFF] = data;
+//     tomRam8[offset & 0x3FFF] = data;
 }
 
 
@@ -1479,6 +1525,10 @@ void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
 //
 void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
 {
+       // Moved here tentatively, so we can see everything written to TOM.
+       tomRam8[(offset + 0) & 0x3FFF] = data >> 8;
+       tomRam8[(offset + 1) & 0x3FFF] = data & 0xFF;
+
 #ifdef TOM_DEBUG
        WriteLog("TOM: Writing byte %04X at %06X", data, offset);
 #endif
@@ -1584,8 +1634,8 @@ if (offset >= 0xF02000 && offset <= 0xF020FF)
                data &= 0x03FF;                 // These are all 10-bit registers
 
 // Fix a lockup bug... :-P
-       TOMWriteByte(0xF00000 | offset, data >> 8, who);
-       TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
+//     TOMWriteByte(0xF00000 | offset, data >> 8, who);
+//     TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
 
 if (offset == MEMCON1)
        WriteLog("TOM: Memory Config 1 written by %s: $%04X\n", whoName[who], data);
@@ -1654,6 +1704,7 @@ if (offset == HEQ)
 // TOM Shouldn't be mucking around with this, it's up to the host system to properly
 // handle this kind of crap.
 // NOTE: This is needed somehow, need to get rid of the dependency on this crap.
+//       N.B.: It's used in the rendering functions... So...
 #warning "!!! Need to get rid of this dependency !!!"
 #if 1
        if ((offset >= 0x28) && (offset <= 0x4F))
index 3ffc1864177e590b579ed8f43f3f4efd25aaf6e0..ed89b93cf41b9ae87fc1fedf743ed62ed4622005 100644 (file)
--- a/src/tom.h
+++ b/src/tom.h
@@ -41,6 +41,8 @@ uint8_t TOMGetVideoMode(void);
 uint8_t * TOMGetRamPointer(void);
 uint16_t TOMGetHDB(void);
 uint16_t TOMGetVDB(void);
+void TOMDumpIORegistersToLog(void);
+
 
 int TOMIRQEnabled(int irq);
 uint16_t TOMIRQControlReg(void);
index 75b07cb0fb2fa610ec82fcdf754feb1015603e2e..635f0c059cd2c2628ad3701b17e3908121be1245 100644 (file)
@@ -6,20 +6,22 @@
 #
 # See the README and GPLv3 files for licensing and warranty information
 #
-# NOTE: M68000 core is built and linked in as a library, so there should be no more
-#       problems with using the qmake build system as-is. :-)
-#       Other than on the Mac, where it stupidly defaults to making XCode binaries. >:-(
-#       Well, we fixed it in the Makefile, by doing platfrom detection there. :-/
+# NOTE: M68000 core is built and linked in as a library, so there should be no
+#       more problems with using the qmake build system as-is. :-)
+#       Other than on the Mac, where it stupidly defaults to making XCode
+#       binaries. >:-( Well, we fixed it in the Makefile, by doing platform
+#       detection there. :-/
 #
 
 TARGET     = virtualjaguar
 CONFIG    += qt warn_on release
 # debug
 RESOURCES += virtualjaguar.qrc
-LIBS      += -Lobj -ljaguarcore -lz -lm68k
+LIBS      += -Lobj -Lsrc/m68000/obj -ljaguarcore -lz -lm68k
 QT        += opengl
 
-# We stuff all the intermediate crap into obj/ so it won't confuse us mere mortals ;-)
+# We stuff all the intermediate crap into obj/ so it won't confuse us mere
+# mortals ;-)
 OBJECTS_DIR = obj
 MOC_DIR     = obj
 RCC_DIR     = obj
@@ -35,19 +37,23 @@ macx { LIBS += `sdl-config --static-libs` }
 else { LIBS += `$(CROSS)sdl-config --libs` }
 
 # Icon on Win32, Mac
-win32 { LIBS += res/vj-ico.o }
+#win32 { LIBS += res/vj-ico.o }
+win32 { ICON = res/vj.ico }
 macx  { ICON = res/vj-icon.icns }
 
 # C/C++ flags...
 # NOTE: May have to put -Wall back in, but only on non-release cycles. It can
-#       cause problems if you're not careful. (Can do this via command line in qmake)
+#       cause problems if you're not careful. (Can do this via command line in
+#       qmake)
 QMAKE_CFLAGS += `$(CROSS)sdl-config --cflags`
 QMAKE_CXXFLAGS += `$(CROSS)sdl-config --cflags`
 
 # Need to add libcdio stuffola (checking/including)...
 
-# Translations. NB: Nobody has stepped up to do any :-P so these are dummy translations
-TRANSLATIONS = virtualjaguar_fr.ts \
+# Translations. NB: Nobody has stepped up to do any :-P so these are dummy
+# translations
+TRANSLATIONS = \
+       virtualjaguar_fr.ts \
        virtualjaguar_gr.ts
 
 INCLUDEPATH += \
@@ -84,8 +90,7 @@ HEADERS = \
        src/gui/debug/m68kdasmbrowser.h \
        src/gui/debug/memorybrowser.h \
        src/gui/debug/opbrowser.h \
-       src/gui/debug/riscdasmbrowser.h \
-#      src/gui/sdljoystick.h
+       src/gui/debug/riscdasmbrowser.h
 
 SOURCES = \
        src/gui/about.cpp \
@@ -109,5 +114,5 @@ SOURCES = \
        src/gui/debug/m68kdasmbrowser.cpp \
        src/gui/debug/memorybrowser.cpp \
        src/gui/debug/opbrowser.cpp \
-       src/gui/debug/riscdasmbrowser.cpp \
-#      src/gui/sdljoystick.cpp
+       src/gui/debug/riscdasmbrowser.cpp
+