From 50f02ae172a1fa1d6af80ab825e4eaa3bc969a92 Mon Sep 17 00:00:00 2001 From: SimonAfek Date: Wed, 12 Jul 2023 10:49:01 +0200 Subject: [PATCH 01/49] Fix broken macOS interface build (#679) * Update macOS version in build_interface.yml * Typo fixes in build_interface.yml --- .github/workflows/build_interface.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_interface.yml b/.github/workflows/build_interface.yml index 9dc809c15..a45a514a4 100644 --- a/.github/workflows/build_interface.yml +++ b/.github/workflows/build_interface.yml @@ -23,14 +23,14 @@ jobs: - name: Build - ninja run: ninja -C desmume/src/frontend/interface/build - - name: Upload artificat + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: linux path: desmume/src/frontend/interface/build/libdesmume.so build_macos: - runs-on: macos-10.15 + runs-on: macos-12 name: Build MacOS steps: - name: Checkout @@ -53,7 +53,7 @@ jobs: CC: clang CXX: clang++ - - name: Upload artificat + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: macos @@ -78,7 +78,7 @@ jobs: cd desmume\src\frontend\interface\windows MSBuild.exe DeSmuME_Interface.vcxproj /p:configuration="Release Fastbuild" /p:Platform=${{ matrix.arch }} - - name: Upload artificat + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: win-${{ matrix.arch }} From 0c90e8f4e330ecfde199ca2ba6a177edd8e7783d Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 18 Jul 2023 11:13:42 -0700 Subject: [PATCH 02/49] Cheat System: Rearchitect the system for loading cheat database files in preparation for adding new features to the database file presentation. Also do a bunch of code cleanup and fix multiple bugs. - The file description is no longer limited to 16 characters. - Folder notes are now included in the description strings of exported cheat items. These can be important for cheats that include operating instructions in their associated folder notes. - Fix a bug where reading the last game entry of the database file would fail. - Fix a potential bug where reading a game entry from an encrypted database file would fail if the initial entry data resides very close to a 512-byte boundary. - Fix a bug where deleting a CHEATSEXPORT object without calling CHEATSEXPORT.close() would result in its associated file remaining open. - Fix a bug where deleting a CHEATSEXPORT object without calling CHEATSEXPORT.close() would result in CHEATSEXPORT.cheats leaking memory. --- desmume/src/cheatSystem.cpp | 1076 +++++++++++++---- desmume/src/cheatSystem.h | 189 ++- desmume/src/frontend/cocoa/cocoa_cheat.h | 13 +- desmume/src/frontend/cocoa/cocoa_cheat.mm | 48 +- .../src/frontend/cocoa/openemu/NDSGameCore.mm | 2 +- desmume/src/frontend/windows/cheatsWin.cpp | 6 +- 6 files changed, 1027 insertions(+), 307 deletions(-) diff --git a/desmume/src/cheatSystem.cpp b/desmume/src/cheatSystem.cpp index 811536a5e..ebf2ffe15 100755 --- a/desmume/src/cheatSystem.cpp +++ b/desmume/src/cheatSystem.cpp @@ -106,7 +106,7 @@ bool CHEATS::update(u8 size, u32 address, u32 val, char *description, bool enabl this->_list[pos].code[0][0] = address & 0x0FFFFFFF; this->_list[pos].code[0][1] = val; this->_list[pos].num = 1; - this->_list[pos].type = 0; + this->_list[pos].type = CHEAT_TYPE_INTERNAL; this->_list[pos].size = size; this->setDescription(description, pos); this->_list[pos].enabled = (enabled) ? 1 : 0; @@ -692,7 +692,7 @@ bool CHEATS::ARparser(const CHEATS_LIST &theList) size_t CHEATS::add_AR_Direct(const CHEATS_LIST &srcCheat) { const size_t itemIndex = this->addItem(srcCheat); - this->_list[itemIndex].type = 1; + this->_list[itemIndex].type = CHEAT_TYPE_AR; return itemIndex; } @@ -700,8 +700,6 @@ size_t CHEATS::add_AR_Direct(const CHEATS_LIST &srcCheat) bool CHEATS::add_AR(char *code, char *description, bool enabled) { bool didValidateItem = false; - - //if (num == MAX_CHEAT_LIST) return FALSE; size_t num = this->_list.size(); CHEATS_LIST temp; @@ -713,7 +711,7 @@ bool CHEATS::add_AR(char *code, char *description, bool enabled) } this->_list.push_back(temp); - this->_list[num].type = 1; + this->_list[num].type = CHEAT_TYPE_AR; this->setDescription(description, num); this->_list[num].enabled = (enabled) ? 1 : 0; @@ -750,7 +748,7 @@ bool CHEATS::update_AR(char *code, char *description, bool enabled, const size_t } this->setDescription(description, pos); - this->_list[pos].type = 1; + this->_list[pos].type = CHEAT_TYPE_AR; } this->_list[pos].enabled = (enabled) ? 1 : 0; @@ -767,8 +765,6 @@ bool CHEATS::update_AR(char *code, char *description, u8 enabled, const size_t p bool CHEATS::add_CB(char *code, char *description, bool enabled) { bool didValidateItem = false; - - //if (num == MAX_CHEAT_LIST) return FALSE; size_t num = this->_list.size(); CHEATS_LIST *cheatItem = this->getItemPtrAtIndex(num); @@ -783,7 +779,7 @@ bool CHEATS::add_CB(char *code, char *description, bool enabled) return didValidateItem; } - this->_list[num].type = 2; + this->_list[num].type = CHEAT_TYPE_CODEBREAKER; this->setDescription(description, num); this->_list[num].enabled = (enabled) ? 1 : 0; @@ -819,7 +815,7 @@ bool CHEATS::update_CB(char *code, char *description, bool enabled, const size_t return didValidateItem; } - this->_list[pos].type = 2; + this->_list[pos].type = CHEAT_TYPE_CODEBREAKER; this->setDescription(description, pos); } this->_list[pos].enabled = (enabled) ? 1 : 0; @@ -975,7 +971,7 @@ bool CHEATS::save() char buf2[10] = { 0 }; u32 adr = this->_list[i].code[t][0]; - if (this->_list[i].type == 0) + if (this->_list[i].type == CHEAT_TYPE_INTERNAL) { //size of the cheat is written out as adr highest nybble adr &= 0x0FFFFFFF; @@ -1068,17 +1064,17 @@ bool CHEATS::load() memset(&tmp_cht, 0, sizeof(tmp_cht)); if ((buf[0] == 'D') && (buf[1] == 'S')) // internal - tmp_cht.type = 0; + tmp_cht.type = CHEAT_TYPE_INTERNAL; else if ((buf[0] == 'A') && (buf[1] == 'R')) // Action Replay - tmp_cht.type = 1; + tmp_cht.type = CHEAT_TYPE_AR; else if ((buf[0] == 'B') && (buf[1] == 'S')) // Codebreaker - tmp_cht.type = 2; + tmp_cht.type = CHEAT_TYPE_CODEBREAKER; else continue; // TODO: CB not supported - if (tmp_cht.type == 3) + if (tmp_cht.type == CHEAT_TYPE_CODEBREAKER) { INFO("Cheats: Codebreaker code no supported at line %i\n", line); continue; @@ -1102,7 +1098,7 @@ bool CHEATS::load() } tmp_cht.num = (u32)codeStr.length() / 16; - if ((tmp_cht.type == 0) && (tmp_cht.num > 1)) + if ((tmp_cht.type == CHEAT_TYPE_INTERNAL) && (tmp_cht.num > 1)) { INFO("Cheats: Too many values for internal cheat\n", line); continue; @@ -1120,7 +1116,7 @@ bool CHEATS::load() continue; } - if (tmp_cht.type == 0) + if (tmp_cht.type == CHEAT_TYPE_INTERNAL) { tmp_cht.size = std::min(3, ((tmp_cht.code[i][0] & 0xF0000000) >> 28)); tmp_cht.code[i][0] &= 0x0FFFFFFF; @@ -1620,7 +1616,612 @@ void CHEATSEARCH::getListReset() } // ========================================================================= Export -void CHEATSEXPORT::R4decrypt(u8 *buf, const size_t len, u64 n) + +CheatDBGame* GetCheatDBGameEntryFromList(const CheatDBGameList &gameList, const char *gameCode, const u32 gameDatabaseCRC) +{ + CheatDBGame *outGameEntry = NULL; + + for (size_t i = 0; i < gameList.size(); i++) + { + const CheatDBGame &gameEntry = gameList[i]; + + if ( (gameDatabaseCRC == gameEntry.GetCRC()) && !memcmp(gameCode, gameEntry.GetSerial(), 4) ) + { + outGameEntry = (CheatDBGame *)&gameEntry; + break; + } + } + + return outGameEntry; +} + +void CheatItemGenerateDescriptionHierarchical(const char *itemName, const char *itemNote, CHEATS_LIST &outCheatItem) +{ + if (itemName != NULL) + { + strncpy(outCheatItem.descriptionMajor, itemName, sizeof(outCheatItem.descriptionMajor)); + outCheatItem.descriptionMajor[sizeof(outCheatItem.descriptionMajor) - 1] = '\0'; + } + + if (itemNote != NULL) + { + strncpy(outCheatItem.descriptionMinor, itemNote, sizeof(outCheatItem.descriptionMinor)); + outCheatItem.descriptionMinor[sizeof(outCheatItem.descriptionMinor) - 1] = '\0'; + } +} + +void CheatItemGenerateDescriptionFlat(const char *folderName, const char *folderNote, const char *itemName, const char *itemNote, CHEATS_LIST &outCheatItem) +{ + std::string descriptionStr = ""; + + if ( (folderName != NULL) && (*folderName != '\0') ) + { + descriptionStr += folderName; + } + + if ( (folderNote != NULL) && (*folderNote != '\0') ) + { + if ( (folderName != NULL) && (*folderName != '\0') ) + { + descriptionStr += " "; + } + + descriptionStr += "["; + descriptionStr += folderNote; + descriptionStr += "]"; + } + + if ( ((folderName != NULL) && (*folderName != '\0')) || + ((folderNote != NULL) && (*folderNote != '\0')) ) + { + descriptionStr += ": "; + } + + if ( (itemName != NULL) && (*itemName != '\0') ) + { + descriptionStr += itemName; + } + + if ( (itemNote != NULL) && (*itemNote != '\0') ) + { + if ( (itemName != NULL) && (*itemName != '\0') ) + { + descriptionStr += " | "; + } + + descriptionStr += itemNote; + } + + strncpy(outCheatItem.description, descriptionStr.c_str(), sizeof(outCheatItem.description)); + outCheatItem.description[sizeof(outCheatItem.description) - 1] = '\0'; +} + +CheatDBGame::CheatDBGame() +{ + _baseOffset = 0; + _firstEntryOffset = 0; + _encryptOffset = 0; + + _dataSize = 0; + _crc = 0; + _entryCount = 0; + + _title = ""; + memset(_serial, 0, sizeof(_serial)); + + _entryDataRawPtr = NULL; + _entryData = NULL; + + _entryRoot.base = NULL; + _entryRoot.name = NULL; + _entryRoot.note = NULL; + _entryRoot.codeLength = NULL; + _entryRoot.codeData = NULL; + _entryRoot.child.resize(0); + _entryRoot.parent = NULL; + + _cheatItemCount = 0; +} + +CheatDBGame::CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize) +{ + CheatDBGame::SetInitialProperties(dataSize, encryptOffset, fat); + + _firstEntryOffset = 0; + _entryCount = 0; + _title = ""; + + _entryDataRawPtr = NULL; + _entryData = NULL; + + _entryRoot.base = NULL; + _entryRoot.name = NULL; + _entryRoot.note = NULL; + _entryRoot.codeLength = NULL; + _entryRoot.codeData = NULL; + _entryRoot.child.resize(0); + _entryRoot.parent = NULL; + + _cheatItemCount = 0; +} + +CheatDBGame::CheatDBGame(FILE *fp, const bool isEncrypted, const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize, u8 (&workingBuffer)[1024]) +{ + CheatDBGame::SetInitialProperties(dataSize, encryptOffset, fat); + CheatDBGame::LoadPropertiesFromFile(fp, isEncrypted, workingBuffer); + + _entryDataRawPtr = NULL; + _entryData = NULL; + + _entryRoot.base = NULL; + _entryRoot.name = NULL; + _entryRoot.note = NULL; + _entryRoot.codeLength = NULL; + _entryRoot.codeData = NULL; + _entryRoot.child.resize(0); + _entryRoot.parent = NULL; + + _cheatItemCount = 0; +} + +CheatDBGame::~CheatDBGame() +{ + if (this->_entryDataRawPtr != NULL) + { + free(this->_entryDataRawPtr); + this->_entryDataRawPtr = NULL; + this->_entryData = NULL; + } +} + +void CheatDBGame::SetInitialProperties(const u32 dataSize, const u32 encryptOffset, const FAT_R4 &fat) +{ + _dataSize = dataSize; + _encryptOffset = encryptOffset; + _baseOffset = (u32)fat.addr; + _crc = fat.CRC; + _serial[0] = fat.serial[0]; + _serial[1] = fat.serial[1]; + _serial[2] = fat.serial[2]; + _serial[3] = fat.serial[3]; + _serial[4] = '\0'; +} + +void CheatDBGame::LoadPropertiesFromFile(FILE *fp, const bool isEncrypted, u8 (&workingBuffer)[1024]) +{ + const size_t gameDataBufferSize = (_dataSize < sizeof(workingBuffer)) ? _dataSize : sizeof(workingBuffer); + CheatDBFile::ReadToBuffer(fp, _baseOffset, isEncrypted, _encryptOffset, gameDataBufferSize, workingBuffer); + + const u8 *gameDataBuffer = workingBuffer + _encryptOffset; + const char *gameTitlePtrInBuffer = (const char *)gameDataBuffer; + _title = gameTitlePtrInBuffer; + + const u32 offsetMask = ~(u32)0x00000003; + const u32 entryCountOffset = (_baseOffset + (u32)strlen(gameTitlePtrInBuffer) + 4) & offsetMask; + _entryCount = *(u32 *)(gameDataBuffer + entryCountOffset - _baseOffset); + _firstEntryOffset = entryCountOffset + 36; +} + +u32 CheatDBGame::GetBaseOffset() const +{ + return this->_baseOffset; +} + +u32 CheatDBGame::GetFirstEntryOffset() const +{ + return this->_firstEntryOffset; +} + +u32 CheatDBGame::GetEncryptOffset() const +{ + return this->_encryptOffset; +} + +u32 CheatDBGame::GetDataSize() const +{ + return this->_dataSize; +} + +u32 CheatDBGame::GetCRC() const +{ + return this->_crc; +} + +u32 CheatDBGame::GetEntryCount() const +{ + return this->_entryCount; +} + +u32 CheatDBGame::GetCheatItemCount() const +{ + return this->_cheatItemCount; +} + +const char* CheatDBGame::GetTitle() const +{ + return this->_title.c_str(); +} + +const char* CheatDBGame::GetSerial() const +{ + return this->_serial; +} + +const CheatDBEntry& CheatDBGame::GetEntryRoot() const +{ + return this->_entryRoot; +} + +const u8* CheatDBGame::GetEntryRawData() const +{ + return this->_entryData; +} + +bool CheatDBGame::IsEntryDataLoaded() const +{ + return (this->_entryData != NULL); +} + +void CheatDBGame::_UpdateDirectoryParents(CheatDBEntry &directory) +{ + const size_t directoryItemCount = directory.child.size(); + + for (size_t i = 0; i < directoryItemCount; i++) + { + CheatDBEntry &entry = directory.child[i]; + entry.parent = &directory; + + const u32 entryValue = *(u32 *)entry.base; + const bool isFolder = ((entryValue & 0xF0000000) == 0x10000000); + + if (isFolder) + { + this->_UpdateDirectoryParents(entry); + } + } +} + +u8* CheatDBGame::LoadEntryData(FILE *fp, const bool isEncrypted) +{ + this->_cheatItemCount = 0; + + this->_entryRoot.base = NULL; + this->_entryRoot.name = NULL; + this->_entryRoot.note = NULL; + this->_entryRoot.codeLength = NULL; + this->_entryRoot.codeData = NULL; + this->_entryRoot.child.resize(0); + this->_entryRoot.parent = NULL; + + if (this->_entryDataRawPtr != NULL) + { + free(this->_entryDataRawPtr); + this->_entryDataRawPtr = NULL; + this->_entryData = NULL; + } + + this->_entryDataRawPtr = (u8 *)malloc(this->_dataSize + 8); + memset(this->_entryDataRawPtr, 0, this->_dataSize + 8); + + bool didReadSuccessfully = CheatDBFile::ReadToBuffer(fp, this->_baseOffset, isEncrypted, this->_encryptOffset, this->_dataSize, this->_entryDataRawPtr); + if (!didReadSuccessfully) + { + free(this->_entryDataRawPtr); + this->_entryDataRawPtr = NULL; + this->_entryData = NULL; + + return this->_entryData; + } + + this->_entryData = this->_entryDataRawPtr + this->_encryptOffset; + this->_entryRoot.base = this->_entryData; + this->_entryRoot.name = (char *)this->_entryRoot.base; + + CheatDBEntry *currentDirectory = &this->_entryRoot; + u32 currentDirectoryItemCount = 0; + std::vector directoryItemCountList; + + CheatDBEntry tempEntry; + tempEntry.name = NULL; + tempEntry.note = NULL; + tempEntry.base = NULL; + tempEntry.codeLength = NULL; + tempEntry.codeData = NULL; + tempEntry.parent = NULL; + tempEntry.child.resize(0); + + const uintptr_t ptrMask = ~(uintptr_t)0x00000003; + u32 *cmd = (u32 *)(this->_entryData + this->_firstEntryOffset - this->_baseOffset); + + for (size_t i = 0; i < this->_entryCount; i++) + { + const u32 entryValue = *cmd; + const bool isFolder = ((entryValue & 0xF0000000) == 0x10000000); + + currentDirectory->child.push_back(tempEntry); + CheatDBEntry &newEntry = currentDirectory->child.back(); + newEntry.parent = currentDirectory; + + const u32 baseOffset = (u32)((uintptr_t)cmd - (uintptr_t)this->_entryData); + newEntry.base = this->_entryData + baseOffset; + + const u32 nameOffset = baseOffset + 4; + newEntry.name = (char *)(this->_entryData + nameOffset); + + const u32 noteOffset = nameOffset + (u32)strlen(newEntry.name) + 1; + newEntry.note = (char *)(this->_entryData + noteOffset); + + if (isFolder) + { + newEntry.codeLength = NULL; + newEntry.codeData = NULL; + cmd = (u32 *)( ((uintptr_t)newEntry.note + strlen(newEntry.note) + 1 + 3) & ptrMask ); + + const u32 entryCount = entryValue & 0x00FFFFFF; + + if (entryCount > 0) + { + // Reserve the memory now to avoid std::vector from doing any memory + // reallocations that would mess up the parent pointers. + newEntry.child.reserve(entryCount); + + if (currentDirectoryItemCount > 1) + { + currentDirectoryItemCount--; + directoryItemCountList.push_back(currentDirectoryItemCount); + } + } + + currentDirectoryItemCount = entryCount; + currentDirectory = &newEntry; + } + else + { + const u32 codeLengthOffset = (noteOffset + (u32)strlen(newEntry.note) + 1 + 3) & 0xFFFFFFFC; + newEntry.codeLength = (u32 *)(this->_entryData + codeLengthOffset); + + const u32 codeDataOffset = codeLengthOffset + 4; + newEntry.codeData = (u32 *)(this->_entryData + codeDataOffset); + + const u32 entrySize = (entryValue & 0x00FFFFFF) + 1; // Note that this does not represent bytes, but the number of 32-bit chunks. + cmd += entrySize; + + if (currentDirectory == &this->_entryRoot) + { + // If a cheat item exists at the base level of the tree, then we need to + // add each cheat item individually. + currentDirectoryItemCount = 1; + } + + currentDirectoryItemCount--; + this->_cheatItemCount++; + } + + if (currentDirectoryItemCount == 0) + { + currentDirectory = currentDirectory->parent; + if (currentDirectory == NULL) + { + currentDirectory = &this->_entryRoot; + } + + if (directoryItemCountList.size() > 0) + { + currentDirectoryItemCount = directoryItemCountList.back(); + directoryItemCountList.pop_back(); + } + } + } + + // Child items of directories are implemented as std::vectors, which can move their + // elements around in memory as items are added to the vector. This means that parent + // pointers are undoubtedly broken at this point. Therefore, we need to update the + // parent pointers now so that all relationships are properly set. + // + // Note that any additions or removals to elements in this->_entryRoot will result in + // broken parent pointers, and so we must assume that this->_entryRoot is immutable + // at this point. Considering that the purpose of this->_entryRoot is supposed to be + // a glorified wrapper to this->_entryData, which itself is immutable, the + // immutability of this->_entryRoot is deemed acceptable. + this->_UpdateDirectoryParents(this->_entryRoot); + + return this->_entryData; +} + +bool CheatDBGame::_CreateCheatItemFromCheatEntry(const CheatDBEntry &inEntry, const bool isHierarchical, CHEATS_LIST &outCheatItem) +{ + bool didParseCheatEntry = false; + + if (inEntry.codeLength == NULL) + { + return didParseCheatEntry; + } + + u32 codeCount = *inEntry.codeLength / 2; + if (codeCount > MAX_XX_CODE) + { + return didParseCheatEntry; + } + + if (isHierarchical) + { + CheatItemGenerateDescriptionHierarchical(inEntry.name, inEntry.note, outCheatItem); + } + else + { + const char *folderName = ( (inEntry.parent != NULL) && (inEntry.parent != &this->_entryRoot) ) ? inEntry.parent->name : NULL; + const char *folderNote = ( (inEntry.parent != NULL) && (inEntry.parent != &this->_entryRoot) ) ? inEntry.parent->note : NULL; + + CheatItemGenerateDescriptionFlat(folderName, folderNote, inEntry.name, inEntry.note, outCheatItem); + } + + outCheatItem.num = codeCount; + outCheatItem.type = CHEAT_TYPE_AR; + + for (size_t j = 0, t = 0; j < codeCount; j++, t+=2) + { + outCheatItem.code[j][0] = *(inEntry.codeData + t + 0); + outCheatItem.code[j][1] = *(inEntry.codeData + t + 1); + } + + didParseCheatEntry = true; + return didParseCheatEntry; +} + +size_t CheatDBGame::_DirectoryAddCheatsFlat(const CheatDBEntry &directory, const bool isHierarchical, size_t cheatIndex, CHEATS_LIST *outCheatsList) +{ + size_t cheatCount = 0; + if (outCheatsList == NULL) + { + return cheatCount; + } + + const size_t directoryItemCount = directory.child.size(); + for (size_t i = 0; i < directoryItemCount; i++) + { + const CheatDBEntry &entry = directory.child[i]; + const u32 entryValue = *(u32 *)entry.base; + const bool isFolder = ((entryValue & 0xF0000000) == 0x10000000); + + if (isFolder) + { + const size_t addedCount = this->_DirectoryAddCheatsFlat(entry, isHierarchical, cheatIndex, outCheatsList); + cheatCount += addedCount; + cheatIndex += addedCount; + } + else + { + CHEATS_LIST &outCheat = outCheatsList[cheatIndex]; + + const bool didParseCheatEntry = this->_CreateCheatItemFromCheatEntry(entry, isHierarchical, outCheat); + if (!didParseCheatEntry) + { + continue; + } + + cheatIndex++; + cheatCount++; + } + } + + return cheatCount; +} + +size_t CheatDBGame::ParseEntriesToCheatsListFlat(CHEATS_LIST *outCheatsList) +{ + return this->_DirectoryAddCheatsFlat(this->_entryRoot, false, 0, outCheatsList); +} + +CheatDBFile::CheatDBFile() +{ + _path = ""; + _description = ""; + + _type = CHEATS_DB_R4; + _isEncrypted = false; + _size = 0; + _fp = NULL; +} + +CheatDBFile::~CheatDBFile() +{ + this->CloseFile(); +} + +FILE* CheatDBFile::GetFilePtr() const +{ + return this->_fp; +} + +bool CheatDBFile::IsEncrypted() const +{ + return this->_isEncrypted; +} + +const char* CheatDBFile::GetDescription() const +{ + return this->_description.c_str(); +} + +int CheatDBFile::OpenFile(const char *filePath) +{ + int error = 0; + + this->_fp = fopen(filePath, "rb"); + if (this->_fp == NULL) + { + printf("ERROR: Failed to open the cheat database.\n"); + error = 1; + return error; + } + + // Determine the file's total size. + fseek(this->_fp, 0, SEEK_END); + this->_size = ftell(this->_fp); + + // Validate the file header before doing anything else. At this time, + // we will also be determining the file's encryption status. + const char *headerID = "R4 CheatCode"; + if (this->_size < strlen(headerID)) + { + printf("ERROR: Failed to validate the file header.\n"); + error = 2; + return error; + } + + if (this->_size < CHEATDB_FILEOFFSET_FIRST_FAT_ENTRY) + { + printf("ERROR: No FAT entries found.\n"); + error = 2; + return error; + } + + // Read the file header. + u8 workingBuffer[512] = {0}; + fseek(this->_fp, 0, SEEK_SET); + const size_t headerReadSize = (this->_size < 512) ? this->_size : 512; + fread(workingBuffer, 1, headerReadSize, this->_fp); + + if (strncmp((char *)workingBuffer, headerID, strlen(headerID)) != 0) + { + // Try checking the file header again, assuming that the file is + // encrypted this time. + CheatDBFile::R4Decrypt(workingBuffer, headerReadSize, 0); + if (strncmp((char *)workingBuffer, headerID, strlen(headerID)) != 0) + { + // Whether the file is encrypted or unencrypted, the file + // header failed validation. Therefore, the file will be + // closed and we will bail out now. + fclose(this->_fp); + this->_fp = NULL; + + printf("ERROR: Failed to validate the file header.\n"); + error = 2; + return error; + } + + // File header validation passed, but did so only because we + // decrypted the header first, so mark the file as encrypted + // for future operations. + this->_isEncrypted = true; + } + + this->_description = (const char *)(workingBuffer + CHEATDB_OFFSET_FILE_DESCRIPTION); + this->_path = filePath; + + return error; +} + +void CheatDBFile::CloseFile() +{ + if (this->_fp != NULL) + { + fclose(this->_fp); + this->_fp = NULL; + } +} + +void CheatDBFile::R4Decrypt(u8 *buf, const size_t len, u64 n) { size_t r = 0; while (r < len) @@ -1668,247 +2269,272 @@ void CHEATSEXPORT::R4decrypt(u8 *buf, const size_t len, u64 n) } } -bool CHEATSEXPORT::load(char *path) +bool CheatDBFile::ReadToBuffer(FILE *fp, const size_t fileOffset, + const bool isEncrypted, const size_t encryptOffset, + const size_t requestedSize, u8 *outBuffer) { - error = 0; - - fp = fopen(path, "rb"); - if (!fp) + bool didReadSuccessfully = false; + + if ( (fp == NULL) || (outBuffer == NULL) ) { - printf("Error open database\n"); - error = 1; - return false; - } - - const char *headerID = "R4 CheatCode"; - char buf[255] = {0}; - fread(buf, 1, strlen(headerID), fp); - if (strncmp(buf, headerID, strlen(headerID)) != 0) - { - // check encrypted - R4decrypt((u8 *)buf, strlen(headerID), 0); - if (strcmp(buf, headerID) != 0) - { - error = 2; - return false; - } - encrypted = true; - } - - fseek(fp, 0, SEEK_END); - fsize = ftell(fp); - fseek(fp, 0, SEEK_SET); - - if (!search()) - { - printf("ERROR: cheat in database not found\n"); - error = 3; - return false; + return didReadSuccessfully; } - if (!getCodes()) + fseek(fp, fileOffset - encryptOffset, SEEK_SET); + + const size_t readSize = fread(outBuffer, 1, requestedSize, fp); + if (readSize != requestedSize) { - printf("ERROR: export cheats failed\n"); - error = 4; - return false; + return didReadSuccessfully; } - return true; -} -void CHEATSEXPORT::close() -{ - if (fp) - fclose(fp); - if (cheats) + if (isEncrypted) { - delete [] cheats; - cheats = NULL; + CheatDBFile::R4Decrypt(outBuffer, requestedSize, fileOffset >> 9); } + + didReadSuccessfully = true; + return didReadSuccessfully; } -bool CHEATSEXPORT::search() +CheatDBGame CheatDBFile::_ReadGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 gameDataSize, u8 (&workingBuffer)[1024]) { - if (!fp) return false; + return CheatDBGame(this->_fp, this->_isEncrypted, encryptOffset, fat, gameDataSize, workingBuffer); +} - u32 pos = 0x0100; - FAT_R4 fat_tmp = {0}; - u8 buf[512] = {0}; - - CRC = 0; - encOffset = 0; +u32 CheatDBFile::LoadGameList(const char *gameCode, const u32 gameDatabaseCRC, CheatDBGameList &outList) +{ + u32 entryCount = 0; + if (this->_fp == NULL) + { + return entryCount; + } + + // If gameCode is NULL, then we're going to assume that the entire + // game list will be rebuilt from scratch. + if (gameCode == NULL) + { + outList.resize(0); + } + + u8 fatBuffer[512] = {0}; + u8 gameEntryBuffer[1024] = {0}; + u32 pos = CHEATDB_FILEOFFSET_FIRST_FAT_ENTRY; u64 t = 0; - memset(date, 0, sizeof(date)); - if (encrypted) + FAT_R4 fatEntryCurrent = {0}; + FAT_R4 fatEntryNext = {0}; + + if (this->_isEncrypted) { - fseek(fp, 0, SEEK_SET); - fread(&buf[0], 1, 512, fp); - R4decrypt((u8 *)&buf[0], 512, 0); - memcpy(&date[0], &buf[0x10], 16); + fseek(this->_fp, 0, SEEK_SET); + fread(fatBuffer, 1, 512, this->_fp); + CheatDBFile::R4Decrypt(fatBuffer, 512, 0); } else { - fseek(fp, 0x10, SEEK_SET); - fread(&date, 16, 1, fp); - fseek(fp, pos, SEEK_SET); - fread(&fat_tmp, sizeof(fat), 1, fp); + fseek(this->_fp, pos, SEEK_SET); + fread(&fatEntryNext, sizeof(fatEntryNext), 1, this->_fp); } - + do { - if (encrypted) + if (this->_isEncrypted) { - memcpy(&fat, &buf[pos % 512], sizeof(fat)); - pos += sizeof(fat); - if ((pos>>9) > t) + memcpy(&fatEntryCurrent, &fatBuffer[pos % 512], sizeof(fatEntryCurrent)); + pos += sizeof(fatEntryCurrent); + if ((pos >> 9) > t) { t++; - fread(&buf[0], 1, 512, fp); - R4decrypt((u8 *)&buf[0], 512, t); + fread(fatBuffer, 1, 512, this->_fp); + CheatDBFile::R4Decrypt(fatBuffer, 512, t); } - memcpy(&fat_tmp, &buf[pos % 512], sizeof(fat_tmp)); // next + memcpy(&fatEntryNext, &fatBuffer[pos % 512], sizeof(fatEntryNext)); } else { - memcpy(&fat, &fat_tmp, sizeof(fat)); - fread(&fat_tmp, sizeof(fat_tmp), 1, fp); - - } - //printf("serial: %s, offset %08X\n", fat.serial, fat.addr); - if (gameInfo.crcForCheatsDb == fat.CRC - && !memcmp(gameInfo.header.gameCode, &fat.serial[0], 4)) - { - dataSize = fat_tmp.addr ? (fat_tmp.addr - fat.addr) : 0; - if (encrypted) - { - encOffset = fat.addr % 512; - dataSize += encOffset; - } - if (!dataSize) return false; - CRC = fat.CRC; - char serialBuf[5] = {0}; - memcpy(&serialBuf, &fat.serial[0], 4); - printf("Cheats: found %s CRC %08X at 0x%08llX, size %llu byte(s)\n", serialBuf, fat.CRC, fat.addr, (unsigned long long)(dataSize - encOffset)); - return true; - } - - } while (fat.addr > 0); - - memset(&fat, 0, sizeof(FAT_R4)); - return false; -} - -bool CHEATSEXPORT::getCodes() -{ - if (!fp) return false; - - u32 pos = 0; - u32 pos_cht = 0; - - u8 *data = new u8 [dataSize+8]; - if (!data) return false; - memset(data, 0, dataSize+8); - - fseek(fp, fat.addr - encOffset, SEEK_SET); - - if (fread(data, 1, dataSize, fp) != dataSize) - { - delete [] data; - data = NULL; - return false; - } - - if (encrypted) - R4decrypt(data, dataSize, fat.addr >> 9); - - uintptr_t ptrMask = ~(uintptr_t)0 << 2; - u8 *gameTitlePtr = (u8 *)data + encOffset; - - memset(gametitle, 0, CHEAT_DB_GAME_TITLE_SIZE); - memcpy(gametitle, gameTitlePtr, strlen((const char *)gameTitlePtr)); - - u32 *cmd = (u32 *)(((uintptr_t)gameTitlePtr + strlen((const char *)gameTitlePtr) + 4) & ptrMask); - numCheats = cmd[0] & 0x0FFFFFFF; - cmd += 9; - cheats = new CHEATS_LIST[numCheats]; - memset(cheats, 0, sizeof(CHEATS_LIST) * numCheats); - - while (pos < numCheats) - { - u32 folderNum = 1; - u8 *folderName = NULL; - u8 *folderNote = NULL; - if ((*cmd & 0xF0000000) == 0x10000000) // Folder - { - folderNum = (*cmd & 0x00FFFFFF); - folderName = (u8*)((uintptr_t)cmd + 4); - folderNote = (u8*)((uintptr_t)folderName + strlen((char*)folderName) + 1); - pos++; - cmd = (u32 *)(((uintptr_t)folderName + strlen((char*)folderName) + 1 + strlen((char*)folderNote) + 1 + 3) & ptrMask); - } - - for (u32 i = 0; i < folderNum; i++) // in folder - { - u8 *cheatName = (u8 *)((uintptr_t)cmd + 4); - u8 *cheatNote = (u8 *)((uintptr_t)cheatName + strlen((char*)cheatName) + 1); - u32 *cheatData = (u32 *)(((uintptr_t)cheatNote + strlen((char*)cheatNote) + 1 + 3) & ptrMask); - u32 cheatDataLen = *cheatData++; - u32 numberCodes = cheatDataLen / 2; - - if (numberCodes <= MAX_XX_CODE) - { - std::string descriptionStr = ""; - - if ( folderName && *folderName ) - { - descriptionStr += (char *)folderName; - descriptionStr += ": "; - } - - descriptionStr += (char *)cheatName; - - if ( cheatNote && *cheatNote ) - { - descriptionStr += " | "; - descriptionStr += (char *)cheatNote; - } - - strncpy(cheats[pos_cht].description, descriptionStr.c_str(), sizeof(cheats[pos_cht].description)); - cheats[pos_cht].description[sizeof(cheats[pos_cht].description) - 1] = '\0'; - - cheats[pos_cht].num = numberCodes; - cheats[pos_cht].type = 1; - - for(u32 j = 0, t = 0; j < numberCodes; j++, t+=2 ) - { - cheats[pos_cht].code[j][0] = (u32)*(cheatData+t); - //printf("%i: %08X ", j, cheats[pos_cht].code[j][0]); - cheats[pos_cht].code[j][1] = (u32)*(cheatData+t+1); - //printf("%08X\n", cheats[pos_cht].code[j][1]); - - } - pos_cht++; - } - - pos++; - cmd = (u32 *)((uintptr_t)cmd + ((*cmd + 1)*4)); + memcpy(&fatEntryCurrent, &fatEntryNext, sizeof(fatEntryNext)); + pos += sizeof(fatEntryNext); + fseek(this->_fp, pos, SEEK_SET); + fread(&fatEntryNext, sizeof(fatEntryNext), 1, this->_fp); } - }; - - delete [] data; - - numCheats = pos_cht; - //for (int i = 0; i < numCheats; i++) - // printf("%i: %s\n", i, cheats[i].description); + u32 encryptOffset = 0; + u32 dataSize = 0; + + if (fatEntryNext.addr > 0) + { + dataSize = (u32)(fatEntryNext.addr - fatEntryCurrent.addr); + } + else + { + // For the last game entry, use whatever remaining data there is in the + // file for the data size. However, we don't know how much extraneous + // data may exist, so limit the data size to 1 MB, which should be more + // than enough to account for all of the game entry data. + dataSize = (u32)(this->_size - fatEntryCurrent.addr); + if (dataSize > (1024 * 1024)) + { + dataSize = 1024 * 1024; + } + } + + if (this->_isEncrypted) + { + encryptOffset = (u32)(fatEntryCurrent.addr % 512); + dataSize += encryptOffset; + } + + if (dataSize == 0) + { + continue; + } + + // If gameCode is provided, then this method will search the file for the first matching + // serial and CRC, and then stop searching, adding only a single entry to the game list. + // If all you need is a limited number of games (or just one game), then using this + // method is a CPU and memory efficient means to get an entry from game list. + // + // If gameCode is NULL, then this method will add all game entries from the database file + // to the game list. This will consume more CPU cycles and memory, but having the entire + // game list in memory can be useful for clients that allow for database browsing. + if (gameCode != NULL) + { + if ( (gameDatabaseCRC == fatEntryCurrent.CRC) && !memcmp(gameCode, fatEntryCurrent.serial, 4) ) + { + CheatDBGame *foundGameEntry = GetCheatDBGameEntryFromList(outList, gameCode, gameDatabaseCRC); + if (foundGameEntry == NULL) + { + // Only add to the game list if the entry has not been added yet. + outList.push_back( this->_ReadGame(encryptOffset, fatEntryCurrent, dataSize, gameEntryBuffer) ); + } + + entryCount = 1; + return entryCount; + } + } + else + { + outList.push_back( this->_ReadGame(encryptOffset, fatEntryCurrent, dataSize, gameEntryBuffer) ); + } + + } while (fatEntryNext.addr > 0); - return true; + return entryCount; } -CHEATS_LIST *CHEATSEXPORT::getCheats() +CHEATSEXPORT::CHEATSEXPORT() { - return cheats; + _selectedDbGame = NULL; + _cheats = NULL; + _error = 0; } -u32 CHEATSEXPORT::getCheatsNum() + +CHEATSEXPORT::~CHEATSEXPORT() { - return numCheats; + this->close(); +} + +bool CHEATSEXPORT::load(const char *path) +{ + bool didLoadSucceed = false; + + this->_error = this->_dbFile.OpenFile(path); + if (this->_error != 0) + { + return didLoadSucceed; + } + + CheatDBGameList gameList; + this->_dbFile.LoadGameList(gameInfo.header.gameCode, gameInfo.crcForCheatsDb, gameList); + CheatDBGame *dbGamePtr = GetCheatDBGameEntryFromList(gameList, gameInfo.header.gameCode, gameInfo.crcForCheatsDb); + + if (dbGamePtr == NULL) + { + const char gameCodeString[5] = { + gameInfo.header.gameCode[0], + gameInfo.header.gameCode[1], + gameInfo.header.gameCode[2], + gameInfo.header.gameCode[3], + '\0' + }; + + printf("ERROR: Cheat for game code '%s' not found in database.\n", gameCodeString); + this->_error = 3; + return didLoadSucceed; + } + + u8 *dbGameBuffer = dbGamePtr->LoadEntryData(this->_dbFile.GetFilePtr(), this->_dbFile.IsEncrypted()); + if (dbGameBuffer == NULL) + { + printf("ERROR: Failed to read game entries from file.\n"); + this->_error = 1; + return didLoadSucceed; + } + + if (this->_cheats != NULL) + { + free(this->_cheats); + } + + this->_cheats = (CHEATS_LIST *)malloc( sizeof(CHEATS_LIST) * dbGamePtr->GetEntryCount() ); + memset(this->_cheats, 0, sizeof(CHEATS_LIST) * dbGamePtr->GetEntryCount()); + + const size_t parsedCheatCount = dbGamePtr->ParseEntriesToCheatsListFlat(this->_cheats); + if (parsedCheatCount == 0) + { + printf("ERROR: export cheats failed\n"); + this->_error = 4; + return didLoadSucceed; + } + + this->_selectedDbGame = dbGamePtr; + + didLoadSucceed = true; + return didLoadSucceed; +} + +void CHEATSEXPORT::close() +{ + this->_dbFile.CloseFile(); + + if (this->_cheats != NULL) + { + free(this->_cheats); + this->_cheats = NULL; + } +} + +CHEATS_LIST *CHEATSEXPORT::getCheats() const +{ + return this->_cheats; +} + +size_t CHEATSEXPORT::getCheatsNum() const +{ + if (this->_selectedDbGame == NULL) + { + return 0; + } + + return (size_t)this->_selectedDbGame->GetCheatItemCount(); +} + +const char* CHEATSEXPORT::getGameTitle() const +{ + if (this->_selectedDbGame == NULL) + { + return ""; + } + + return this->_selectedDbGame->GetTitle(); +} + +const char* CHEATSEXPORT::getDescription() const +{ + return (const char *)this->_dbFile.GetDescription(); +} + +u8 CHEATSEXPORT::getErrorCode() const +{ + return this->_error; } diff --git a/desmume/src/cheatSystem.h b/desmume/src/cheatSystem.h index 4c74451c0..d73f0edf4 100755 --- a/desmume/src/cheatSystem.h +++ b/desmume/src/cheatSystem.h @@ -24,10 +24,8 @@ #define CHEAT_VERSION_MAJOR 2 #define CHEAT_VERSION_MINOR 0 -#define MAX_CHEAT_LIST 100 #define MAX_XX_CODE 1024 #define CHEAT_FILE_MIN_FGETS_BUFFER 32768 -#define CHEAT_DB_GAME_TITLE_SIZE 256 #define CHEAT_TYPE_EMPTY 0xFF #define CHEAT_TYPE_INTERNAL 0 @@ -39,7 +37,7 @@ struct CHEATS_LIST CHEATS_LIST() { memset(this,0,sizeof(*this)); - type = 0xFF; + type = CHEAT_TYPE_EMPTY; } u8 type; u8 enabled; @@ -48,7 +46,18 @@ struct CHEATS_LIST // 1 - can decrease // 2 - can increase u32 code[MAX_XX_CODE][2]; - char description[1024]; + + union + { + char description[1024]; + + struct + { + char descriptionMajor[512]; + char descriptionMinor[512]; + }; + }; + u32 num; u8 size; }; @@ -151,71 +160,153 @@ public: void getListReset(); }; +#define CHEATDB_OFFSET_FILE_DESCRIPTION 0x00000010 +#define CHEATDB_FILEOFFSET_FIRST_FAT_ENTRY 0x00000100 + enum CHEATS_DB_TYPE { CHEATS_DB_R4 = 0 }; +// This struct maps to the FAT entries in the R4 cheat database file. #pragma pack(push) #pragma pack(1) typedef struct FAT_R4 { - u8 serial[4]; - u32 CRC; + u8 serial[4]; + u32 CRC; u64 addr; } FAT_R4; #pragma pack(pop) +// Wrapper for a single entry in a memory block that contains data read from a cheat database file. +// This struct also maintains the hierarchical relationships between entries. +struct CheatDBEntry +{ + u8 *base; // Pointer to the entry's base location in memory. + char *name; // Pointer to the entry's name string. + char *note; // Pointer to the entry's note string. + u32 *codeLength; // Pointer to the entry's 32-bit code length in bytes. This value is NULL if the entry is a directory. + u32 *codeData; // Pointer to the entry's code data, provided in pairs of 32-bit values. This value is NULL if the entry is a directory. + + CheatDBEntry *parent; + std::vector child; +}; +typedef struct CheatDBEntry CheatDBEntry; + +class CheatDBGame +{ +protected: + u32 _baseOffset; // This offset is relative to the file head. + u32 _firstEntryOffset; // This offset is relative to the file head. + u32 _encryptOffset; // This offset is relative to the memory address of this->_entryDataRawPtr. + + u32 _dataSize; + u32 _crc; + u32 _entryCount; + + std::string _title; + char _serial[4 + 1]; + + u8 *_entryDataRawPtr; + u8 *_entryData; + CheatDBEntry _entryRoot; + u32 _cheatItemCount; + + void _UpdateDirectoryParents(CheatDBEntry &directory); + bool _CreateCheatItemFromCheatEntry(const CheatDBEntry &inEntry, const bool isHierarchical, CHEATS_LIST &outCheatItem); + size_t _DirectoryAddCheatsFlat(const CheatDBEntry &directory, const bool isHierarchical, size_t cheatIndex, CHEATS_LIST *outCheatsList); + +public: + CheatDBGame(); + CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize); + CheatDBGame(FILE *fp, const bool isEncrypted, const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize, u8 (&workingBuffer)[1024]); + ~CheatDBGame(); + + void SetInitialProperties(const u32 dataSize, const u32 encryptOffset, const FAT_R4 &fat); + void LoadPropertiesFromFile(FILE *fp, const bool isEncrypted, u8 (&workingBuffer)[1024]); + + u32 GetBaseOffset() const; + u32 GetFirstEntryOffset() const; + u32 GetEncryptOffset() const; + u32 GetDataSize() const; + u32 GetCRC() const; + u32 GetEntryCount() const; + u32 GetCheatItemCount() const; + const char* GetTitle() const; + const char* GetSerial() const; + + const CheatDBEntry& GetEntryRoot() const; + const u8* GetEntryRawData() const; + bool IsEntryDataLoaded() const; + + u8* LoadEntryData(FILE *fp, const bool isEncrypted); + size_t ParseEntriesToCheatsListFlat(CHEATS_LIST *outCheatsList); +}; + +typedef std::vector CheatDBGameList; + +class CheatDBFile +{ +protected: + std::string _path; + std::string _description; + + CHEATS_DB_TYPE _type; + bool _isEncrypted; + size_t _size; + + FILE *_fp; + + CheatDBGame _ReadGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 gameDataSize, u8 (&workingBuffer)[1024]); + +public: + CheatDBFile(); + ~CheatDBFile(); + + static void R4Decrypt(u8 *buf, const size_t len, u64 n); + static bool ReadToBuffer(FILE *fp, const size_t fileOffset, const bool isEncrypted, const size_t encryptOffset, const size_t requestedSize, u8 *outBuffer); + + FILE* GetFilePtr() const; + bool IsEncrypted() const; + const char* GetDescription() const; + + int OpenFile(const char *filePath); + void CloseFile(); + + u32 LoadGameList(const char *gameCode, const u32 gameDatabaseCRC, CheatDBGameList &outList); +}; + class CHEATSEXPORT { private: - CHEATS_DB_TYPE type; - bool encrypted; - FILE *fp; - size_t fsize; - u64 dataSize; - u64 encOffset; - FAT_R4 fat; - bool search(); - bool getCodes(); - void R4decrypt(u8 *buf, const size_t len, u64 n); + CheatDBFile _dbFile; + CheatDBGame *_selectedDbGame; + CHEATS_LIST *_cheats; - u32 numCheats; - CHEATS_LIST *cheats; - - u8 error; // 0 - no errors - // 1 - open failed/file not found - // 2 - file format is wrong (no valid header ID) - // 3 - cheat not found in database - // 4 - export error from database + u8 _error; // 0 - no errors + // 1 - open failed/file not found + // 2 - file format is wrong (no valid header ID) + // 3 - cheat not found in database + // 4 - export error from database public: - CHEATSEXPORT() : - fp(NULL), - fsize(0), - dataSize(0), - encOffset(0), - type(CHEATS_DB_R4), - encrypted(false), - numCheats(0), - cheats(0), - CRC(0), - error(0) - { - memset(&fat, 0, sizeof(fat)); - memset(gametitle, 0, sizeof(gametitle)); - memset(date, 0, sizeof(date)); - } - - u8 gametitle[CHEAT_DB_GAME_TITLE_SIZE]; - u8 date[17]; - u32 CRC; - bool load(char *path); - void close(); - CHEATS_LIST *getCheats(); - u32 getCheatsNum(); - u8 getErrorCode() { return error; } + CHEATSEXPORT(); + ~CHEATSEXPORT(); + + bool load(const char *path); + void close(); + + CHEATS_LIST *getCheats() const; + size_t getCheatsNum() const; + const char* getGameTitle() const; + const char* getDescription() const; + u8 getErrorCode() const; }; +CheatDBGame* GetCheatDBGameEntryFromList(const CheatDBGameList &gameList, const char *gameCode, const u32 gameDatabaseCRC); +void CheatItemGenerateDescriptionHierarchical(const char *itemName, const char *itemNote, CHEATS_LIST &outCheatItem); +void CheatItemGenerateDescriptionFlat(const char *folderName, const char *folderNote, const char *itemName, const char *itemNote, CHEATS_LIST &outCheatItem); + extern CHEATS *cheats; extern CHEATSEARCH *cheatSearch; diff --git a/desmume/src/frontend/cocoa/cocoa_cheat.h b/desmume/src/frontend/cocoa/cocoa_cheat.h index f552b1ad2..a3b4ed9a9 100644 --- a/desmume/src/frontend/cocoa/cocoa_cheat.h +++ b/desmume/src/frontend/cocoa/cocoa_cheat.h @@ -95,7 +95,8 @@ protected: bool _willAddFromDB; CheatType _cheatType; - std::string _descriptionString; + std::string _descriptionMajorString; + std::string _descriptionMinorString; // Internal cheat type parameters CheatFreezeType _freezeType; @@ -132,8 +133,8 @@ public: void SetType(CheatType requestedType); bool IsSupportedType() const; - const char* GetDescription() const; - void SetDescription(const char *descriptionString); + const char* GetMajorDescription() const; + void SetMajorDescription(const char *descriptionString); CheatFreezeType GetFreezeType() const; void SetFreezeType(CheatFreezeType theFreezeType); @@ -224,7 +225,7 @@ class ClientCheatDatabase protected: ClientCheatList *_list; std::string _title; - std::string _date; + std::string _description; std::string _lastFilePath; public: @@ -235,7 +236,7 @@ public: ClientCheatList* LoadFromFile(const char *dbFilePath); const char* GetTitle() const; - const char* GetDate() const; + const char* GetDescription() const; }; class ClientCheatManager @@ -289,7 +290,7 @@ public: ClientCheatList* GetDatabaseList() const; ClientCheatList* DatabaseListLoadFromFile(const char *dbFilePath); const char* GetDatabaseTitle() const; - const char* GetDatabaseDate() const; + const char* GetDatabaseDescription() const; bool SearchDidStart() const; void SearchReset(); diff --git a/desmume/src/frontend/cocoa/cocoa_cheat.mm b/desmume/src/frontend/cocoa/cocoa_cheat.mm index 9afb62e5d..f60532484 100644 --- a/desmume/src/frontend/cocoa/cocoa_cheat.mm +++ b/desmume/src/frontend/cocoa/cocoa_cheat.mm @@ -178,7 +178,8 @@ ClientCheatItem::ClientCheatItem() _willAddFromDB = false; _cheatType = CheatType_Internal; - _descriptionString = "No description."; + _descriptionMajorString = "No description."; + _descriptionMinorString = ""; _freezeType = CheatFreezeType_Normal; _address = 0x02000000; strncpy(_addressString, "0x02000000", sizeof(_addressString)); @@ -202,7 +203,8 @@ void ClientCheatItem::Init(const CHEATS_LIST &inCheatItem) this->_isEnabled = (inCheatItem.enabled) ? true : false; this->_cheatType = (CheatType)inCheatItem.type; - this->_descriptionString = inCheatItem.description; + this->_descriptionMajorString = inCheatItem.description; + this->_descriptionMinorString = ""; this->_freezeType = (CheatFreezeType)inCheatItem.freezeType; this->_valueLength = inCheatItem.size + 1; // CHEATS_LIST.size value range is [1...4], but starts counting from 0. @@ -238,7 +240,7 @@ void ClientCheatItem::Init(const CHEATS_LIST &inCheatItem) void ClientCheatItem::Init(const ClientCheatItem &inCheatItem) { this->SetEnabled(inCheatItem.IsEnabled()); - this->SetDescription(inCheatItem.GetDescription()); + this->SetMajorDescription(inCheatItem.GetMajorDescription()); this->SetType(inCheatItem.GetType()); this->SetFreezeType(inCheatItem.GetFreezeType()); @@ -322,20 +324,20 @@ bool ClientCheatItem::IsSupportedType() const return (this->_cheatType != CheatType_CodeBreaker); } -const char* ClientCheatItem::GetDescription() const +const char* ClientCheatItem::GetMajorDescription() const { - return this->_descriptionString.c_str(); + return this->_descriptionMajorString.c_str(); } -void ClientCheatItem::SetDescription(const char *descriptionString) +void ClientCheatItem::SetMajorDescription(const char *descriptionString) { if (descriptionString == NULL) { - this->_descriptionString = ""; + this->_descriptionMajorString = ""; } else { - this->_descriptionString = descriptionString; + this->_descriptionMajorString = descriptionString; } } @@ -608,7 +610,7 @@ void ClientCheatItem::ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const outCheatItem->type = this->_cheatType; outCheatItem->enabled = (this->_isEnabled) ? 1 : 0; - strncpy(outCheatItem->description, this->_descriptionString.c_str(), sizeof(outCheatItem->description)); + strncpy(outCheatItem->description, this->_descriptionMajorString.c_str(), sizeof(outCheatItem->description)); switch (this->_cheatType) { @@ -1062,7 +1064,7 @@ ClientCheatDatabase::ClientCheatDatabase() { _list = new ClientCheatList; _title.resize(0); - _date.resize(0); + _description.resize(0); _lastFilePath.resize(0); } @@ -1090,8 +1092,8 @@ ClientCheatList* ClientCheatDatabase::LoadFromFile(const char *dbFilePath) if (didFileLoad) { this->_list->RemoveAll(); - this->_title = (const char *)exporter->gametitle; - this->_date = (const char *)exporter->date; + this->_title = exporter->getGameTitle(); + this->_description = exporter->getDescription(); this->_lastFilePath = dbFilePath; const size_t itemCount = exporter->getCheatsNum(); @@ -1127,9 +1129,9 @@ const char* ClientCheatDatabase::GetTitle() const return this->_title.c_str(); } -const char* ClientCheatDatabase::GetDate() const +const char* ClientCheatDatabase::GetDescription() const { - return this->_date.c_str(); + return this->_description.c_str(); } #pragma mark - @@ -1242,11 +1244,11 @@ ClientCheatItem* ClientCheatManager::NewItem() char newDesc[16]; snprintf(newDesc, sizeof(newDesc), "Untitled %ld", (unsigned long)this->_untitledCount); - newItem->SetDescription(newDesc); + newItem->SetMajorDescription(newDesc); } else { - newItem->SetDescription("Untitled"); + newItem->SetMajorDescription("Untitled"); } if (newItem->IsEnabled()) @@ -1407,9 +1409,9 @@ const char* ClientCheatManager::GetDatabaseTitle() const return this->_currentDatabase->GetTitle(); } -const char* ClientCheatManager::GetDatabaseDate() const +const char* ClientCheatManager::GetDatabaseDescription() const { - return this->_currentDatabase->GetDate(); + return this->_currentDatabase->GetDescription(); } bool ClientCheatManager::SearchDidStart() const @@ -1623,18 +1625,18 @@ static NSImage *iconCodeBreaker = nil; - (NSString *) description { - return [NSString stringWithCString:_internalData->GetDescription() encoding:NSUTF8StringEncoding]; + return [NSString stringWithCString:_internalData->GetMajorDescription() encoding:NSUTF8StringEncoding]; } - (void) setDescription:(NSString *)desc { if (desc == nil) { - _internalData->SetDescription(NULL); + _internalData->SetMajorDescription(NULL); } else { - _internalData->SetDescription([desc cStringUsingEncoding:NSUTF8StringEncoding]); + _internalData->SetMajorDescription([desc cStringUsingEncoding:NSUTF8StringEncoding]); } if ((workingCopy != nil) && !_disableWorkingCopyUpdate) @@ -1645,7 +1647,7 @@ static NSImage *iconCodeBreaker = nil; - (char *) descriptionCString { - return (char *)_internalData->GetDescription(); + return (char *)_internalData->GetMajorDescription(); } - (NSInteger) cheatType @@ -2072,7 +2074,7 @@ static NSImage *iconCodeBreaker = nil; - (NSString *) databaseDate { - return [NSString stringWithCString:_internalCheatManager->GetDatabaseDate() encoding:NSUTF8StringEncoding]; + return [NSString stringWithCString:_internalCheatManager->GetDatabaseDescription() encoding:NSUTF8StringEncoding]; } - (NSUInteger) itemTotalCount diff --git a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm index 76d82f475..71e266cd8 100644 --- a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm +++ b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm @@ -1199,7 +1199,7 @@ void UpdateDisplayPropertiesFromStates(uint64_t displayModeStates, ClientDisplay ClientCheatItem *newCheatItem = new ClientCheatItem; newCheatItem->SetType(CheatType_ActionReplay); // Default to Action Replay for now newCheatItem->SetFreezeType(CheatFreezeType_Normal); - newCheatItem->SetDescription(NULL); // OpenEmu takes care of this + newCheatItem->SetMajorDescription(NULL); // OpenEmu takes care of this newCheatItem->SetRawCodeString([code cStringUsingEncoding:NSUTF8StringEncoding], true); newCheatItem->SetEnabled((enabled) ? true : false); diff --git a/desmume/src/frontend/windows/cheatsWin.cpp b/desmume/src/frontend/windows/cheatsWin.cpp index 9fe7d52ab..dc975a2d2 100755 --- a/desmume/src/frontend/windows/cheatsWin.cpp +++ b/desmume/src/frontend/windows/cheatsWin.cpp @@ -1534,13 +1534,13 @@ INT_PTR CALLBACK CheatsExportProc(HWND dialog, UINT msg,WPARAM wparam,LPARAM lpa { case WM_INITDIALOG: { - SetWindowText(GetDlgItem(dialog, IDC_CDATE), (LPCSTR)cheatsExport->date); - if (cheatsExport->gametitle && strlen((char*)cheatsExport->gametitle) > 0) + SetWindowText(GetDlgItem(dialog, IDC_CDATE), (LPCSTR)cheatsExport->getDescription()); + if ( strlen(cheatsExport->getGameTitle()) > 0 ) { char buf[512] = {0}; GetWindowText(dialog, &buf[0], sizeof(buf)); strcat(buf, ": "); - strcat(buf, (char*)cheatsExport->gametitle); + strcat(buf, cheatsExport->getGameTitle()); SetWindowText(dialog, (LPCSTR)buf); } LV_COLUMN lvColumn; From 6ee942ca5f6b2b6f643a4eff0e1d987d2b4be745 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 18 Jul 2023 12:10:55 -0700 Subject: [PATCH 03/49] types.h: Remove an extraneous file inclusion. --- desmume/src/types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/desmume/src/types.h b/desmume/src/types.h index 42aa28cda..a4c3b3a15 100644 --- a/desmume/src/types.h +++ b/desmume/src/types.h @@ -309,7 +309,6 @@ typedef float32x4_t v128f32; #endif #ifdef ENABLE_SSE -#include #include typedef __m128 v128f32; #define AVAILABLE_TYPE_v128f32 From d08a5dc56c85286990dab43ae6fde4ec197684c3 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 18 Jul 2023 16:43:15 -0700 Subject: [PATCH 04/49] Cocoa Port: Update build optimization profiles in Xcode project. --- .../DeSmuME (Latest).xcodeproj/project.pbxproj | 13 ++++++++----- .../project.xcworkspace/contents.xcworkspacedata | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj index 59d6d6955..d2f8a9cf9 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj @@ -4022,6 +4022,7 @@ AB796CA215CDCB6B00C59155 /* instruction_attributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = instruction_attributes.h; sourceTree = ""; }; AB796CA315CDCB6B00C59155 /* instructions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = instructions.h; sourceTree = ""; }; AB796D7015CDCBA200C59155 /* DeSmuME (Debug).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DeSmuME (Debug).app"; sourceTree = BUILT_PRODUCTS_DIR; }; + AB7DA2432833EEBA001E9A9E /* DeSmuME_arm64.profdata */ = {isa = PBXFileReference; lastKnownFileType = file; path = DeSmuME_arm64.profdata; sourceTree = ""; }; AB7EC7F2189B2B92009D198A /* Icon_AutoholdClear_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_AutoholdClear_420x420.png; path = images/Icon_AutoholdClear_420x420.png; sourceTree = ""; }; AB7EC7F3189B2B92009D198A /* Icon_AutoholdSet_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_AutoholdSet_420x420.png; path = images/Icon_AutoholdSet_420x420.png; sourceTree = ""; }; AB80E04C142BC4A800A52038 /* cocoa_util.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_util.mm; sourceTree = ""; }; @@ -4107,6 +4108,7 @@ AB9971CE134EDA0800531BA7 /* cocoa_globals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_globals.h; sourceTree = ""; }; ABA48DF527F95C2E00D961FB /* colorspacehandler_NEON.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = colorspacehandler_NEON.h; sourceTree = ""; }; ABA48DF627F95C2E00D961FB /* colorspacehandler_NEON.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = colorspacehandler_NEON.cpp; sourceTree = ""; }; + ABA5AB11282E63E20005F25D /* DeSmuME_x86_64.profdata */ = {isa = PBXFileReference; lastKnownFileType = file; path = DeSmuME_x86_64.profdata; sourceTree = ""; }; ABA6574914511EC90077E5E9 /* cocoa_cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_cheat.h; sourceTree = ""; }; ABA6574A14511EC90077E5E9 /* cocoa_cheat.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_cheat.mm; sourceTree = ""; }; ABA67CA52808B8D000B5208D /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; @@ -4212,6 +4214,7 @@ ABC570D4134431DA00E7B0B1 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; ABC719E1138CB25E002827A9 /* DefaultKeyMappings.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DefaultKeyMappings.plist; sourceTree = ""; }; ABC8599028273FEE00A03EA9 /* DeSmuME (x86_64).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DeSmuME (x86_64).app"; sourceTree = BUILT_PRODUCTS_DIR; }; + ABCC191C2831F3E100B795C4 /* DeSmuME_x86_64h.profdata */ = {isa = PBXFileReference; lastKnownFileType = file; path = DeSmuME_x86_64h.profdata; sourceTree = ""; }; ABCC19332287879000DFA471 /* colorspacehandler_AVX512.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = colorspacehandler_AVX512.cpp; sourceTree = ""; }; ABCC19342287879000DFA471 /* colorspacehandler_AVX512.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = colorspacehandler_AVX512.h; sourceTree = ""; }; ABCFA9F2178BDE920030C8BA /* encrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encrypt.h; sourceTree = ""; }; @@ -4380,7 +4383,6 @@ ABDDF7C41898F024007583C1 /* Icon_DisplayToggle_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_DisplayToggle_420x420.png; path = images/Icon_DisplayToggle_420x420.png; sourceTree = ""; }; ABDDF7C71898F032007583C1 /* Icon_FrameAdvance_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_FrameAdvance_420x420.png; path = images/Icon_FrameAdvance_420x420.png; sourceTree = ""; }; ABDDF7C81898F032007583C1 /* Icon_FrameJump_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_FrameJump_420x420.png; path = images/Icon_FrameJump_420x420.png; sourceTree = ""; }; - ABE187E928274F0100B68164 /* DeSmuME_i386.profdata */ = {isa = PBXFileReference; lastKnownFileType = file; path = DeSmuME_i386.profdata; sourceTree = ""; }; ABE5DFE3143FB1DA00835AD8 /* cocoa_videofilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_videofilter.h; sourceTree = ""; }; ABE5DFE4143FB1DA00835AD8 /* cocoa_videofilter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_videofilter.mm; sourceTree = ""; }; ABE670251415DE6C00E8E4C9 /* tinystr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinystr.cpp; sourceTree = ""; }; @@ -4393,6 +4395,7 @@ ABE6840E189E33D5007FD69C /* OGLDisplayOutput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OGLDisplayOutput.h; sourceTree = ""; }; ABE7F53C13EE1C7900FD3A71 /* cocoa_firmware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_firmware.h; sourceTree = ""; }; ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_firmware.mm; sourceTree = ""; }; + ABECD444282DF23100AA6C0C /* DeSmuME_i386.profdata */ = {isa = PBXFileReference; lastKnownFileType = file; path = DeSmuME_i386.profdata; sourceTree = ""; }; ABEFCF5D141AB82A000CC0CD /* AppIcon_ROMSave.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon_ROMSave.icns; sourceTree = ""; }; ABEFCF5E141AB82A000CC0CD /* AppIcon_DeSmuME.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon_DeSmuME.icns; sourceTree = ""; }; ABEFCF5F141AB82A000CC0CD /* AppIcon_NintendoDS_ROM.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon_NintendoDS_ROM.icns; sourceTree = ""; }; @@ -5346,7 +5349,10 @@ AB407F381A620D6E00313213 /* OptimizationProfiles */ = { isa = PBXGroup; children = ( - ABE187E928274F0100B68164 /* DeSmuME_i386.profdata */, + ABECD444282DF23100AA6C0C /* DeSmuME_i386.profdata */, + ABA5AB11282E63E20005F25D /* DeSmuME_x86_64.profdata */, + ABCC191C2831F3E100B795C4 /* DeSmuME_x86_64h.profdata */, + AB7DA2432833EEBA001E9A9E /* DeSmuME_arm64.profdata */, ); path = OptimizationProfiles; sourceTree = ""; @@ -10333,7 +10339,6 @@ buildSettings = { ARCHS = arm64; CLANG_OPTIMIZATION_PROFILE_FILE = "$(SRCROOT)/OptimizationProfiles/DeSmuME_arm64.profdata"; - CLANG_USE_OPTIMIZATION_PROFILE = YES; GCC_FAST_OBJC_DISPATCH = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = fast; @@ -10666,7 +10671,6 @@ ARCHS = x86_64; CLANG_CXX_LIBRARY = "libstdc++"; CLANG_OPTIMIZATION_PROFILE_FILE = "$(SRCROOT)/OptimizationProfiles/DeSmuME_x86_64.profdata"; - CLANG_USE_OPTIMIZATION_PROFILE = YES; GCC_FAST_OBJC_DISPATCH = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = fast; @@ -10715,7 +10719,6 @@ buildSettings = { ARCHS = x86_64h; CLANG_OPTIMIZATION_PROFILE_FILE = "$(SRCROOT)/OptimizationProfiles/DeSmuME_x86_64h.profdata"; - CLANG_USE_OPTIMIZATION_PROFILE = YES; GCC_FAST_OBJC_DISPATCH = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = fast; diff --git a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.xcworkspace/contents.xcworkspacedata b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.xcworkspace/contents.xcworkspacedata index 705f70856..919434a62 100644 --- a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> From 9bf090b309e525da7f432b8a60ef7031e26917cd Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 19 Jul 2023 12:22:06 -0700 Subject: [PATCH 05/49] Cheat System: Fix a bug where the underlying cheat data would get deallocated earlier than intended. (Regression from commit 0c90e8f.) - In CheatDBGame, also differentiate between actual entry size vs. working entry size. --- desmume/src/cheatSystem.cpp | 39 +++++++++++++++++++++---------------- desmume/src/cheatSystem.h | 13 ++++++++----- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/desmume/src/cheatSystem.cpp b/desmume/src/cheatSystem.cpp index ebf2ffe15..25072ab8e 100755 --- a/desmume/src/cheatSystem.cpp +++ b/desmume/src/cheatSystem.cpp @@ -1702,7 +1702,8 @@ CheatDBGame::CheatDBGame() _firstEntryOffset = 0; _encryptOffset = 0; - _dataSize = 0; + _rawDataSize = 0; + _workingDataSize = 0; _crc = 0; _entryCount = 0; @@ -1723,9 +1724,9 @@ CheatDBGame::CheatDBGame() _cheatItemCount = 0; } -CheatDBGame::CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize) +CheatDBGame::CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 rawDataSize) { - CheatDBGame::SetInitialProperties(dataSize, encryptOffset, fat); + CheatDBGame::SetInitialProperties(rawDataSize, encryptOffset, fat); _firstEntryOffset = 0; _entryCount = 0; @@ -1745,9 +1746,9 @@ CheatDBGame::CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 d _cheatItemCount = 0; } -CheatDBGame::CheatDBGame(FILE *fp, const bool isEncrypted, const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize, u8 (&workingBuffer)[1024]) +CheatDBGame::CheatDBGame(FILE *fp, const bool isEncrypted, const u32 encryptOffset, const FAT_R4 &fat, const u32 rawDataSize, u8 (&workingBuffer)[1024]) { - CheatDBGame::SetInitialProperties(dataSize, encryptOffset, fat); + CheatDBGame::SetInitialProperties(rawDataSize, encryptOffset, fat); CheatDBGame::LoadPropertiesFromFile(fp, isEncrypted, workingBuffer); _entryDataRawPtr = NULL; @@ -1774,9 +1775,10 @@ CheatDBGame::~CheatDBGame() } } -void CheatDBGame::SetInitialProperties(const u32 dataSize, const u32 encryptOffset, const FAT_R4 &fat) +void CheatDBGame::SetInitialProperties(const u32 rawDataSize, const u32 encryptOffset, const FAT_R4 &fat) { - _dataSize = dataSize; + _rawDataSize = rawDataSize; + _workingDataSize = rawDataSize + encryptOffset; _encryptOffset = encryptOffset; _baseOffset = (u32)fat.addr; _crc = fat.CRC; @@ -1789,7 +1791,7 @@ void CheatDBGame::SetInitialProperties(const u32 dataSize, const u32 encryptOffs void CheatDBGame::LoadPropertiesFromFile(FILE *fp, const bool isEncrypted, u8 (&workingBuffer)[1024]) { - const size_t gameDataBufferSize = (_dataSize < sizeof(workingBuffer)) ? _dataSize : sizeof(workingBuffer); + const size_t gameDataBufferSize = (_workingDataSize < sizeof(workingBuffer)) ? _workingDataSize : sizeof(workingBuffer); CheatDBFile::ReadToBuffer(fp, _baseOffset, isEncrypted, _encryptOffset, gameDataBufferSize, workingBuffer); const u8 *gameDataBuffer = workingBuffer + _encryptOffset; @@ -1817,9 +1819,14 @@ u32 CheatDBGame::GetEncryptOffset() const return this->_encryptOffset; } -u32 CheatDBGame::GetDataSize() const +u32 CheatDBGame::GetRawDataSize() const { - return this->_dataSize; + return this->_rawDataSize; +} + +u32 CheatDBGame::GetWorkingDataSize() const +{ + return this->_workingDataSize; } u32 CheatDBGame::GetCRC() const @@ -1900,10 +1907,10 @@ u8* CheatDBGame::LoadEntryData(FILE *fp, const bool isEncrypted) this->_entryData = NULL; } - this->_entryDataRawPtr = (u8 *)malloc(this->_dataSize + 8); - memset(this->_entryDataRawPtr, 0, this->_dataSize + 8); + this->_entryDataRawPtr = (u8 *)malloc(this->_workingDataSize + 8); + memset(this->_entryDataRawPtr, 0, this->_workingDataSize + 8); - bool didReadSuccessfully = CheatDBFile::ReadToBuffer(fp, this->_baseOffset, isEncrypted, this->_encryptOffset, this->_dataSize, this->_entryDataRawPtr); + bool didReadSuccessfully = CheatDBFile::ReadToBuffer(fp, this->_baseOffset, isEncrypted, this->_encryptOffset, this->_workingDataSize, this->_entryDataRawPtr); if (!didReadSuccessfully) { free(this->_entryDataRawPtr); @@ -2381,7 +2388,6 @@ u32 CheatDBFile::LoadGameList(const char *gameCode, const u32 gameDatabaseCRC, C if (this->_isEncrypted) { encryptOffset = (u32)(fatEntryCurrent.addr % 512); - dataSize += encryptOffset; } if (dataSize == 0) @@ -2444,9 +2450,8 @@ bool CHEATSEXPORT::load(const char *path) return didLoadSucceed; } - CheatDBGameList gameList; - this->_dbFile.LoadGameList(gameInfo.header.gameCode, gameInfo.crcForCheatsDb, gameList); - CheatDBGame *dbGamePtr = GetCheatDBGameEntryFromList(gameList, gameInfo.header.gameCode, gameInfo.crcForCheatsDb); + this->_dbFile.LoadGameList(gameInfo.header.gameCode, gameInfo.crcForCheatsDb, this->_tempGameList); + CheatDBGame *dbGamePtr = GetCheatDBGameEntryFromList(this->_tempGameList, gameInfo.header.gameCode, gameInfo.crcForCheatsDb); if (dbGamePtr == NULL) { diff --git a/desmume/src/cheatSystem.h b/desmume/src/cheatSystem.h index d73f0edf4..79ca61533 100755 --- a/desmume/src/cheatSystem.h +++ b/desmume/src/cheatSystem.h @@ -201,7 +201,8 @@ protected: u32 _firstEntryOffset; // This offset is relative to the file head. u32 _encryptOffset; // This offset is relative to the memory address of this->_entryDataRawPtr. - u32 _dataSize; + u32 _rawDataSize; + u32 _workingDataSize; u32 _crc; u32 _entryCount; @@ -219,17 +220,18 @@ protected: public: CheatDBGame(); - CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize); - CheatDBGame(FILE *fp, const bool isEncrypted, const u32 encryptOffset, const FAT_R4 &fat, const u32 dataSize, u8 (&workingBuffer)[1024]); + CheatDBGame(const u32 encryptOffset, const FAT_R4 &fat, const u32 rawDataSize); + CheatDBGame(FILE *fp, const bool isEncrypted, const u32 encryptOffset, const FAT_R4 &fat, const u32 rawDataSize, u8 (&workingBuffer)[1024]); ~CheatDBGame(); - void SetInitialProperties(const u32 dataSize, const u32 encryptOffset, const FAT_R4 &fat); + void SetInitialProperties(const u32 rawDataSize, const u32 encryptOffset, const FAT_R4 &fat); void LoadPropertiesFromFile(FILE *fp, const bool isEncrypted, u8 (&workingBuffer)[1024]); u32 GetBaseOffset() const; u32 GetFirstEntryOffset() const; u32 GetEncryptOffset() const; - u32 GetDataSize() const; + u32 GetRawDataSize() const; + u32 GetWorkingDataSize() const; u32 GetCRC() const; u32 GetEntryCount() const; u32 GetCheatItemCount() const; @@ -281,6 +283,7 @@ class CHEATSEXPORT { private: CheatDBFile _dbFile; + CheatDBGameList _tempGameList; CheatDBGame *_selectedDbGame; CHEATS_LIST *_cheats; From 4e6a7f04246049a13090617ab9d0efe5ada6280f Mon Sep 17 00:00:00 2001 From: rogerman Date: Mon, 24 Jul 2023 13:46:05 -0700 Subject: [PATCH 06/49] Cheat System: Fix a couple bugs with CheatDBFile::LoadGameList() when reading the entire database's game list. - Fix a bug where loading all database game entries from an encrypted database would result in reading gobbledygook. - Fix a bug where calling CheatDBFile::LoadGameList() for all database game entries would always return 0 entries rather than the actual number of found entries. --- desmume/src/cheatSystem.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/desmume/src/cheatSystem.cpp b/desmume/src/cheatSystem.cpp index 25072ab8e..55f4b82c2 100755 --- a/desmume/src/cheatSystem.cpp +++ b/desmume/src/cheatSystem.cpp @@ -2352,6 +2352,12 @@ u32 CheatDBFile::LoadGameList(const char *gameCode, const u32 gameDatabaseCRC, C if ((pos >> 9) > t) { t++; + if ( (t << 9) > this->_size) + { + break; + } + + fseek(this->_fp, t << 9, SEEK_SET); fread(fatBuffer, 1, 512, this->_fp); CheatDBFile::R4Decrypt(fatBuffer, 512, t); } @@ -2421,6 +2427,7 @@ u32 CheatDBFile::LoadGameList(const char *gameCode, const u32 gameDatabaseCRC, C else { outList.push_back( this->_ReadGame(encryptOffset, fatEntryCurrent, dataSize, gameEntryBuffer) ); + entryCount++; } } while (fatEntryNext.addr > 0); From e3167110b2edf54951e76b3aeaefe4aeeb7bb377 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 1 Aug 2023 01:41:15 -0700 Subject: [PATCH 07/49] Cocoa Port: Completely redesign the cheat database viewing system with a whole slew of new features! - Multiple cheat database files may now be opened simultaneously, each in their own individual windows. - Cheat database files are now fully browsable. - Game entries are now searchable by game title, serial, and CRC. - Cheat entries are now viewed in a hierarchical layout, better representing the FAT format of the database entries. - All cheats within a directory can now be selected or deselected in just a single click. - Error handling is now more robust, informative, and nicer looking. - Cheat database files are no longer assigned in DeSmuME Preferences; they are now opened through the "File > Open Cheat Database File" menu. - Recent cheat database files are now saved, and can be quickly accessed through the "File > Open Recent Cheat Database File" menu. - It is now possible to remove all cheats at once from the Cheat Manager's cheat list. --- desmume/src/cheatSystem.cpp | 43 +- desmume/src/cheatSystem.h | 33 +- .../project.pbxproj | 56 + .../project.pbxproj | 34 + .../src/frontend/cocoa/DefaultUserPrefs.plist | 2 + desmume/src/frontend/cocoa/cocoa_cheat.h | 109 +- desmume/src/frontend/cocoa/cocoa_cheat.mm | 773 +++- desmume/src/frontend/cocoa/cocoa_globals.h | 33 +- .../src/frontend/cocoa/openemu/NDSGameCore.mm | 3 +- .../English.lproj/CheatDatabaseViewer.xib | 4058 +++++++++++++++++ .../English.lproj/MainMenu.strings | Bin 497164 -> 494476 bytes .../translations/English.lproj/MainMenu.xib | 2488 +++++----- .../CheatDatabaseWindowController.h | 97 + .../CheatDatabaseWindowController.mm | 759 +++ .../userinterface/EmuControllerDelegate.h | 12 +- .../userinterface/EmuControllerDelegate.mm | 194 +- .../cocoa/userinterface/appDelegate.h | 4 + .../cocoa/userinterface/appDelegate.mm | 6 +- .../cocoa/userinterface/cheatWindowDelegate.h | 20 +- .../userinterface/cheatWindowDelegate.mm | 223 +- .../userinterface/preferencesWindowDelegate.h | 6 +- .../preferencesWindowDelegate.mm | 72 - desmume/src/frontend/windows/cheatsWin.cpp | 36 +- 23 files changed, 7414 insertions(+), 1647 deletions(-) create mode 100644 desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib create mode 100644 desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h create mode 100644 desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm diff --git a/desmume/src/cheatSystem.cpp b/desmume/src/cheatSystem.cpp index 55f4b82c2..03993b54d 100755 --- a/desmume/src/cheatSystem.cpp +++ b/desmume/src/cheatSystem.cpp @@ -2123,8 +2123,9 @@ CheatDBFile::CheatDBFile() { _path = ""; _description = ""; + _formatString = "---"; - _type = CHEATS_DB_R4; + _format = CheatDBFileFormat_Undefined; _isEncrypted = false; _size = 0; _fp = NULL; @@ -2150,15 +2151,25 @@ const char* CheatDBFile::GetDescription() const return this->_description.c_str(); } -int CheatDBFile::OpenFile(const char *filePath) +CheatDBFileFormat CheatDBFile::GetFormat() const { - int error = 0; + return this->_format; +} + +const char* CheatDBFile::GetFormatString() const +{ + return this->_formatString.c_str(); +} + +CheatSystemError CheatDBFile::OpenFile(const char *filePath) +{ + CheatSystemError error = CheatSystemError_NoError; this->_fp = fopen(filePath, "rb"); if (this->_fp == NULL) { printf("ERROR: Failed to open the cheat database.\n"); - error = 1; + error = CheatSystemError_FileOpenFailed; return error; } @@ -2172,14 +2183,14 @@ int CheatDBFile::OpenFile(const char *filePath) if (this->_size < strlen(headerID)) { printf("ERROR: Failed to validate the file header.\n"); - error = 2; + error = CheatSystemError_FileFormatInvalid; return error; } if (this->_size < CHEATDB_FILEOFFSET_FIRST_FAT_ENTRY) { printf("ERROR: No FAT entries found.\n"); - error = 2; + error = CheatSystemError_FileFormatInvalid; return error; } @@ -2203,7 +2214,7 @@ int CheatDBFile::OpenFile(const char *filePath) this->_fp = NULL; printf("ERROR: Failed to validate the file header.\n"); - error = 2; + error = CheatSystemError_FileFormatInvalid; return error; } @@ -2213,6 +2224,8 @@ int CheatDBFile::OpenFile(const char *filePath) this->_isEncrypted = true; } + this->_format = CheatDBFileFormat_R4; + this->_formatString = "R4"; this->_description = (const char *)(workingBuffer + CHEATDB_OFFSET_FILE_DESCRIPTION); this->_path = filePath; @@ -2439,7 +2452,7 @@ CHEATSEXPORT::CHEATSEXPORT() { _selectedDbGame = NULL; _cheats = NULL; - _error = 0; + _lastError = CheatSystemError_NoError; } CHEATSEXPORT::~CHEATSEXPORT() @@ -2451,8 +2464,8 @@ bool CHEATSEXPORT::load(const char *path) { bool didLoadSucceed = false; - this->_error = this->_dbFile.OpenFile(path); - if (this->_error != 0) + this->_lastError = this->_dbFile.OpenFile(path); + if (this->_lastError != CheatSystemError_NoError) { return didLoadSucceed; } @@ -2471,7 +2484,7 @@ bool CHEATSEXPORT::load(const char *path) }; printf("ERROR: Cheat for game code '%s' not found in database.\n", gameCodeString); - this->_error = 3; + this->_lastError = CheatSystemError_GameNotFound; return didLoadSucceed; } @@ -2479,7 +2492,7 @@ bool CHEATSEXPORT::load(const char *path) if (dbGameBuffer == NULL) { printf("ERROR: Failed to read game entries from file.\n"); - this->_error = 1; + this->_lastError = CheatSystemError_LoadEntryError; return didLoadSucceed; } @@ -2495,7 +2508,7 @@ bool CHEATSEXPORT::load(const char *path) if (parsedCheatCount == 0) { printf("ERROR: export cheats failed\n"); - this->_error = 4; + this->_lastError = CheatSystemError_LoadEntryError; return didLoadSucceed; } @@ -2546,7 +2559,7 @@ const char* CHEATSEXPORT::getDescription() const return (const char *)this->_dbFile.GetDescription(); } -u8 CHEATSEXPORT::getErrorCode() const +CheatSystemError CHEATSEXPORT::getErrorCode() const { - return this->_error; + return this->_lastError; } diff --git a/desmume/src/cheatSystem.h b/desmume/src/cheatSystem.h index 79ca61533..e4bda9f4c 100755 --- a/desmume/src/cheatSystem.h +++ b/desmume/src/cheatSystem.h @@ -32,6 +32,17 @@ #define CHEAT_TYPE_AR 1 #define CHEAT_TYPE_CODEBREAKER 2 +enum CheatSystemError +{ + CheatSystemError_NoError = 0, + CheatSystemError_FileOpenFailed = 1, + CheatSystemError_FileFormatInvalid = 2, + CheatSystemError_GameNotFound = 3, + CheatSystemError_LoadEntryError = 4, + CheatSystemError_FileSaveFailed = 5, + CheatSystemError_FileDoesNotExist = 6 +}; + struct CHEATS_LIST { CHEATS_LIST() @@ -163,9 +174,11 @@ public: #define CHEATDB_OFFSET_FILE_DESCRIPTION 0x00000010 #define CHEATDB_FILEOFFSET_FIRST_FAT_ENTRY 0x00000100 -enum CHEATS_DB_TYPE +enum CheatDBFileFormat { - CHEATS_DB_R4 = 0 + CheatDBFileFormat_Undefined = 0, + CheatDBFileFormat_R4 = 1, + CheatDBFileFormat_Unknown = 65535 }; // This struct maps to the FAT entries in the R4 cheat database file. @@ -253,8 +266,9 @@ class CheatDBFile protected: std::string _path; std::string _description; + std::string _formatString; - CHEATS_DB_TYPE _type; + CheatDBFileFormat _format; bool _isEncrypted; size_t _size; @@ -272,8 +286,10 @@ public: FILE* GetFilePtr() const; bool IsEncrypted() const; const char* GetDescription() const; + CheatDBFileFormat GetFormat() const; + const char* GetFormatString() const; - int OpenFile(const char *filePath); + CheatSystemError OpenFile(const char *filePath); void CloseFile(); u32 LoadGameList(const char *gameCode, const u32 gameDatabaseCRC, CheatDBGameList &outList); @@ -286,12 +302,7 @@ private: CheatDBGameList _tempGameList; CheatDBGame *_selectedDbGame; CHEATS_LIST *_cheats; - - u8 _error; // 0 - no errors - // 1 - open failed/file not found - // 2 - file format is wrong (no valid header ID) - // 3 - cheat not found in database - // 4 - export error from database + CheatSystemError _lastError; public: CHEATSEXPORT(); @@ -304,7 +315,7 @@ public: size_t getCheatsNum() const; const char* getGameTitle() const; const char* getDescription() const; - u8 getErrorCode() const; + CheatSystemError getErrorCode() const; }; CheatDBGame* GetCheatDBGameEntryFromList(const CheatDBGameList &gameList, const char *gameCode, const u32 gameDatabaseCRC); diff --git a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj index d2f8a9cf9..172267841 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj @@ -1543,6 +1543,27 @@ AB681025187D4AEF0049F2C2 /* Icon_PaddleKnob_256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = AB681018187D4AEF0049F2C2 /* Icon_PaddleKnob_256x256.png */; }; AB681027187D4AEF0049F2C2 /* Icon_Piano_256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = AB681019187D4AEF0049F2C2 /* Icon_Piano_256x256.png */; }; AB68A0DD16B139BC00DE0546 /* OGLRender_3_2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB68A0DA16B139BC00DE0546 /* OGLRender_3_2.cpp */; }; + AB6E17F52A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17F62A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17F72A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17F82A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17F92A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17FA2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17FB2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17FC2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17FD2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E17FE2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */; }; + AB6E18012A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18022A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18032A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18042A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18052A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18062A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18072A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18082A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E18092A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E180A2A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; + AB6E180B2A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */; }; AB74EC8A1738499C0026C41E /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB74EC891738499C0026C41E /* Carbon.framework */; }; AB78B5C11E384F2100297FED /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB3BF4401E262943003E2B24 /* Metal.framework */; settings = {ATTRIBUTES = (Required, ); }; }; AB78B5C21E384F2200297FED /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB3BF4401E262943003E2B24 /* Metal.framework */; settings = {ATTRIBUTES = (Required, ); }; }; @@ -4012,6 +4033,9 @@ AB681018187D4AEF0049F2C2 /* Icon_PaddleKnob_256x256.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_PaddleKnob_256x256.png; path = images/Icon_PaddleKnob_256x256.png; sourceTree = ""; }; AB681019187D4AEF0049F2C2 /* Icon_Piano_256x256.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_Piano_256x256.png; path = images/Icon_Piano_256x256.png; sourceTree = ""; }; AB68A0DA16B139BC00DE0546 /* OGLRender_3_2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OGLRender_3_2.cpp; sourceTree = ""; }; + AB6E17F32A675BF1003A564D /* CheatDatabaseWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CheatDatabaseWindowController.h; sourceTree = ""; }; + AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CheatDatabaseWindowController.mm; sourceTree = ""; }; + AB6E18002A6B218D003A564D /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = translations/English.lproj/CheatDatabaseViewer.xib; sourceTree = ""; }; AB6FBEF5139B6258007BB045 /* slot1_retail_nand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slot1_retail_nand.cpp; sourceTree = ""; }; AB74EC891738499C0026C41E /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; AB75226D14C7BB51009B97B3 /* AppIcon_FirmwareConfig.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon_FirmwareConfig.icns; sourceTree = ""; }; @@ -4935,6 +4959,7 @@ ABC2ECD613B1C87000FAAA2A /* Images */, AB00E87C14205EBC00DE561F /* MainMenu.xib */, AB8967DB16D2ED2700F826F1 /* DisplayWindow.xib */, + AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */, AB350D3A147A1D93007165AC /* HID_usage_strings.plist */, 8D1107310486CEB800E47090 /* Info.plist */, AB02791814415E4C0075E58C /* Info (Debug).plist */, @@ -5227,6 +5252,7 @@ children = ( AB3ACB6614C2361100D7D192 /* appDelegate.h */, AB3ACB6814C2361100D7D192 /* cheatWindowDelegate.h */, + AB6E17F32A675BF1003A564D /* CheatDatabaseWindowController.h */, AB3BF4361E25D6B4003E2B24 /* DisplayViewCALayer.h */, AB8967D716D2ED0700F826F1 /* DisplayWindowController.h */, AB3A655C16CC5416001F5D4A /* EmuControllerDelegate.h */, @@ -5246,6 +5272,7 @@ AB3FBD7E2176DE95005722D0 /* WifiSettingsPanel.h */, AB54718A1E27610500508C5C /* MacMetalDisplayViewShaders.metal */, AB3ACB6714C2361100D7D192 /* appDelegate.mm */, + AB6E17F42A675BF1003A564D /* CheatDatabaseWindowController.mm */, AB3ACB6914C2361100D7D192 /* cheatWindowDelegate.mm */, AB3BF4371E25D9AE003E2B24 /* DisplayViewCALayer.mm */, AB8967D816D2ED0700F826F1 /* DisplayWindowController.mm */, @@ -6451,6 +6478,7 @@ 8C43E79727E3CD0100A35F65 /* Icon_Input_420x420.png in Resources */, 8C43E79827E3CD0100A35F65 /* Icon_AutoholdSet_420x420.png in Resources */, 8C43E79927E3CD0100A35F65 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18032A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, 8C43E79A27E3CD0100A35F65 /* Icon_OpenROM_420x420.png in Resources */, 8C43E79B27E3CD0100A35F65 /* Icon_Reset_420x420.png in Resources */, 8C43E79C27E3CD0100A35F65 /* Icon_RotateCCW_420x420.png in Resources */, @@ -6570,6 +6598,7 @@ 8C43E8F527E3CD4C00A35F65 /* Icon_Input_420x420.png in Resources */, 8C43E8F627E3CD4C00A35F65 /* Icon_AutoholdSet_420x420.png in Resources */, 8C43E8F727E3CD4C00A35F65 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18042A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, 8C43E8F827E3CD4C00A35F65 /* Icon_OpenROM_420x420.png in Resources */, 8C43E8F927E3CD4C00A35F65 /* Icon_Reset_420x420.png in Resources */, 8C43E8FA27E3CD4C00A35F65 /* Icon_RotateCCW_420x420.png in Resources */, @@ -6689,6 +6718,7 @@ 8CCD840827E40B730024BDD5 /* Icon_Input_420x420.png in Resources */, 8CCD840927E40B730024BDD5 /* Icon_AutoholdSet_420x420.png in Resources */, 8CCD840A27E40B730024BDD5 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E180B2A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, 8CCD840B27E40B730024BDD5 /* Icon_OpenROM_420x420.png in Resources */, 8CCD840C27E40B730024BDD5 /* Icon_Reset_420x420.png in Resources */, 8CCD840D27E40B730024BDD5 /* Icon_RotateCCW_420x420.png in Resources */, @@ -6808,6 +6838,7 @@ AB36C78827F2C8AE00C763C8 /* Icon_Input_420x420.png in Resources */, AB36C78927F2C8AE00C763C8 /* Icon_AutoholdSet_420x420.png in Resources */, AB36C78A27F2C8AE00C763C8 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18082A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, AB36C78B27F2C8AE00C763C8 /* Icon_OpenROM_420x420.png in Resources */, AB36C78C27F2C8AE00C763C8 /* Icon_Reset_420x420.png in Resources */, AB36C78D27F2C8AE00C763C8 /* Icon_RotateCCW_420x420.png in Resources */, @@ -6927,6 +6958,7 @@ AB497A0E27F2E97A00E8A244 /* Icon_Input_420x420.png in Resources */, AB497A0F27F2E97A00E8A244 /* Icon_AutoholdSet_420x420.png in Resources */, AB497A1027F2E97A00E8A244 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18072A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, AB497A1127F2E97A00E8A244 /* Icon_OpenROM_420x420.png in Resources */, AB497A1227F2E97A00E8A244 /* Icon_Reset_420x420.png in Resources */, AB497A1327F2E97A00E8A244 /* Icon_RotateCCW_420x420.png in Resources */, @@ -7046,6 +7078,7 @@ AB790193215B84F20082AE82 /* Icon_Input_420x420.png in Resources */, AB790194215B84F20082AE82 /* Icon_AutoholdSet_420x420.png in Resources */, AB790195215B84F20082AE82 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18062A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, AB790196215B84F20082AE82 /* Icon_OpenROM_420x420.png in Resources */, AB790197215B84F20082AE82 /* Icon_Reset_420x420.png in Resources */, AB790198215B84F20082AE82 /* Icon_RotateCCW_420x420.png in Resources */, @@ -7165,6 +7198,7 @@ AB796CE015CDCBA200C59155 /* Icon_Input_420x420.png in Resources */, AB7EC7F6189B2B92009D198A /* Icon_AutoholdSet_420x420.png in Resources */, ABB0FBCC1A9EED350060C55A /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18012A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, AB796CE215CDCBA200C59155 /* Icon_OpenROM_420x420.png in Resources */, AB796CE315CDCBA200C59155 /* Icon_Reset_420x420.png in Resources */, AB796CE415CDCBA200C59155 /* Icon_RotateCCW_420x420.png in Resources */, @@ -7284,6 +7318,7 @@ AB790036215B84E50082AE82 /* Icon_Input_420x420.png in Resources */, AB790037215B84E50082AE82 /* Icon_AutoholdSet_420x420.png in Resources */, AB790038215B84E50082AE82 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18052A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, AB790039215B84E50082AE82 /* Icon_OpenROM_420x420.png in Resources */, AB79003A215B84E50082AE82 /* Icon_Reset_420x420.png in Resources */, AB79003B215B84E50082AE82 /* Icon_RotateCCW_420x420.png in Resources */, @@ -7403,6 +7438,7 @@ AB8F3C5F1A53AC2600A80BF6 /* Icon_Input_420x420.png in Resources */, AB8F3C601A53AC2600A80BF6 /* Icon_AutoholdSet_420x420.png in Resources */, ABB0FBCE1A9EED350060C55A /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18022A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, AB8F3C621A53AC2600A80BF6 /* Icon_OpenROM_420x420.png in Resources */, AB8F3C631A53AC2600A80BF6 /* Icon_Reset_420x420.png in Resources */, AB8F3C641A53AC2600A80BF6 /* Icon_RotateCCW_420x420.png in Resources */, @@ -7532,6 +7568,7 @@ ABC8588628273FEE00A03EA9 /* Icon_Input_420x420.png in Resources */, ABC8588728273FEE00A03EA9 /* Icon_AutoholdSet_420x420.png in Resources */, ABC8588828273FEE00A03EA9 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E18092A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, ABC8588928273FEE00A03EA9 /* Icon_OpenROM_420x420.png in Resources */, ABC8588A28273FEE00A03EA9 /* Icon_Reset_420x420.png in Resources */, ABC8588B28273FEE00A03EA9 /* Icon_RotateCCW_420x420.png in Resources */, @@ -7651,6 +7688,7 @@ ABD2CD3C26E05CB000FB15F7 /* Icon_Input_420x420.png in Resources */, ABD2CD3D26E05CB000FB15F7 /* Icon_AutoholdSet_420x420.png in Resources */, ABD2CD3E26E05CB000FB15F7 /* Icon_MicrophoneBlack_256x256.png in Resources */, + AB6E180A2A6B218D003A564D /* CheatDatabaseViewer.xib in Resources */, ABD2CD3F26E05CB000FB15F7 /* Icon_OpenROM_420x420.png in Resources */, ABD2CD4026E05CB000FB15F7 /* Icon_Reset_420x420.png in Resources */, ABD2CD4126E05CB000FB15F7 /* Icon_RotateCCW_420x420.png in Resources */, @@ -7920,6 +7958,7 @@ 8C43E7F027E3CD0100A35F65 /* ClientExecutionControl.cpp in Sources */, 8C43E7F127E3CD0100A35F65 /* rsemaphore.c in Sources */, 8C43E7F227E3CD0100A35F65 /* movie.cpp in Sources */, + AB6E17F72A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, 8C43E7F327E3CD0100A35F65 /* slot1comp_rom.cpp in Sources */, 8C43E7F427E3CD0100A35F65 /* NDSSystem.cpp in Sources */, 8C43E7F527E3CD0100A35F65 /* MacBaseCaptureTool.mm in Sources */, @@ -8162,6 +8201,7 @@ 8C43E97827E3CD4C00A35F65 /* slot2_rumblepak.cpp in Sources */, 8C43E97927E3CD4C00A35F65 /* sndOSX.cpp in Sources */, 8C43E97A27E3CD4C00A35F65 /* SndOut.cpp in Sources */, + AB6E17F82A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, 8C43E97B27E3CD4C00A35F65 /* psnames.c in Sources */, 8C43E97C27E3CD4C00A35F65 /* Slot2WindowDelegate.mm in Sources */, 8C43E97D27E3CD4C00A35F65 /* truetype.c in Sources */, @@ -8319,6 +8359,7 @@ 8CCD846127E40B730024BDD5 /* ClientExecutionControl.cpp in Sources */, 8CCD846227E40B730024BDD5 /* slot1.cpp in Sources */, 8CCD846327E40B730024BDD5 /* slot1_none.cpp in Sources */, + AB6E17FE2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, 8CCD846427E40B730024BDD5 /* slot1_r4.cpp in Sources */, 8CCD846527E40B730024BDD5 /* cff.c in Sources */, 8CCD846627E40B730024BDD5 /* MacBaseCaptureTool.mm in Sources */, @@ -8653,6 +8694,7 @@ AB36C86B27F2C8AE00C763C8 /* macosx_10_5_compat.cpp in Sources */, AB36C86C27F2C8AE00C763C8 /* OGLRender_3_2.cpp in Sources */, AB36C86D27F2C8AE00C763C8 /* ftfntfmt.c in Sources */, + AB6E17FB2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, AB36C86E27F2C8AE00C763C8 /* EmuControllerDelegate.mm in Sources */, AB36C86F27F2C8AE00C763C8 /* ClientAVCaptureObject.cpp in Sources */, AB36C87027F2C8AE00C763C8 /* cocoa_GPU.mm in Sources */, @@ -8710,6 +8752,7 @@ AB79006E215B84E50082AE82 /* emufile.cpp in Sources */, AB79006F215B84E50082AE82 /* fatdir.cpp in Sources */, AB790070215B84E50082AE82 /* ftbase.c in Sources */, + AB6E17F92A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, AB790071215B84E50082AE82 /* fatfile.cpp in Sources */, AB790072215B84E50082AE82 /* FIFO.cpp in Sources */, AB790073215B84E50082AE82 /* sfnt.c in Sources */, @@ -9010,6 +9053,7 @@ AB790211215B84F20082AE82 /* type1.c in Sources */, AB790212215B84F20082AE82 /* slot2_paddle.cpp in Sources */, AB790213215B84F20082AE82 /* slot2_piano.cpp in Sources */, + AB6E17FA2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, AB790214215B84F20082AE82 /* slot2_rumblepak.cpp in Sources */, AB790215215B84F20082AE82 /* sndOSX.cpp in Sources */, AB790216215B84F20082AE82 /* SndOut.cpp in Sources */, @@ -9167,6 +9211,7 @@ AB796D0415CDCBA200C59155 /* emufile.cpp in Sources */, AB796D0515CDCBA200C59155 /* fatdir.cpp in Sources */, ABFEA8011BB4EC1000B08C25 /* ftbase.c in Sources */, + AB6E17F52A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, AB796D0615CDCBA200C59155 /* fatfile.cpp in Sources */, AB796D0715CDCBA200C59155 /* FIFO.cpp in Sources */, ABFEA8A31BB4EC1100B08C25 /* sfnt.c in Sources */, @@ -9467,6 +9512,7 @@ ABA731701BB51FDC00B26147 /* type1.c in Sources */, AB8F3CBA1A53AC2600A80BF6 /* slot2_paddle.cpp in Sources */, AB8F3CBB1A53AC2600A80BF6 /* slot2_piano.cpp in Sources */, + AB6E17F62A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, AB8F3CBC1A53AC2600A80BF6 /* slot2_rumblepak.cpp in Sources */, AB8F3CBD1A53AC2600A80BF6 /* sndOSX.cpp in Sources */, AB8F3CBE1A53AC2600A80BF6 /* SndOut.cpp in Sources */, @@ -9796,6 +9842,7 @@ ABC858BF28273FEE00A03EA9 /* filetime.cpp in Sources */, ABC858C028273FEE00A03EA9 /* FIRFilter.cpp in Sources */, ABC858C128273FEE00A03EA9 /* firmware.cpp in Sources */, + AB6E17FC2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, ABC858C228273FEE00A03EA9 /* async_job.c in Sources */, ABC858C328273FEE00A03EA9 /* gfx3d.cpp in Sources */, ABC858C428273FEE00A03EA9 /* DisplayViewCALayer.mm in Sources */, @@ -10024,6 +10071,7 @@ ABD2CD7326E05CB000FB15F7 /* filetime.cpp in Sources */, ABD2CD7426E05CB000FB15F7 /* FIRFilter.cpp in Sources */, ABD2CD7526E05CB000FB15F7 /* firmware.cpp in Sources */, + AB6E17FD2A675BF1003A564D /* CheatDatabaseWindowController.mm in Sources */, ABD2CD7626E05CB000FB15F7 /* async_job.c in Sources */, ABD2CD7726E05CB000FB15F7 /* gfx3d.cpp in Sources */, ABD2CD7826E05CB000FB15F7 /* DisplayViewCALayer.mm in Sources */, @@ -10239,6 +10287,14 @@ name = HID_usage_strings.plist; sourceTree = ""; }; + AB6E17FF2A6B218D003A564D /* CheatDatabaseViewer.xib */ = { + isa = PBXVariantGroup; + children = ( + AB6E18002A6B218D003A564D /* English */, + ); + name = CheatDatabaseViewer.xib; + sourceTree = ""; + }; AB8967DB16D2ED2700F826F1 /* DisplayWindow.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj index baa1bd541..735f6235c 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj @@ -1558,6 +1558,11 @@ ABD59849187D4A6C00069403 /* Icon_PaddleKnob_256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = ABD59846187D4A6C00069403 /* Icon_PaddleKnob_256x256.png */; }; ABD5984A187D4A6C00069403 /* Icon_PaddleKnob_256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = ABD59846187D4A6C00069403 /* Icon_PaddleKnob_256x256.png */; }; ABD5984B187D4A6C00069403 /* Icon_PaddleKnob_256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = ABD59846187D4A6C00069403 /* Icon_PaddleKnob_256x256.png */; }; + ABEBCE372A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABEBCE362A703E260028CE8A /* CheatDatabaseWindowController.mm */; }; + ABEBCE382A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABEBCE362A703E260028CE8A /* CheatDatabaseWindowController.mm */; }; + ABEBCE392A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABEBCE362A703E260028CE8A /* CheatDatabaseWindowController.mm */; }; + ABEBCE3A2A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABEBCE362A703E260028CE8A /* CheatDatabaseWindowController.mm */; }; + ABEBCE3B2A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABEBCE362A703E260028CE8A /* CheatDatabaseWindowController.mm */; }; ABECB50918A460710052D52A /* xbrz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABECB50818A460710052D52A /* xbrz.cpp */; }; ABECB50A18A460710052D52A /* xbrz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABECB50818A460710052D52A /* xbrz.cpp */; }; ABECB50B18A460710052D52A /* xbrz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABECB50818A460710052D52A /* xbrz.cpp */; }; @@ -1572,6 +1577,11 @@ ABEF84831873578F00E99ADC /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB8C6E56186CD07E00E3EC64 /* ForceFeedback.framework */; }; ABEF84841873579400E99ADC /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB8C6E56186CD07E00E3EC64 /* ForceFeedback.framework */; }; ABEF84851873579700E99ADC /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB8C6E56186CD07E00E3EC64 /* ForceFeedback.framework */; }; + ABEFFDDE2A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = ABEFFDDC2A78CB67009C3A2D /* CheatDatabaseViewer.xib */; }; + ABEFFDDF2A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = ABEFFDDC2A78CB67009C3A2D /* CheatDatabaseViewer.xib */; }; + ABEFFDE02A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = ABEFFDDC2A78CB67009C3A2D /* CheatDatabaseViewer.xib */; }; + ABEFFDE12A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = ABEFFDDC2A78CB67009C3A2D /* CheatDatabaseViewer.xib */; }; + ABEFFDE22A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = ABEFFDDC2A78CB67009C3A2D /* CheatDatabaseViewer.xib */; }; ABF50ABA169F5FDA0018C08D /* assembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABF50A7B169F5FDA0018C08D /* assembler.cpp */; }; ABF50ABB169F5FDA0018C08D /* assert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABF50A7D169F5FDA0018C08D /* assert.cpp */; }; ABF50ABC169F5FDA0018C08D /* buffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ABF50A7F169F5FDA0018C08D /* buffer.cpp */; }; @@ -2326,6 +2336,8 @@ ABE6702A1415DE6C00E8E4C9 /* tinyxmlparser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxmlparser.cpp; sourceTree = ""; }; ABE7F53C13EE1C7900FD3A71 /* cocoa_firmware.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_firmware.h; sourceTree = ""; }; ABE7F53D13EE1C7900FD3A71 /* cocoa_firmware.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = cocoa_firmware.mm; sourceTree = ""; }; + ABEBCE352A703E260028CE8A /* CheatDatabaseWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheatDatabaseWindowController.h; sourceTree = ""; }; + ABEBCE362A703E260028CE8A /* CheatDatabaseWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CheatDatabaseWindowController.mm; sourceTree = ""; }; ABECB50718A460710052D52A /* xbrz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xbrz.h; sourceTree = ""; }; ABECB50818A460710052D52A /* xbrz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xbrz.cpp; sourceTree = ""; }; ABECB51218A460910052D52A /* OGLDisplayOutput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OGLDisplayOutput.h; sourceTree = ""; }; @@ -2334,6 +2346,7 @@ ABEFCF5E141AB82A000CC0CD /* AppIcon_DeSmuME.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon_DeSmuME.icns; sourceTree = ""; }; ABEFCF5F141AB82A000CC0CD /* AppIcon_NintendoDS_ROM.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon_NintendoDS_ROM.icns; sourceTree = ""; }; ABEFCF60141AB82A000CC0CD /* AppIcon_SaveState.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon_SaveState.icns; sourceTree = ""; }; + ABEFFDDD2A78CB67009C3A2D /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = translations/English.lproj/CheatDatabaseViewer.xib; sourceTree = ""; }; ABF50A74169F5FDA0018C08D /* AsmJit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsmJit.h; sourceTree = ""; }; ABF50A75169F5FDA0018C08D /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Config.h; sourceTree = ""; }; ABF50A76169F5FDA0018C08D /* core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = core.h; sourceTree = ""; }; @@ -2657,6 +2670,7 @@ AB05E8201BBFD41200065D18 /* source-sans-pro */, ABC2ECD613B1C87000FAAA2A /* Images */, AB00E87C14205EBC00DE561F /* MainMenu.xib */, + ABEFFDDC2A78CB67009C3A2D /* CheatDatabaseViewer.xib */, AB700DB816CDDBC400FBD336 /* DisplayWindow.xib */, AB350D3A147A1D93007165AC /* HID_usage_strings.plist */, 8D1107310486CEB800E47090 /* Info.plist */, @@ -3199,6 +3213,7 @@ isa = PBXGroup; children = ( AB3ACB6614C2361100D7D192 /* appDelegate.h */, + ABEBCE352A703E260028CE8A /* CheatDatabaseWindowController.h */, AB3ACB6814C2361100D7D192 /* cheatWindowDelegate.h */, AB3E69811E25FBBF00D4CC75 /* DisplayViewCALayer.h */, AB700DDC16CDE4C300FBD336 /* DisplayWindowController.h */, @@ -3217,6 +3232,7 @@ ABA0356E169127BB00817C69 /* troubleshootingWindowDelegate.h */, AB4B5A1F217E47E400381363 /* WifiSettingsPanel.h */, AB3ACB6714C2361100D7D192 /* appDelegate.mm */, + ABEBCE362A703E260028CE8A /* CheatDatabaseWindowController.mm */, AB3ACB6914C2361100D7D192 /* cheatWindowDelegate.mm */, AB3E69821E25FBBF00D4CC75 /* DisplayViewCALayer.mm */, AB700DDD16CDE4C300FBD336 /* DisplayWindowController.mm */, @@ -4014,6 +4030,7 @@ ABA1659B2808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16.png in Resources */, ABA1659C2808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16@2x.png in Resources */, AB6D78942809FA43007C6B0A /* Icon_MicrophoneIdleNoHardware_256x256.png in Resources */, + ABEFFDDF2A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4133,6 +4150,7 @@ ABA165A92808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16.png in Resources */, ABA165AA2808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16@2x.png in Resources */, AB6D78952809FA43007C6B0A /* Icon_MicrophoneIdleNoHardware_256x256.png in Resources */, + ABEFFDE02A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4252,6 +4270,7 @@ ABA165D32808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16.png in Resources */, ABA165D42808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16@2x.png in Resources */, AB6D78982809FA43007C6B0A /* Icon_MicrophoneIdleNoHardware_256x256.png in Resources */, + ABEFFDDE2A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4371,6 +4390,7 @@ ABA165C52808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16.png in Resources */, ABA165C62808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16@2x.png in Resources */, AB6D78972809FA43007C6B0A /* Icon_MicrophoneIdleNoHardware_256x256.png in Resources */, + ABEFFDE22A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4490,6 +4510,7 @@ ABA165B72808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16.png in Resources */, ABA165B82808BD6A00C8CFF5 /* Icon_VolumeTwoThird_DarkMode_16x16@2x.png in Resources */, AB6D78962809FA43007C6B0A /* Icon_MicrophoneIdleNoHardware_256x256.png in Resources */, + ABEFFDE12A78CB67009C3A2D /* CheatDatabaseViewer.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4835,6 +4856,7 @@ ABD1267720AE812900EFE1B2 /* ClientAVCaptureObject.cpp in Sources */, ABD1267820AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A22217E47E400381363 /* WifiSettingsPanel.mm in Sources */, + ABEBCE382A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5029,6 +5051,7 @@ ABD1267920AE812900EFE1B2 /* ClientAVCaptureObject.cpp in Sources */, ABD1267A20AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A23217E47E400381363 /* WifiSettingsPanel.mm in Sources */, + ABEBCE392A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5253,6 +5276,7 @@ ABD1267520AE812900EFE1B2 /* ClientAVCaptureObject.cpp in Sources */, ABD1267620AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A21217E47E400381363 /* WifiSettingsPanel.mm in Sources */, + ABEBCE372A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5477,6 +5501,7 @@ ABD1267D20AE812900EFE1B2 /* ClientAVCaptureObject.cpp in Sources */, ABD1267E20AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A25217E47E400381363 /* WifiSettingsPanel.mm in Sources */, + ABEBCE3B2A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5671,6 +5696,7 @@ ABD1267B20AE812900EFE1B2 /* ClientAVCaptureObject.cpp in Sources */, ABD1267C20AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A24217E47E400381363 /* WifiSettingsPanel.mm in Sources */, + ABEBCE3A2A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5717,6 +5743,14 @@ name = Localizable.strings; sourceTree = ""; }; + ABEFFDDC2A78CB67009C3A2D /* CheatDatabaseViewer.xib */ = { + isa = PBXVariantGroup; + children = ( + ABEFFDDD2A78CB67009C3A2D /* English */, + ); + name = CheatDatabaseViewer.xib; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ diff --git a/desmume/src/frontend/cocoa/DefaultUserPrefs.plist b/desmume/src/frontend/cocoa/DefaultUserPrefs.plist index 911f9e18a..629aeee35 100644 --- a/desmume/src/frontend/cocoa/DefaultUserPrefs.plist +++ b/desmume/src/frontend/cocoa/DefaultUserPrefs.plist @@ -4,6 +4,8 @@ Advanscene_AutoDetectRomSaveType + CheatDatabase_RecentFilePath + CoreControl_EnableAutoFrameSkip CoreControl_FramesToSkipSetting diff --git a/desmume/src/frontend/cocoa/cocoa_cheat.h b/desmume/src/frontend/cocoa/cocoa_cheat.h index a3b4ed9a9..f98b11bb7 100644 --- a/desmume/src/frontend/cocoa/cocoa_cheat.h +++ b/desmume/src/frontend/cocoa/cocoa_cheat.h @@ -18,9 +18,11 @@ #include #include -#import +#include "../../cheatSystem.h" #undef BOOL +#import + class CHEATS; class CHEATS_LIST; class CHEATSEARCH; @@ -54,16 +56,6 @@ enum CheatSearchCompareStyle CheatSearchCompareStyle_NotEquals = 3 }; -enum CheatSystemError -{ - CheatSystemError_NoError = 0, - CheatSystemError_FileOpenFailed = 1, - CheatSystemError_FileFormatInvalid = 2, - CheatSystemError_CheatNotFound = 3, - CheatSystemError_ExportError = 4, - CheatSystemError_FileSaveFailed = 5 -}; - union DesmumeCheatSearchItem { uint64_t data; @@ -95,8 +87,8 @@ protected: bool _willAddFromDB; CheatType _cheatType; - std::string _descriptionMajorString; - std::string _descriptionMinorString; + std::string _nameString; + std::string _commentString; // Internal cheat type parameters CheatFreezeType _freezeType; @@ -133,8 +125,11 @@ public: void SetType(CheatType requestedType); bool IsSupportedType() const; - const char* GetMajorDescription() const; - void SetMajorDescription(const char *descriptionString); + const char* GetName() const; + void SetName(const char *nameString); + + const char* GetComments() const; + void SetComments(const char *commentString); CheatFreezeType GetFreezeType() const; void SetFreezeType(CheatFreezeType theFreezeType); @@ -346,6 +341,8 @@ public: - (void) destroyWorkingCopy; - (void) mergeToParent; ++ (void) setIconDirectory:(NSImage *)iconImage; ++ (NSImage *) iconDirectory; + (void) setIconInternalCheat:(NSImage *)iconImage; + (NSImage *) iconInternalCheat; + (void) setIconActionReplay:(NSImage *)iconImage; @@ -355,11 +352,83 @@ public: @end +@interface CocoaDSCheatDBEntry : NSObject +{ + CheatDBEntry *_dbEntry; + + CocoaDSCheatDBEntry *parent; + NSMutableArray *child; + NSInteger willAdd; + NSString *codeString; + + BOOL needSetMixedState; +} + +@property (readonly, nonatomic) NSString *name; +@property (readonly, nonatomic) NSString *comment; +@property (readonly, nonatomic) NSImage *icon; +@property (readonly, nonatomic) NSInteger entryCount; +@property (readonly, nonatomic) NSString *codeString; +@property (readonly, nonatomic) BOOL isDirectory; +@property (readonly, nonatomic) BOOL isCheatItem; +@property (assign) NSInteger willAdd; +@property (assign) BOOL needSetMixedState; +@property (assign) CocoaDSCheatDBEntry *parent; +@property (readonly, nonatomic) NSMutableArray *child; + +- (id) initWithDBEntry:(const CheatDBEntry *)dbEntry; +- (ClientCheatItem *) newClientItem; + +@end + +@interface CocoaDSCheatDBGame : NSObject +{ + CheatDBGame *_dbGame; + CocoaDSCheatDBEntry *entryRoot; + NSUInteger index; +} + +@property (assign) NSUInteger index; +@property (readonly, nonatomic) NSString *title; +@property (readonly, nonatomic) NSString *serial; +@property (readonly, nonatomic) NSUInteger crc; +@property (readonly, nonatomic) NSString *crcString; +@property (readonly, nonatomic) NSInteger dataSize; +@property (readonly, nonatomic) NSString *dataSizeString; +@property (readonly, nonatomic) BOOL isDataLoaded; +@property (readonly, nonatomic) NSInteger cheatItemCount; +@property (readonly, nonatomic) CocoaDSCheatDBEntry *entryRoot; + +- (id) initWithGameEntry:(const CheatDBGame *)gameEntry; +- (CocoaDSCheatDBEntry *) loadEntryDataFromFilePtr:(FILE *)fp isEncrypted:(BOOL)isEncrypted; + +@end + +@interface CocoaDSCheatDatabase : NSObject +{ + CheatDBFile *_dbFile; + CheatDBGameList *_dbGameList; + NSMutableArray *gameList; + + NSURL *lastFileURL; +} + +@property (readonly) NSURL *lastFileURL; +@property (readonly, nonatomic) NSString *description; +@property (readonly, nonatomic) NSString *formatString; +@property (readonly, nonatomic) BOOL isEncrypted; +@property (readonly) NSMutableArray *gameList; + +- (id) initWithFileURL:(NSURL *)fileURL error:(CheatSystemError *)errorCode; +- (CocoaDSCheatDBGame *) getGameEntryUsingCode:(const char *)gameCode crc:(NSUInteger)crc; +- (CocoaDSCheatDBEntry *) loadGameEntry:(CocoaDSCheatDBGame *)dbGame; + +@end + @interface CocoaDSCheatManager : NSObject { ClientCheatManager *_internalCheatManager; NSMutableArray *sessionList; - NSMutableArray *databaseList; NSMutableArray *searchResultsList; pthread_rwlock_t *rwlockCoreExecute; @@ -367,11 +436,10 @@ public: @property (readonly, nonatomic, getter=internalManager) ClientCheatManager *_internalCheatManager; @property (readonly) NSMutableArray *sessionList; +@property (readonly, nonatomic) NSString *currentGameCode; +@property (readonly, nonatomic) NSUInteger currentGameCRC; @property (readonly, nonatomic) NSUInteger itemTotalCount; @property (readonly, nonatomic) NSUInteger itemActiveCount; -@property (readonly) NSMutableArray *databaseList; -@property (readonly, nonatomic) NSString *databaseTitle; -@property (readonly, nonatomic) NSString *databaseDate; @property (readonly) NSMutableArray *searchResultsList; @property (readonly, nonatomic) BOOL searchDidStart; @property (readonly, nonatomic) NSUInteger searchCount; @@ -390,8 +458,7 @@ public: - (void) loadFromMaster; - (void) applyToMaster; -- (NSMutableArray *) databaseListLoadFromFile:(NSURL *)fileURL errorCode:(NSInteger *)error; -- (NSUInteger) databaseAddSelected; +- (NSUInteger) databaseAddSelectedInEntry:(CocoaDSCheatDBEntry *)theEntry; - (NSUInteger) runExactValueSearch:(NSInteger)value byteSize:(UInt8)byteSize signType:(NSInteger)signType; - (NSUInteger) runComparativeSearch:(NSInteger)typeID byteSize:(UInt8)byteSize signType:(NSInteger)signType; diff --git a/desmume/src/frontend/cocoa/cocoa_cheat.mm b/desmume/src/frontend/cocoa/cocoa_cheat.mm index f60532484..31fbb83b3 100644 --- a/desmume/src/frontend/cocoa/cocoa_cheat.mm +++ b/desmume/src/frontend/cocoa/cocoa_cheat.mm @@ -20,7 +20,6 @@ #import "cocoa_globals.h" #import "cocoa_util.h" -#include "../../cheatSystem.h" #include "../../MMU.h" #undef BOOL @@ -178,8 +177,8 @@ ClientCheatItem::ClientCheatItem() _willAddFromDB = false; _cheatType = CheatType_Internal; - _descriptionMajorString = "No description."; - _descriptionMinorString = ""; + _nameString = "No description."; + _commentString = ""; _freezeType = CheatFreezeType_Normal; _address = 0x02000000; strncpy(_addressString, "0x02000000", sizeof(_addressString)); @@ -203,8 +202,8 @@ void ClientCheatItem::Init(const CHEATS_LIST &inCheatItem) this->_isEnabled = (inCheatItem.enabled) ? true : false; this->_cheatType = (CheatType)inCheatItem.type; - this->_descriptionMajorString = inCheatItem.description; - this->_descriptionMinorString = ""; + this->_nameString = inCheatItem.description; + this->_commentString = ""; this->_freezeType = (CheatFreezeType)inCheatItem.freezeType; this->_valueLength = inCheatItem.size + 1; // CHEATS_LIST.size value range is [1...4], but starts counting from 0. @@ -240,7 +239,8 @@ void ClientCheatItem::Init(const CHEATS_LIST &inCheatItem) void ClientCheatItem::Init(const ClientCheatItem &inCheatItem) { this->SetEnabled(inCheatItem.IsEnabled()); - this->SetMajorDescription(inCheatItem.GetMajorDescription()); + this->SetName(inCheatItem.GetName()); + this->SetComments(inCheatItem.GetComments()); this->SetType(inCheatItem.GetType()); this->SetFreezeType(inCheatItem.GetFreezeType()); @@ -324,20 +324,37 @@ bool ClientCheatItem::IsSupportedType() const return (this->_cheatType != CheatType_CodeBreaker); } -const char* ClientCheatItem::GetMajorDescription() const +const char* ClientCheatItem::GetName() const { - return this->_descriptionMajorString.c_str(); + return this->_nameString.c_str(); } -void ClientCheatItem::SetMajorDescription(const char *descriptionString) +void ClientCheatItem::SetName(const char *nameString) { - if (descriptionString == NULL) + if (nameString == NULL) { - this->_descriptionMajorString = ""; + this->_nameString = ""; } else { - this->_descriptionMajorString = descriptionString; + this->_nameString = nameString; + } +} + +const char* ClientCheatItem::GetComments() const +{ + return this->_commentString.c_str(); +} + +void ClientCheatItem::SetComments(const char *commentString) +{ + if (commentString == NULL) + { + this->_commentString = ""; + } + else + { + this->_commentString = commentString; } } @@ -610,7 +627,7 @@ void ClientCheatItem::ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const outCheatItem->type = this->_cheatType; outCheatItem->enabled = (this->_isEnabled) ? 1 : 0; - strncpy(outCheatItem->description, this->_descriptionMajorString.c_str(), sizeof(outCheatItem->description)); + strncpy(outCheatItem->description, this->_nameString.c_str(), sizeof(outCheatItem->description)); switch (this->_cheatType) { @@ -1110,7 +1127,7 @@ ClientCheatList* ClientCheatDatabase::LoadFromFile(const char *dbFilePath) } else { - dbError = (CheatSystemError)exporter->getErrorCode(); + dbError = exporter->getErrorCode(); } delete exporter; @@ -1244,11 +1261,11 @@ ClientCheatItem* ClientCheatManager::NewItem() char newDesc[16]; snprintf(newDesc, sizeof(newDesc), "Untitled %ld", (unsigned long)this->_untitledCount); - newItem->SetMajorDescription(newDesc); + newItem->SetName(newDesc); } else { - newItem->SetMajorDescription("Untitled"); + newItem->SetName("Untitled"); } if (newItem->IsEnabled()) @@ -1511,6 +1528,7 @@ void ClientCheatManager::ApplyPendingInternalCheatWrites() @implementation CocoaDSCheatItem +static NSImage *iconDirectory = nil; static NSImage *iconInternalCheat = nil; static NSImage *iconActionReplay = nil; static NSImage *iconCodeBreaker = nil; @@ -1625,18 +1643,18 @@ static NSImage *iconCodeBreaker = nil; - (NSString *) description { - return [NSString stringWithCString:_internalData->GetMajorDescription() encoding:NSUTF8StringEncoding]; + return [NSString stringWithCString:_internalData->GetName() encoding:NSUTF8StringEncoding]; } - (void) setDescription:(NSString *)desc { if (desc == nil) { - _internalData->SetMajorDescription(NULL); + _internalData->SetName(NULL); } else { - _internalData->SetMajorDescription([desc cStringUsingEncoding:NSUTF8StringEncoding]); + _internalData->SetName([desc cStringUsingEncoding:NSUTF8StringEncoding]); } if ((workingCopy != nil) && !_disableWorkingCopyUpdate) @@ -1647,7 +1665,7 @@ static NSImage *iconCodeBreaker = nil; - (char *) descriptionCString { - return (char *)_internalData->GetMajorDescription(); + return (char *)_internalData->GetName(); } - (NSInteger) cheatType @@ -1661,7 +1679,7 @@ static NSImage *iconCodeBreaker = nil; switch (theType) { - case CHEAT_TYPE_INTERNAL: + case CheatType_Internal: [self setCheatTypeIcon:iconInternalCheat]; [self setIsSupportedCheatType:YES]; [self setMemAddress:[self memAddress]]; @@ -1669,13 +1687,13 @@ static NSImage *iconCodeBreaker = nil; [self setBytes:[self bytes]]; break; - case CHEAT_TYPE_ACTION_REPLAY: + case CheatType_ActionReplay: [self setCheatTypeIcon:iconActionReplay]; [self setIsSupportedCheatType:YES]; [self setCode:[self code]]; break; - case CHEAT_TYPE_CODE_BREAKER: + case CheatType_CodeBreaker: [self setCheatTypeIcon:iconCodeBreaker]; [self setIsSupportedCheatType:NO]; [self setCode:[self code]]; @@ -1702,15 +1720,15 @@ static NSImage *iconCodeBreaker = nil; switch ([self cheatType]) { - case CHEAT_TYPE_INTERNAL: + case CheatType_Internal: theIcon = iconInternalCheat; break; - case CHEAT_TYPE_ACTION_REPLAY: + case CheatType_ActionReplay: theIcon = iconActionReplay; break; - case CHEAT_TYPE_CODE_BREAKER: + case CheatType_CodeBreaker: theIcon = iconCodeBreaker; break; @@ -1874,7 +1892,7 @@ static NSImage *iconCodeBreaker = nil; [self setCheatType:[self cheatType]]; [self setFreezeType:[self freezeType]]; - if ([self cheatType] == CHEAT_TYPE_INTERNAL) + if ([self cheatType] == CheatType_Internal) { [self setMemAddressSixDigitString:[self memAddressSixDigitString]]; [self setValue:[self value]]; @@ -1903,7 +1921,7 @@ static NSImage *iconCodeBreaker = nil; [self setCheatType:[cdsCheatItem cheatType]]; [self setFreezeType:[cdsCheatItem freezeType]]; - if ([self cheatType] == CHEAT_TYPE_INTERNAL) + if ([self cheatType] == CheatType_Internal) { [self setMemAddress:[cdsCheatItem memAddress]]; [self setValue:[cdsCheatItem value]]; @@ -1952,6 +1970,16 @@ static NSImage *iconCodeBreaker = nil; [parent copyFrom:self]; } ++ (void) setIconDirectory:(NSImage *)iconImage +{ + iconDirectory = iconImage; +} + ++ (NSImage *) iconDirectory +{ + return iconDirectory; +} + + (void) setIconInternalCheat:(NSImage *)iconImage { iconInternalCheat = iconImage; @@ -1984,16 +2012,615 @@ static NSImage *iconCodeBreaker = nil; @end +@implementation CocoaDSCheatDBEntry + +@dynamic name; +@dynamic comment; +@dynamic icon; +@dynamic entryCount; +@dynamic codeString; +@dynamic isDirectory; +@dynamic isCheatItem; +@dynamic willAdd; +@synthesize needSetMixedState; +@synthesize parent; +@synthesize child; + +- (id)init +{ + return [self initWithDBEntry:NULL]; +} + +- (id) initWithDBEntry:(const CheatDBEntry *)dbEntry +{ + self = [super init]; + if (self == nil) + { + return self; + } + + if (dbEntry == NULL) + { + [self release]; + self = nil; + return self; + } + + if (dbEntry->codeLength == NULL) + { + const NSUInteger entryCount = dbEntry->child.size(); + child = [[NSMutableArray alloc] initWithCapacity:entryCount]; + if (child == nil) + { + [self release]; + self = nil; + return self; + } + + for (NSUInteger i = 0; i < entryCount; i++) + { + const CheatDBEntry &childEntry = dbEntry->child[i]; + + CocoaDSCheatDBEntry *newCocoaEntry = [[CocoaDSCheatDBEntry alloc] initWithDBEntry:&childEntry]; + [newCocoaEntry setParent:self]; + [child addObject:newCocoaEntry]; + } + } + else + { + child = nil; + } + + _dbEntry = (CheatDBEntry *)dbEntry; + codeString = nil; + willAdd = NO; + needSetMixedState = NO; + parent = nil; + + return self; +} + +- (void)dealloc +{ + [child release]; + child = nil; + + [codeString release]; + codeString = nil; + + [super dealloc]; +} + +- (NSString *) name +{ + if (_dbEntry->name != NULL) + { + return [NSString stringWithCString:_dbEntry->name encoding:NSUTF8StringEncoding]; + } + + return @""; +} + +- (NSString *) comment +{ + if (_dbEntry->note != NULL) + { + return [NSString stringWithCString:_dbEntry->note encoding:NSUTF8StringEncoding]; + } + + return @""; +} + +- (NSImage *) icon +{ + if (_dbEntry->codeLength == NULL) + { + return [CocoaDSCheatItem iconDirectory]; + } + + return [CocoaDSCheatItem iconActionReplay]; +} + +- (NSInteger) entryCount +{ + return (NSInteger)_dbEntry->child.size(); +} + +- (NSString *) codeString +{ + if ( (codeString == nil) && [self isCheatItem] ) + { + char codeStr[8+8+1+1+1] = {0}; + const size_t codeCount = *_dbEntry->codeLength / 2; + + u32 code0 = _dbEntry->codeData[0]; + u32 code1 = _dbEntry->codeData[1]; + snprintf(codeStr, sizeof(codeStr), "%08X %08X", code0, code1); + std::string code = codeStr; + + for (size_t i = 1; i < codeCount; i++) + { + code0 = _dbEntry->codeData[(i * 2) + 0]; + code1 = _dbEntry->codeData[(i * 2) + 1]; + snprintf(codeStr, sizeof(codeStr), "\n%08X %08X", code0, code1); + code += codeStr; + } + + codeString = [[NSString alloc] initWithCString:code.c_str() encoding:NSUTF8StringEncoding]; + } + + return codeString; +} + +- (BOOL) isDirectory +{ + return (_dbEntry->codeLength == NULL) ? YES : NO; +} + +- (BOOL) isCheatItem +{ + return (_dbEntry->codeLength != NULL) ? YES : NO; +} + +- (void) setWillAdd:(NSInteger)theState +{ + if ((theState == GUI_STATE_MIXED) && ![self needSetMixedState]) + { + theState = GUI_STATE_ON; + } + + if (willAdd == theState) + { + return; + } + else + { + willAdd = theState; + } + + if (theState == GUI_STATE_MIXED) + { + if (parent != nil) + { + [parent willChangeValueForKey:@"willAdd"]; + [parent setNeedSetMixedState:YES]; + [parent setWillAdd:GUI_STATE_MIXED]; + [parent setNeedSetMixedState:NO]; + [parent didChangeValueForKey:@"willAdd"]; + } + + return; + } + + if (_dbEntry->codeLength == NULL) + { + for (CocoaDSCheatDBEntry *childEntry in child) + { + [childEntry willChangeValueForKey:@"willAdd"]; + [childEntry setWillAdd:theState]; + [childEntry didChangeValueForKey:@"willAdd"]; + } + } + + if (parent != nil) + { + NSInteger firstEntryState = [(CocoaDSCheatDBEntry *)[[parent child] objectAtIndex:0] willAdd]; + BOOL isMixedStateFound = (firstEntryState == GUI_STATE_MIXED); + + if (!isMixedStateFound) + { + for (CocoaDSCheatDBEntry *childEntry in [parent child]) + { + const NSInteger childEntryState = [childEntry willAdd]; + + isMixedStateFound = (firstEntryState != childEntryState) || (childEntryState == GUI_STATE_MIXED); + if (isMixedStateFound) + { + [parent willChangeValueForKey:@"willAdd"]; + [parent setNeedSetMixedState:YES]; + [parent setWillAdd:GUI_STATE_MIXED]; + [parent setNeedSetMixedState:NO]; + [parent didChangeValueForKey:@"willAdd"]; + break; + } + } + } + + if (!isMixedStateFound) + { + [parent willChangeValueForKey:@"willAdd"]; + [parent setWillAdd:firstEntryState]; + [parent didChangeValueForKey:@"willAdd"]; + } + } +} + +- (NSInteger) willAdd +{ + return willAdd; +} + +- (ClientCheatItem *) newClientItem +{ + ClientCheatItem *newItem = NULL; + if (![self isCheatItem]) + { + return newItem; + } + + newItem = new ClientCheatItem; + newItem->SetType(CheatType_ActionReplay); // Default to Action Replay for now + newItem->SetFreezeType(CheatFreezeType_Normal); + newItem->SetEnabled(false); + newItem->SetComments(_dbEntry->note); + + CheatDBEntry *entryParent = _dbEntry->parent; + + // TODO: Replace this flattening out of names/comments with separated names/comments and tags. + std::string descString = ""; + std::string itemString = ""; + + if ( ((_dbEntry->name != NULL) && (*_dbEntry->name != '\0')) || + ((_dbEntry->note != NULL) && (*_dbEntry->note != '\0')) ) + { + if ( (_dbEntry->name != NULL) && (*_dbEntry->name != '\0') ) + { + itemString += _dbEntry->name; + } + + if ( (_dbEntry->note != NULL) && (*_dbEntry->note != '\0') ) + { + if ( (_dbEntry->name != NULL) && (*_dbEntry->name != '\0') ) + { + itemString += " | "; + } + + itemString += _dbEntry->note; + } + } + else + { + itemString = "No description."; + } + + // If this entry is root or child of root, then don't add the directory + // name or comments to the new cheat item's description. + if ( (entryParent == NULL) || (entryParent->parent == NULL) ) + { + descString = itemString; + } + else + { + if ( (entryParent->name != NULL) && (*entryParent->name != '\0') ) + { + descString += entryParent->name; + } + + if ( (entryParent->note != NULL) && (*entryParent->note != '\0') ) + { + if ( (entryParent->name != NULL) && (*entryParent->name != '\0') ) + { + descString += " "; + } + + descString += "["; + descString += entryParent->note; + descString += "]"; + } + + descString += ": "; + descString += itemString; + } + + newItem->SetName(descString.c_str()); + newItem->SetRawCodeString([[self codeString] cStringUsingEncoding:NSUTF8StringEncoding], true); + + return newItem; +} + +@end + +@implementation CocoaDSCheatDBGame + +@synthesize index; +@dynamic title; +@dynamic serial; +@dynamic crc; +@dynamic crcString; +@dynamic dataSize; +@dynamic isDataLoaded; +@dynamic cheatItemCount; +@synthesize entryRoot; + +- (id)init +{ + return [self initWithGameEntry:NULL]; +} + +- (id) initWithGameEntry:(const CheatDBGame *)gameEntry +{ + self = [super init]; + if (self == nil) + { + return self; + } + + _dbGame = (CheatDBGame *)gameEntry; + entryRoot = nil; + index = 0; + + return self; +} + +- (void)dealloc +{ + [entryRoot release]; + entryRoot = nil; + + [super dealloc]; +} + +- (NSString *) title +{ + return [NSString stringWithCString:_dbGame->GetTitle() encoding:NSUTF8StringEncoding]; +} + +- (NSString *) serial +{ + return [NSString stringWithCString:_dbGame->GetSerial() encoding:NSUTF8StringEncoding]; +} + +- (NSUInteger) crc +{ + return (NSUInteger)_dbGame->GetCRC(); +} + +- (NSString *) crcString +{ + const u32 crc = _dbGame->GetCRC(); + return [NSString stringWithFormat:@"%08lX", (unsigned long)crc]; +} + +- (NSInteger) dataSize +{ + return (NSInteger)_dbGame->GetRawDataSize(); +} + +- (NSString *) dataSizeString +{ + const u32 dataSize = _dbGame->GetRawDataSize(); + const float dataSizeKB = (float)dataSize / 1024.0f; + + if (dataSize > ((1024 * 100) - 1)) + { + return [NSString stringWithFormat:@"%1.1f KB", dataSizeKB]; + } + else if (dataSize > ((1024 * 10) - 1)) + { + return [NSString stringWithFormat:@"%1.2f KB", dataSizeKB]; + } + + return [NSString stringWithFormat:@"%lu bytes", (unsigned long)dataSize]; +} + +- (BOOL) isDataLoaded +{ + return (_dbGame->IsEntryDataLoaded()) ? YES : NO; +} + +- (NSInteger) cheatItemCount +{ + return (NSInteger)_dbGame->GetCheatItemCount(); +} + +- (CocoaDSCheatDBEntry *) loadEntryDataFromFilePtr:(FILE *)fp isEncrypted:(BOOL)isEncrypted +{ + [entryRoot release]; + entryRoot = nil; + + u8 *entryData = _dbGame->LoadEntryData(fp, (isEncrypted) ? true : false); + if (entryData == NULL) + { + return entryRoot; + } + + entryRoot = [[CocoaDSCheatDBEntry alloc] initWithDBEntry:&_dbGame->GetEntryRoot()]; + return entryRoot; +} + +@end + +@implementation CocoaDSCheatDatabase + +@synthesize lastFileURL; +@dynamic description; +@dynamic formatString; +@dynamic isEncrypted; +@synthesize gameList; + +- (id)init +{ + return [self initWithFileURL:nil error:NULL]; +} + +- (id) initWithFileURL:(NSURL *)fileURL error:(CheatSystemError *)errorCode +{ + self = [super init]; + if (self == nil) + { + return self; + } + + if (fileURL == nil) + { + [self release]; + self = nil; + return self; + } + + lastFileURL = [fileURL copy]; + + CheatDBFile *newDBFile = new CheatDBFile(); + if (newDBFile == NULL) + { + [lastFileURL release]; + [self release]; + self = nil; + return self; + } + + CheatSystemError error = newDBFile->OpenFile([CocoaDSUtil cPathFromFileURL:fileURL]); + if (error != CheatSystemError_NoError) + { + delete newDBFile; + + if (errorCode != nil) + { + *errorCode = error; + } + + [lastFileURL release]; + [self release]; + self = nil; + return self; + } + + _dbGameList = new CheatDBGameList; + if (_dbGameList == NULL) + { + delete newDBFile; + + if (errorCode == nil) + { + *errorCode = error; + } + + [lastFileURL release]; + [self release]; + self = nil; + return self; + } + + newDBFile->LoadGameList(NULL, 0, *_dbGameList); + const size_t gameCount = _dbGameList->size(); + + gameList = [[NSMutableArray alloc] initWithCapacity:gameCount]; + if (gameList == nil) + { + delete newDBFile; + + if (errorCode == nil) + { + *errorCode = error; + } + + [lastFileURL release]; + [self release]; + self = nil; + return self; + } + + for (size_t i = 0; i < gameCount; i++) + { + const CheatDBGame &dbGame = (*_dbGameList)[i]; + CocoaDSCheatDBGame *newCocoaDBGame = [[[CocoaDSCheatDBGame alloc] initWithGameEntry:&dbGame] autorelease]; + + [gameList addObject:newCocoaDBGame]; + [newCocoaDBGame setIndex:[gameList indexOfObject:newCocoaDBGame]]; + } + + _dbFile = newDBFile; + + return self; +} + +- (void)dealloc +{ + [gameList release]; + [lastFileURL release]; + + delete _dbGameList; + _dbGameList = NULL; + + delete _dbFile; + _dbFile = NULL; + + [super dealloc]; +} + +- (NSString *) description +{ + return [NSString stringWithCString:_dbFile->GetDescription() encoding:NSUTF8StringEncoding]; +} + +- (NSString *) formatString +{ + return [NSString stringWithCString:_dbFile->GetFormatString() encoding:NSUTF8StringEncoding]; +} + +- (BOOL) isEncrypted +{ + return (_dbFile->IsEncrypted()) ? YES : NO; +} + +- (CocoaDSCheatDBGame *) getGameEntryUsingCode:(const char *)gameCode crc:(NSUInteger)crc +{ + if (gameCode == nil) + { + return nil; + } + + const char gameCodeTerminated[5] = { + gameCode[0], + gameCode[1], + gameCode[2], + gameCode[3], + '\0' + }; + + NSString *gameCodeString = [NSString stringWithCString:gameCodeTerminated encoding:NSUTF8StringEncoding]; + + for (CocoaDSCheatDBGame *dbGame in gameList) + { + if ( ([dbGame crc] == crc) && [[dbGame serial] isEqualToString:gameCodeString] ) + { + return dbGame; + } + } + + return nil; +} + +- (CocoaDSCheatDBEntry *) loadGameEntry:(CocoaDSCheatDBGame *)dbGame +{ + CocoaDSCheatDBEntry *entryRoot = nil; + + if (dbGame == nil) + { + return entryRoot; + } + else if ([dbGame isDataLoaded]) + { + entryRoot = [dbGame entryRoot]; + } + else + { + entryRoot = [dbGame loadEntryDataFromFilePtr:_dbFile->GetFilePtr() isEncrypted:_dbFile->IsEncrypted()]; + } + + return entryRoot; +} + +@end @implementation CocoaDSCheatManager @synthesize _internalCheatManager; @synthesize sessionList; +@dynamic currentGameCode; +@dynamic currentGameCRC; @dynamic itemTotalCount; @dynamic itemActiveCount; -@synthesize databaseList; -@dynamic databaseTitle; -@dynamic databaseDate; @synthesize searchResultsList; @dynamic searchCount; @dynamic searchDidStart; @@ -2023,20 +2650,10 @@ static NSImage *iconCodeBreaker = nil; return self; } - databaseList = [[NSMutableArray alloc] initWithCapacity:100]; - if (databaseList == nil) - { - [sessionList release]; - [self release]; - self = nil; - return self; - } - searchResultsList = [[NSMutableArray alloc] initWithCapacity:100]; if (searchResultsList == nil) { [sessionList release]; - [databaseList release]; [self release]; self = nil; return self; @@ -2055,9 +2672,6 @@ static NSImage *iconCodeBreaker = nil; [sessionList release]; sessionList = nil; - [databaseList release]; - databaseList = nil; - [searchResultsList release]; searchResultsList = nil; @@ -2067,14 +2681,22 @@ static NSImage *iconCodeBreaker = nil; [super dealloc]; } -- (NSString *) databaseTitle +- (NSString *) currentGameCode { - return [NSString stringWithCString:_internalCheatManager->GetDatabaseTitle() encoding:NSUTF8StringEncoding]; + const char gameCodeTerminated[5] = { + gameInfo.header.gameCode[0], + gameInfo.header.gameCode[1], + gameInfo.header.gameCode[2], + gameInfo.header.gameCode[3], + '\0' + }; + + return [NSString stringWithCString:gameCodeTerminated encoding:NSUTF8StringEncoding]; } -- (NSString *) databaseDate +- (NSUInteger) currentGameCRC { - return [NSString stringWithCString:_internalCheatManager->GetDatabaseDescription() encoding:NSUTF8StringEncoding]; + return (NSUInteger)gameInfo.crcForCheatsDb; } - (NSUInteger) itemTotalCount @@ -2251,59 +2873,38 @@ static NSImage *iconCodeBreaker = nil; _internalCheatManager->ApplyToMaster(); } -- (NSMutableArray *) databaseListLoadFromFile:(NSURL *)fileURL errorCode:(NSInteger *)error +- (NSUInteger) databaseAddSelectedInEntry:(CocoaDSCheatDBEntry *)theEntry { - if (fileURL == nil) + NSUInteger willAddCount = 0; + if (theEntry == nil) { - return nil; + return willAddCount; } - [self willChangeValueForKey:@"databaseTitle"]; - [self willChangeValueForKey:@"databaseDate"]; - - ClientCheatList *dbList = _internalCheatManager->DatabaseListLoadFromFile([CocoaDSUtil cPathFromFileURL:fileURL]); - - [self didChangeValueForKey:@"databaseTitle"]; - [self didChangeValueForKey:@"databaseDate"]; - - if (dbList != NULL) + NSMutableArray *entryChildren = [theEntry child]; + if (entryChildren == nil) { - [databaseList removeAllObjects]; - - const size_t itemCount = dbList->GetTotalCheatCount(); - for (size_t i = 0; i < itemCount; i++) + return willAddCount; + } + + for (CocoaDSCheatDBEntry *entry in entryChildren) + { + if ([entry isDirectory]) { - CocoaDSCheatItem *cheatItem = [[CocoaDSCheatItem alloc] initWithCheatItem:dbList->GetItemAtIndex(i)]; - if (cheatItem != nil) - { - [databaseList addObject:[cheatItem autorelease]]; - } + willAddCount += [self databaseAddSelectedInEntry:entry]; } - } - - return databaseList; -} - -- (NSUInteger) databaseAddSelected -{ - NSUInteger addedItemCount = 0; - - for (CocoaDSCheatItem *dbItem in databaseList) - { - if ([dbItem willAdd]) + else if ([entry willAdd]) { - ClientCheatItem *newCheatItem = new ClientCheatItem; - newCheatItem->Init(*[dbItem clientData]); - + ClientCheatItem *newCheatItem = [entry newClientItem]; CocoaDSCheatItem *newCocoaCheatItem = [self addExistingItem:newCheatItem]; if (newCocoaCheatItem != nil) { - addedItemCount++; + willAddCount++; } } } - return addedItemCount; + return willAddCount; } - (NSUInteger) runExactValueSearch:(NSInteger)value byteSize:(UInt8)byteSize signType:(NSInteger)signType diff --git a/desmume/src/frontend/cocoa/cocoa_globals.h b/desmume/src/frontend/cocoa/cocoa_globals.h index 43a13b846..bdd60eb28 100644 --- a/desmume/src/frontend/cocoa/cocoa_globals.h +++ b/desmume/src/frontend/cocoa/cocoa_globals.h @@ -1,6 +1,6 @@ /* Copyright (C) 2011 Roger Manuel - Copyright (C) 2012-2022 DeSmuME Team + Copyright (C) 2012-2023 DeSmuME Team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ #define NSSTRING_TITLE_EXPORT_ROM_SAVE_PANEL NSLocalizedString(@"Export ROM Save File", nil) #define NSSTRING_TITLE_SELECT_ROM_PANEL NSLocalizedString(@"Select ROM", nil) #define NSSTRING_TITLE_SELECT_ADVANSCENE_DB_PANEL NSLocalizedString(@"Select ADVANsCEne Database", nil) -#define NSSTRING_TITLE_SELECT_R4_CHEAT_DB_PANEL NSLocalizedString(@"Select R4 Cheat Database", nil) +#define NSSTRING_TITLE_OPEN_CHEAT_DB_PANEL NSLocalizedString(@"Open Cheat Database", nil) #define NSSTRING_TITLE_SELECT_ARM7_IMAGE_PANEL NSLocalizedString(@"Select ARM7 BIOS Image", nil) #define NSSTRING_TITLE_SELECT_ARM9_IMAGE_PANEL NSLocalizedString(@"Select ARM9 BIOS Image", nil) #define NSSTRING_TITLE_SELECT_FIRMWARE_IMAGE_PANEL NSLocalizedString(@"Select Firmware Image", nil) @@ -303,41 +303,12 @@ enum SPU_SYNC_METHOD_P = 2 }; -enum -{ - CHEAT_TYPE_INTERNAL = 0, - CHEAT_TYPE_ACTION_REPLAY = 1, - CHEAT_TYPE_CODE_BREAKER = 2 -}; - -enum -{ - CHEATSEARCH_SEARCHSTYLE_EXACT_VALUE = 0, - CHEATSEARCH_SEARCHSTYLE_COMPARATIVE = 1 -}; - -enum -{ - CHEATSEARCH_COMPARETYPE_GREATER_THAN = 0, - CHEATSEARCH_COMPARETYPE_LESSER_THAN = 1, - CHEATSEARCH_COMPARETYPE_EQUALS_TO = 2, - CHEATSEARCH_COMPARETYPE_NOT_EQUALS_TO = 3 -}; - enum { CHEATSEARCH_UNSIGNED = 0, CHEATSEARCH_SIGNED = 1 }; -enum -{ - CHEATEXPORT_ERROR_FILE_NOT_FOUND = 1, - CHEATEXPORT_ERROR_WRONG_FILE_FORMAT = 2, - CHEATEXPORT_ERROR_SERIAL_NOT_FOUND = 3, - CHEATEXPORT_ERROR_EXPORT_FAILED = 4 -}; - /* PORT MESSAGES */ diff --git a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm index 71e266cd8..9a4f9c902 100644 --- a/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm +++ b/desmume/src/frontend/cocoa/openemu/NDSGameCore.mm @@ -1199,7 +1199,8 @@ void UpdateDisplayPropertiesFromStates(uint64_t displayModeStates, ClientDisplay ClientCheatItem *newCheatItem = new ClientCheatItem; newCheatItem->SetType(CheatType_ActionReplay); // Default to Action Replay for now newCheatItem->SetFreezeType(CheatFreezeType_Normal); - newCheatItem->SetMajorDescription(NULL); // OpenEmu takes care of this + newCheatItem->SetName(NULL); // OpenEmu takes care of this + newCheatItem->SetComments(NULL); // OpenEmu does not support cheat item comments newCheatItem->SetRawCodeString([code cStringUsingEncoding:NSUTF8StringEncoding], true); newCheatItem->SetEnabled((enabled) ? true : false); diff --git a/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib b/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib new file mode 100644 index 000000000..f4df17c48 --- /dev/null +++ b/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib @@ -0,0 +1,4058 @@ + + + + 1060 + 13F1911 + 851 + 1265.21 + 698.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 851 + + + YES + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + YES + + + YES + + + + YES + + CheatDatabaseWindowController + + + FirstResponder + + + NSApplication + + + 15 + 2 + {{235, 175}, {640, 480}} + 74973184 + Cheat Database Viewer + NSWindow + + + {1.7976931348623157e+308, 1.7976931348623157e+308} + {480, 400} + + + 256 + + YES + + + 268 + {{17, 452}, {60, 14}} + + + YES + + 68157504 + 4326400 + File Path: + + LucidaGrande-Bold + 11 + 3344 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + NO + 1 + + + + 292 + {{43, 3}, {114, 32}} + + + YES + + 67108864 + 134217728 + Select All + + LucidaGrande + 13 + 1040 + + + -2038284288 + 129 + + + 200 + 25 + + NO + + + + 292 + {{157, 3}, {114, 32}} + + + YES + + 67108864 + 134217728 + Select None + + + -2038284288 + 129 + + + 200 + 25 + + NO + + + + 289 + {{530, 3}, {96, 32}} + + + 1 + YES + + 67108864 + 134217728 + Add + + + -2038284288 + 129 + + DQ + 200 + 25 + + NO + + + + 265 + {{429, 414}, {103, 14}} + + + YES + + 68157504 + 71435264 + Database Format: + + + + + + NO + 1 + + + + 266 + {{82, 451}, {444, 16}} + + + YES + + 77594689 + 272766464 + + + LucidaGrande + 11 + 3088 + + Database file path + + + + + NO + 1 + + + + 265 + {{534, 414}, {89, 14}} + + + YES + + 70254657 + 4330496 + + + DB Format + + + + + NO + 1 + + + + 265 + {{449, 397}, {83, 14}} + + + YES + + 68157504 + 71435264 + Game Count: + + + + + + NO + 1 + + + + 265 + + YES + + {{534, 397}, {89, 14}} + + + YES + + 70254657 + 4330496 + + + + YES + + YES + allowsFloats + formatterBehavior + locale + negativeInfinitySymbol + nilSymbol + positiveInfinitySymbol + usesGroupingSeparator + + + YES + + + + + + -∞ + + +∞ + + + + # + # + + + + + + + + NaN + + YES + + + YES + + + + + 0 + 0 + YES + NO + 1 + AAAAAAAAAAAAAAAAAAAAAA + + + + 3 + YES + YES + YES + + . + , + YES + NO + NO + + Count + + + + + NO + 1 + + + + 265 + {{434, 431}, {98, 14}} + + + YES + + 68157504 + 71435264 + Data Encryption: + + + + + + NO + 1 + + + + 268 + {{17, 422}, {90, 14}} + + + YES + + 68157504 + 4326400 + Game Search: + + + + + + NO + 1 + + + + 265 + {{534, 431}, {89, 14}} + + + YES + + 70254657 + 4330496 + + + Y/N + + + + + NO + 1 + + + + 265 + {{529, 444}, {96, 28}} + + + _NS:610 + YES + + 67108864 + 134348800 + Choose… + + _NS:610 + + -2038284288 + 129 + + + 200 + 25 + + NO + + + + 292 + {{11, 7}, {27, 27}} + + + YES + + -2080374784 + 134217728 + + + + -2033434624 + 160 + + NSImage + NSActionTemplate + + + + 400 + 75 + + NO + + + + 274 + + YES + + + 256 + + YES + + + 269 + {{304, 35.5}, {32, 32}} + + + _NS:4186 + 28682 + 100 + + + + 274 + + YES + + + 2304 + + YES + + + 256 + {638, 87} + + + _NS:1843 + YES + NO + YES + + + 256 + {638, 17} + + + _NS:1845 + + + + + -2147483392 + {{224, 0}, {16, 17}} + _NS:1848 + + + YES + + 40 + 40 + 1000 + + 75497536 + 67110912 + + + + 3 + MC4zMzMzMzI5ODU2AA + + + 6 + System + headerTextColor + + + + + 69206081 + -2080237568 + Text Cell + + LucidaGrande + 11 + 16 + + + + YES + + YES + allowsFloats + formatterBehavior + locale + negativeInfinitySymbol + nilSymbol + numberStyle + positiveInfinitySymbol + usesGroupingSeparator + + + YES + + + + -∞ + + + +∞ + + + + #0.### + #0.### + + + + + + + + NaN + + + + + + 3 + YES + YES + YES + + . + , + NO + NO + NO + + + + 6 + System + controlBackgroundColor + + + + + + + + 361 + 70 + 10000 + + 75497536 + 2048 + Title + + + + + + 69206081 + 137216 + Text Cell + + + + + + 3 + YES + YES + + + + 66 + 66 + 3.4028234663852886e+38 + + 75497536 + 134219776 + Serial + + + 6 + System + headerColor + + 3 + MQA + + + + + + 69206081 + 134354944 + Text Cell + + + + + + YES + + + + 70 + 70 + 3.4028234663852886e+38 + + 75497536 + 134219776 + CRC + + + + + + 69206081 + 134354944 + Text Cell + + + + + + YES + + + crc + YES + compare: + + + + 86 + 86 + 3.4028234663852886e+38 + + 75497536 + 134219776 + Data Size + + + + + + 69206081 + -2013128704 + Text Cell + + + + + + YES + + + dataSize + YES + compare: + + + + 3 + 2 + + + 6 + System + gridColor + + 3 + MC41AA + + + 15 + -692060160 + + + 4 + 15 + 0 + YES + 0 + 1 + + + {{1, 17}, {638, 87}} + + + _NS:1841 + + + 4 + + + + -2147483392 + {{224, 17}, {15, 102}} + + + _NS:1860 + NO + + _doScroller: + 0.98861788617886182 + + + + -2147483392 + {{1, 161}, {798, 16}} + + + _NS:1862 + NO + 1 + + _doScroller: + 0.99874843554443049 + + + + 2304 + + YES + + + {{1, 0}, {638, 17}} + + + _NS:1846 + + + 4 + + + {640, 105} + + + _NS:1839 + 133682 + + + + + QSAAAEEgAABBiAAAQYgAAA + 0.25 + 4 + 1 + + + {640, 105} + + + _NS:1030 + NSView + + + + 256 + + YES + + + 274 + + YES + + + 2304 + + YES + + + 256 + {638, 214} + + + _NS:1718 + YES + NO + YES + + + 256 + {638, 17} + + + _NS:1720 + + + + + -2147483392 + {{224, 0}, {16, 17}} + _NS:1724 + + + YES + + willAdd + 16 + 16 + 1000 + + 75497536 + 67110912 + + + + 3 + MC4zMzMzMzI5ODU2AA + + + + + 67108864 + 83886080 + + + _NS:1912 + + 1210863872 + 2 + + NSImage + NSSwitch + + + NSSwitch + + + + 200 + 25 + + + + + 84 + 84 + 1000 + + 75497536 + 2048 + + + + + + + 67108864 + 33554432 + + _NS:4163 + 4 + 0 + 0 + NO + + + + + 200 + 10 + 3.4028234663852886e+38 + + 75497536 + 2048 + Name + + + + + + 69206017 + 4096 + Text Cell + + + + + + 3 + YES + YES + + + + 326.09765625 + 10 + 3.4028234663852886e+38 + + 75497536 + 2048 + Comments + + + + + + 69206017 + 135168 + Text Cell + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 42 + -759169024 + + + 4 + 15 + 0 + YES + 0 + 1 + 17 + + + + {{1, 17}, {638, 214}} + + + _NS:1716 + + + 4 + + + + -2147483392 + {{783, 17}, {16, 38}} + + + _NS:1741 + NO + + _doScroller: + 0.86363636363636365 + + + + -2147483392 + {{1, 206}, {798, 16}} + + + _NS:1743 + NO + 1 + + _doScroller: + 0.99874843554443049 + + + + 2304 + + YES + + + {{1, 0}, {638, 17}} + + + _NS:1721 + + + 4 + + + {640, 232} + + + _NS:1714 + 133682 + + + + + QSAAAEEgAABCMAAAQjAAAA + 0.25 + 4 + 1 + + + {{0, 115}, {640, 233}} + + + _NS:1033 + NSView + + + {{0, 41}, {640, 348}} + + + _NS:1028 + 3 + CheatDatabaseViewerSplitter + + + + 266 + + YES + + {{20, 397}, {265, 22}} + + + _NS:845 + YES + + 342884416 + 268436544 + + Title + _NS:845 + + YES + 1 + + 6 + System + textBackgroundColor + + + + + 0 + 0 + search + + _searchFieldSearch: + + 138690560 + 0 + + 400 + 75 + + + 0 + 0 + clear + + YES + + YES + + YES + AXDescription + NSAccessibilityEncodedAttributesValueType + + + YES + cancel + + + + + + _searchFieldCancel: + + 138690560 + 0 + + 400 + 75 + + 255 + CAAAAA + + NO + 1 + + + + 265 + {{288, 393}, {136, 28}} + + + _NS:610 + YES + + 67108864 + 134348800 + Select Current Game + + _NS:610 + + -2038284288 + 129 + + + 200 + 25 + + NO + + + {640, 480} + + + + {{0, 0}, {1440, 878}} + {480, 422} + {1.7976931348623157e+308, 1.7976931348623157e+308} + CheatDatabaseViewer + YES + + + + 272 + + YES + + + 276 + + YES + + + 2304 + + YES + + + 2322 + {188, 328} + + + _NS:1498 + + + + + + + + + + YES + + + 134 + + + + 188 + 1 + + + 100673793 + 0 + + + + YES + + YES + NSBackgroundColor + NSColor + + + YES + + 6 + System + selectedTextBackgroundColor + + + + 6 + System + selectedTextColor + + + + + + + YES + + YES + NSColor + NSCursor + NSUnderline + + + YES + + 1 + MCAwIDEAA + + + {8, -8} + 13 + + + + + + + 1 + + 6 + {463, 10000000} + + + + {{1, 1.02734375}, {188, 328}} + + + + _NS:1496 + + + + {4, -5} + 1 + + 4 + + + + 256 + {{173, 1}, {16, 328}} + + + _NS:1512 + NO + + _doScroller: + 1 + 0.85256409645080566 + + + + -2147483392 + {{-100, -100}, {87, 18}} + + + _NS:1514 + NO + 1 + + _doScroller: + 1 + 0.94565218687057495 + + + {{5, 5.52734375}, {190, 330}} + + + + _NS:1494 + 133138 + + + + AAAAAEEgAAAAAAAAQSAAAA + 0.25 + 4 + 1 + + + + 268 + {{5, 343}, {190, 51}} + + + YES + + 69206017 + 272633856 + + + LucidaGrande-Bold + 13 + 16 + + Cheat Name + + + + + NO + 1 + + + {200, 400} + + + NSView + + + + {200, 400} + {0, 0} + {200, 10000} + 0 + 0.0 + 5 + + + + + 1 + 2 + {{157, 276}, {480, 185}} + 1685586944 + Error Sheet + NSWindow + + + {1.7976931348623157e+308, 1.7976931348623157e+308} + + + 256 + + YES + + + 289 + {{370, 12}, {96, 32}} + + + YES + + 67108864 + 134217728 + OK + + + -2038284288 + 129 + + DQ + 200 + 25 + + NO + + + + 268 + {{17, 148}, {446, 17}} + + + _NS:4068 + YES + + 70254657 + 272634880 + + + Major String + _NS:4068 + + + + + NO + 1 + + + + 268 + {{17, 44}, {446, 96}} + + + _NS:4068 + YES + + 69206017 + 272764928 + + + Minor String + _NS:4068 + + + + + NO + 1 + + + {480, 185} + + + + {{0, 0}, {1440, 878}} + {1.7976931348623157e+308, 1.7976931348623157e+308} + YES + + + + YES + title + serial + crcString + index + dataSize + dataSizeString + + CocoaDSCheatDBGame + + YES + YES + YES + YES + YES + + + + YES + name + comment + isDirectory + willAdd + icon + codeString + + CocoaDSCheatDBEntry + YES + + YES + YES + YES + child + isCheatItem + entryCount + + + + + YES + + + value: arrangedObjects.title + + + + + + value: arrangedObjects.title + value + arrangedObjects.title + + NSConditionallySetsEditable + + + 2 + + + 54 + + + + value: arrangedObjects.serial + + + + + + value: arrangedObjects.serial + value + arrangedObjects.serial + + NSConditionallySetsEditable + + + 2 + + + 55 + + + + value: arrangedObjects.crcString + + + + + + value: arrangedObjects.crcString + value + arrangedObjects.crcString + + NSConditionallySetsEditable + + + 2 + + + 56 + + + + value: arrangedObjects.index + + + + + + value: arrangedObjects.index + value + arrangedObjects.index + 2 + + + 58 + + + + value: arrangedObjects.icon + + + + + + value: arrangedObjects.icon + value + arrangedObjects.icon + 2 + + + 59 + + + + value: arrangedObjects.willAdd + + + + + + value: arrangedObjects.willAdd + value + arrangedObjects.willAdd + 2 + + + 60 + + + + value: arrangedObjects.name + + + + + + value: arrangedObjects.name + value + arrangedObjects.name + + NSConditionallySetsEditable + + + 2 + + + 61 + + + + value: arrangedObjects.comment + + + + + + value: arrangedObjects.comment + value + arrangedObjects.comment + + NSConditionallySetsEditable + + + 2 + + + 62 + + + + parentWindow + + + + 89 + + + + toggle: + + + + 92 + + + + contentView + + + + 100 + + + + addSelected: + + + + 101 + + + + selectAll: + + + + 102 + + + + selectNone: + + + + 103 + + + + openFile: + + + + 104 + + + + gameListController + + + + 105 + + + + window + + + + 106 + + + + entryListController + + + + 107 + + + + value: filePath + + + + + + value: filePath + value + filePath + 2 + + + 108 + + + + value: gameCount + + + + + + value: gameCount + value + gameCount + 2 + + + 109 + + + + value: isEncryptedString + + + + + + value: isEncryptedString + value + isEncryptedString + 2 + + + 110 + + + + value: databaseFormatString + + + + + + value: databaseFormatString + value + databaseFormatString + 2 + + + 111 + + + + value: arrangedObjects.dataSizeString + + + + + + value: arrangedObjects.dataSizeString + value + arrangedObjects.dataSizeString + + NSConditionallySetsEditable + + + 2 + + + 112 + + + + animate: isFileLoading + + + + + + animate: isFileLoading + animate + isFileLoading + 2 + + + 124 + + + + enabled: isFileLoading + + + + + + enabled: isFileLoading + enabled + isFileLoading + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 125 + + + + enabled: isFileLoading + + + + + + enabled: isFileLoading + enabled + isFileLoading + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 126 + + + + gameTable + + + + 128 + + + + delegate + + + + 129 + + + + delegate + + + + 130 + + + + entryOutline + + + + 131 + + + + value: selection.name + + + + + + value: selection.name + value + selection.name + 2 + + + 133 + + + + value: selection.codeString + + + + + + value: selection.codeString + value + selection.codeString + + NSConditionallySetsEditable + + + 2 + + + 147 + + + + font: codeViewerFont + + + + + + font: codeViewerFont + font + codeViewerFont + 2 + + + 148 + + + + delegate + + + + 186 + + + + splitView + + + + 189 + + + + selectCurrentGame: + + + + 196 + + + + enabled: isCurrentGameFound + + + + + + enabled: isCurrentGameFound + enabled + isCurrentGameFound + 2 + + + 197 + + + + enabled: isCurrentGameFound + + + + + + enabled: isCurrentGameFound + enabled + isCurrentGameFound + 2 + + + 198 + + + + enabled: isCurrentGameFound + + + + + + enabled: isCurrentGameFound + enabled + isCurrentGameFound + 2 + + + 199 + + + + enabled: isCurrentGameFound + + + + + + enabled: isCurrentGameFound + enabled + isCurrentGameFound + 2 + + + 200 + + + + enabled2: isSelectedGameTheCurrentGame + + + + + + enabled2: isSelectedGameTheCurrentGame + enabled2 + isSelectedGameTheCurrentGame + + YES + + YES + NSMultipleValuesPlaceholder + NSNoSelectionPlaceholder + NSNotApplicablePlaceholder + NSNullPlaceholder + + + YES + + + + + + + + 2 + + + 201 + + + + enabled2: isSelectedGameTheCurrentGame + + + + + + enabled2: isSelectedGameTheCurrentGame + enabled2 + isSelectedGameTheCurrentGame + + YES + + YES + NSMultipleValuesPlaceholder + NSNoSelectionPlaceholder + NSNotApplicablePlaceholder + NSNullPlaceholder + + + YES + + + + + + + + 2 + + + 202 + + + + enabled2: isSelectedGameTheCurrentGame + + + + + + enabled2: isSelectedGameTheCurrentGame + enabled2 + isSelectedGameTheCurrentGame + + YES + + YES + NSMultipleValuesPlaceholder + NSNoSelectionPlaceholder + NSNotApplicablePlaceholder + NSNullPlaceholder + + + YES + + + + + + + + 2 + + + 203 + + + + errorSheet + + + + 204 + + + + closeErrorSheet: + + + + 209 + + + + value: errorMajorString + + + + + + value: errorMajorString + value + errorMajorString + 2 + + + 212 + + + + value: errorMajorString + + + + + + value: errorMajorString + value + errorMajorString + 2 + + + 215 + + + + value: errorMinorString + + + + + + value: errorMinorString + value + errorMinorString + 2 + + + 216 + + + + predicate: filterPredicate + + + + + + predicate: filterPredicate + predicate + filterPredicate + + YES + + YES + NSDisplayName + NSPredicateFormat + + + YES + Title + title CONTAINS[cd] $value + + + 2 + + + 219 + + + + predicate2: filterPredicate + + + + + + predicate2: filterPredicate + predicate2 + filterPredicate + + YES + + YES + NSDisplayName + NSPredicateFormat + + + YES + Serial + serial CONTAINS[cd] $value + + + + 2 + + + 220 + + + + predicate3: filterPredicate + + + + + + predicate3: filterPredicate + predicate3 + filterPredicate + + YES + + YES + NSDisplayName + NSPredicateFormat + + + YES + CRC + crcString CONTAINS[cd] $value + + + + 2 + + + 222 + + + + + YES + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 3 + + + YES + + + + + + 4 + + + YES + + + + + + + + + + + + + + + + + + + + + + 8 + + + YES + + + + + + 9 + + + YES + + + + + + 10 + + + YES + + + + + + 11 + + + YES + + + + + + 13 + + + YES + + + + + + 14 + + + YES + + + + + + 15 + + + YES + + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 52 + + + Cheat Database Game Array Controller + + + 53 + + + Cheat Database Entry Tree Controller + + + 63 + + + YES + + + + + + 64 + + + + + 65 + + + YES + + + + + + 66 + + + YES + + + + + + 67 + + + + + 68 + + + + + 69 + + + YES + + + + + + 70 + + + YES + + + + + + 71 + + + YES + + + + + + 72 + + + + + 73 + + + YES + + + + Window (Error Sheet) + + + 74 + + + YES + + + + + + + + 76 + + + YES + + + + + + 81 + + + + + 85 + + + + + 90 + + + YES + + + + + + 91 + + + + + 93 + + + YES + + + + + Code View + + + 95 + + + YES + + + + + + 96 + + + + + 113 + + + + + 142 + + + YES + + + + + + + + 143 + + + + + 144 + + + + + 145 + + + + + 149 + + + YES + + + + + + + 151 + + + YES + + + + + + 150 + + + YES + + + + + + + 6 + + + YES + + + + + + + + + 28 + + + + + 27 + + + + + 26 + + + YES + + + + + + + + + + 25 + + + + + 33 + + + YES + + + + + + 32 + + + YES + + + + + + 31 + + + YES + + + + + + 30 + + + YES + + + + + + 29 + + + YES + + + + + + 39 + + + + + 38 + + + + + 37 + + + + + 36 + + + + + 34 + + + YES + + + + + + 35 + + + + + 5 + + + YES + + + + + + + + + 43 + + + + + 42 + + + + + 41 + + + YES + + + + + + + + + 40 + + + + + 47 + + + YES + + + + + + 46 + + + YES + + + + + + 45 + + + YES + + + + + + 44 + + + YES + + + + + + 51 + + + + + 50 + + + + + 49 + + + + + 48 + + + + + 152 + + + YES + + + + + + 153 + + + + + 116 + + + + + 187 + + + YES + + + + + + 188 + + + + + 190 + + + YES + + + + + + 191 + + + + + 210 + + + YES + + + + + + 211 + + + + + 213 + + + YES + + + + + + 214 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 10.IBPluginDependency + 10.IBViewBoundsToFrameTransform + 11.IBPluginDependency + 113.IBNumberFormatterBehaviorMetadataKey + 113.IBNumberFormatterLocalizesFormatMetadataKey + 113.IBPluginDependency + 116.IBPluginDependency + 116.IBViewBoundsToFrameTransform + 13.IBPluginDependency + 14.IBPluginDependency + 14.IBViewBoundsToFrameTransform + 142.IBPluginDependency + 142.IBViewBoundsToFrameTransform + 143.IBPluginDependency + 144.IBPluginDependency + 145.IBPluginDependency + 149.IBPluginDependency + 149.IBViewBoundsToFrameTransform + 15.IBPluginDependency + 15.IBViewBoundsToFrameTransform + 150.IBPluginDependency + 150.IBViewBoundsToFrameTransform + 151.IBPluginDependency + 152.IBPluginDependency + 152.IBViewBoundsToFrameTransform + 153.IBPluginDependency + 16.IBPluginDependency + 17.IBPluginDependency + 18.IBPluginDependency + 187.IBPluginDependency + 187.IBViewBoundsToFrameTransform + 188.IBPluginDependency + 190.IBPluginDependency + 190.IBViewBoundsToFrameTransform + 191.IBPluginDependency + 20.IBPluginDependency + 21.IBPluginDependency + 210.IBPluginDependency + 210.IBViewBoundsToFrameTransform + 211.IBPluginDependency + 213.IBPluginDependency + 213.IBViewBoundsToFrameTransform + 214.IBPluginDependency + 22.IBPluginDependency + 23.IBPluginDependency + 25.IBPluginDependency + 26.IBPluginDependency + 27.IBPluginDependency + 28.IBPluginDependency + 3.IBEditorWindowLastContentRect + 3.IBPluginDependency + 3.IBWindowTemplateEditedContentRect + 3.NSWindowTemplate.visibleAtLaunch + 3.windowTemplate.hasMinSize + 3.windowTemplate.minSize + 32.IBPluginDependency + 33.IBPluginDependency + 34.IBPluginDependency + 35.IBNumberFormatterBehaviorMetadataKey + 35.IBNumberFormatterLocalizesFormatMetadataKey + 35.IBPluginDependency + 36.IBPluginDependency + 4.IBPluginDependency + 40.IBPluginDependency + 41.IBPluginDependency + 42.IBPluginDependency + 43.IBPluginDependency + 46.IBPluginDependency + 47.IBPluginDependency + 48.IBPluginDependency + 49.IBAttributePlaceholdersKey + 49.IBPluginDependency + 5.IBPluginDependency + 5.IBViewBoundsToFrameTransform + 52.IBPluginDependency + 53.IBPluginDependency + 6.IBPluginDependency + 6.IBViewBoundsToFrameTransform + 63.IBPluginDependency + 63.IBViewBoundsToFrameTransform + 64.IBPluginDependency + 65.IBPluginDependency + 65.IBViewBoundsToFrameTransform + 66.IBPluginDependency + 66.IBViewBoundsToFrameTransform + 67.IBPluginDependency + 68.IBPluginDependency + 69.IBPluginDependency + 69.IBViewBoundsToFrameTransform + 70.IBPluginDependency + 70.IBViewBoundsToFrameTransform + 71.IBPluginDependency + 72.IBPluginDependency + 73.IBEditorWindowLastContentRect + 73.IBPluginDependency + 73.IBWindowTemplateEditedContentRect + 73.NSWindowTemplate.visibleAtLaunch + 74.IBPluginDependency + 76.IBPluginDependency + 76.IBViewBoundsToFrameTransform + 8.IBPluginDependency + 8.IBViewBoundsToFrameTransform + 81.IBPluginDependency + 85.IBPluginDependency + 9.IBPluginDependency + 9.IBViewBoundsToFrameTransform + 90.IBAttributePlaceholdersKey + 90.IBPluginDependency + 90.IBViewBoundsToFrameTransform + 91.IBPluginDependency + 93.IBEditorWindowLastContentRect + 93.IBPluginDependency + 93.IBViewBoundsToFrameTransform + 95.IBPluginDependency + 95.IBViewBoundsToFrameTransform + 96.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBiAAAw9yAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDmAAAwwkAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD2IAAwdgAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAAAAAAAAw34AAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAAAAAAAAw8KAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDn4AAwdgAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCpAAAw9GAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD2gAAw9sAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDiYAAw98AAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBiAAAwxUAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBiAAAwwoAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{502, 214}, {640, 480}} + com.apple.InterfaceBuilder.CocoaPlugin + {{502, 214}, {640, 480}} + + + {480, 400} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + YES + + + YES + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAAAAAAAAw0rtAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAAA/gAAAw1gAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD/oAAw+8AAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD14AAw92AAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDwYAAw92AAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDawAAw9yAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDoIAAw9yAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{540, 610}, {480, 185}} + com.apple.InterfaceBuilder.CocoaPlugin + {{540, 610}, {480, 185}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDuQAAwuwAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABC9gAAw9yAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCpAAAw+kAAA + + + ToolTip + + ToolTip + + Shows/hides the address search drawer. + + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBmAAAwfAAAA + + com.apple.InterfaceBuilder.CocoaPlugin + {{528, 378}, {200, 400}} + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBQAAAw8QAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 228 + + + + YES + + CheatDatabaseWindowController + NSWindowController + + YES + + YES + addSelected: + closeErrorSheet: + openFile: + selectAll: + selectCurrentGame: + selectNone: + + + YES + id + id + id + id + id + id + + + + YES + + YES + addSelected: + closeErrorSheet: + openFile: + selectAll: + selectCurrentGame: + selectNone: + + + YES + + addSelected: + id + + + closeErrorSheet: + id + + + openFile: + id + + + selectAll: + id + + + selectCurrentGame: + id + + + selectNone: + id + + + + + YES + + YES + entryListController + entryOutline + errorSheet + gameListController + gameTable + splitView + + + YES + NSTreeController + NSOutlineView + NSWindow + NSArrayController + NSTableView + NSSplitView + + + + YES + + YES + entryListController + entryOutline + errorSheet + gameListController + gameTable + splitView + + + YES + + entryListController + NSTreeController + + + entryOutline + NSOutlineView + + + errorSheet + NSWindow + + + gameListController + NSArrayController + + + gameTable + NSTableView + + + splitView + NSSplitView + + + + + IBProjectSource + userinterface/CheatDatabaseWindowController.h + + + + + YES + + NSActionCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSActionCell.h + + + + NSApplication + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSApplication.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSApplicationScripting.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSColorPanel.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSHelpManager.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSPageLayout.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSUserInterfaceItemSearching.h + + + + NSArrayController + NSObjectController + + IBFrameworkSource + AppKit.framework/Headers/NSArrayController.h + + + + NSButton + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSButton.h + + + + NSButtonCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSButtonCell.h + + + + NSCell + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSCell.h + + + + NSControl + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSControl.h + + + + NSController + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSController.h + + + + NSDrawer + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSDrawer.h + + + + NSFormatter + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFormatter.h + + + + NSImageCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSImageCell.h + + + + NSMenu + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenu.h + + + + NSNumberFormatter + NSFormatter + + IBFrameworkSource + Foundation.framework/Headers/NSNumberFormatter.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSAccessibility.h + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDictionaryController.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDragging.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontManager.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontPanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSKeyValueBinding.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSNibLoading.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSOutlineView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSPasteboard.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSSavePanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbarItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSView.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObjectScripting.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPortCoder.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptObjectSpecifiers.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptWhoseTests.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLDownload.h + + + + NSObject + + IBFrameworkSource + QuartzCore.framework/Headers/CAAnimation.h + + + + NSObject + + IBFrameworkSource + QuartzCore.framework/Headers/CALayer.h + + + + NSObject + + IBFrameworkSource + QuartzCore.framework/Headers/CIImageProvider.h + + + + NSObjectController + NSController + + IBFrameworkSource + AppKit.framework/Headers/NSObjectController.h + + + + NSOutlineView + NSTableView + + + + NSProgressIndicator + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSProgressIndicator.h + + + + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSInterfaceStyle.h + + + + NSResponder + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSResponder.h + + + + NSScrollView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSScrollView.h + + + + NSScroller + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSScroller.h + + + + NSSearchField + NSTextField + + IBFrameworkSource + AppKit.framework/Headers/NSSearchField.h + + + + NSSearchFieldCell + NSTextFieldCell + + IBFrameworkSource + AppKit.framework/Headers/NSSearchFieldCell.h + + + + NSSplitView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSSplitView.h + + + + NSTableColumn + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableColumn.h + + + + NSTableHeaderView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSTableHeaderView.h + + + + NSTableView + NSControl + + + + NSText + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSText.h + + + + NSTextField + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSTextField.h + + + + NSTextFieldCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSTextFieldCell.h + + + + NSTextView + NSText + + IBFrameworkSource + AppKit.framework/Headers/NSTextView.h + + + + NSTreeController + NSObjectController + + IBFrameworkSource + AppKit.framework/Headers/NSTreeController.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSClipView.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItem.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSRulerView.h + + + + NSView + NSResponder + + + + NSWindow + + + + NSWindow + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSWindow.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSWindowScripting.h + + + + NSWindowController + NSResponder + + showWindow: + id + + + showWindow: + + showWindow: + id + + + + IBFrameworkSource + AppKit.framework/Headers/NSWindowController.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + ../../DeSmuME (XCode 3).xcodeproj + 3 + + YES + + YES + NSActionTemplate + NSSwitch + + + YES + {14, 14} + {15, 15} + + + + diff --git a/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.strings b/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.strings index 90587aad6b747e888dd93a6205f57449cbbab370..ea250f0a9e11c914765a2b2e4f83dbabff4dcc90 100644 GIT binary patch delta 517 zcmZvY%PT}-7{h9$D>B(}9OfvzCyva|hYmeOq0TbK$~ z>hD7<8Dxh|ARC%cTHIwN7nngIv7zIMWWw56U>6+2xio~)I2*@AgzBrlI8)+ELdl`z zw0vmh05(2T4{q*p@sBwl z-J@C$%5&A;E18k*C7oniks`Q%%*$<*BAl*hMfPJjJkVe4!V1YsemGCpL?3!Jo`!Nv zIJHStCrTEvOtLZ@tmjpql&f8u|K16zBaH17Q8cf}iqqf9r*OauL+{QD*oG48>oc`mT+j2FHEJa48P delta 965 zcmZ{iT}V@57{}kQ<5^2<9ak4yTbr35%XCAHWim3OGP33fx~XtsQ5I@#eM2pfBnfK0 z;lG=rq^pqFGFT7hBGFOS{YAW#TxiDxW=-m>J zjMfT%fSkhb%lZm@JIMkvzdV5McT5a90yO6cu(>j`1A<|;9oHwtCJgLlA~zjoKbx-S zy%?ybrIwbHqjsXCZLOS+Y{S5JZb$H`C>`0)T^2bS)eK$9sc)U^ zYHL8m$JdVh;*ngcpLr?fmkC!+X};pfTw;~hz>9`;2L_L`ilt#yS3%Yj9|@2KVpso4 zOTO3L<{e;yEhktNqI>v88T1Q$*vbs)^7t^jK{(CMVG_p0PPPUE9_4SohTgPB+kb&M z@$3g(j%!auSVpe~m#FKiR_){vIY8nhNfMYj!^%;#W}=r{)=V7X?*FmMsF=9~s3q9Z z>ZNw%J=BGKQW-Z$S;4pv;tuMTnL&YRo3Nq9OY0B?4_ZZYXLyyxA2&3MPmgK;c_+eS5}Ao7G7gfZ`y^WS=cZ#9ja@7A#2k6 z$qCX&dSte-C>JZW|Y87LZ2S)e$mtsMy2nWoq|Ut-a6%>1A}KB^z@X77M?F zg{*XXrnd0f%3@?E=~U}Vnxk|z|E(EyJGGEnWT^1oWNU*>GYJ`AP>VZ@Me9hC?ZeAk X#gz + + + YES + YES + + + 2147483647 + + + + + + Open Cheat Database File… + + 2147483647 + + + + + + Open Recent Cheat Database File + + 2147483647 + + + submenuAction: + + + Open Recent Cheat Database File + + + + Clear Menu + + 2147483647 + + + + + + @@ -3150,9 +3191,11 @@ {1.7976931348623157e+308, 1.7976931348623157e+308} - + 256 {400, 100} + + {{0, 0}, {1920, 1177}} {1.7976931348623157e+308, 1.7976931348623157e+308} @@ -3160,7 +3203,7 @@ YES - + 268 @@ -3176,6 +3219,7 @@ 268 {{175, 50}, {199, 21}} + YES 613417024 @@ -3195,6 +3239,7 @@ 268 {{376, 43}, {96, 32}} + YES 67108864 @@ -3216,6 +3261,7 @@ 268 {{15, 53}, {155, 17}} + YES 68157504 @@ -3234,6 +3280,7 @@ 268 {{15, 14}, {454, 28}} + YES 69206017 @@ -3251,10 +3298,12 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA {{1, 1}, {484, 81}} + {{17, 16}, {486, 97}} + {0, 0} 67108864 @@ -3280,94 +3329,6 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA2 NO - - - 12 - - - - 274 - - - - 268 - {{148, 14}, {226, 21}} - - YES - - 613417024 - 272634880 - - - File Name - - - - - NO - 1 - - - - 268 - {{376, 7}, {96, 32}} - - YES - - 67108864 - 134217728 - Choose... - - - -2038284288 - 129 - - - 200 - 25 - - NO - - - - 268 - {{15, 17}, {128, 17}} - - YES - - 68157504 - 71304192 - R4 Cheat Database: - - - - - - NO - 1 - - - {{1, 1}, {484, 45}} - - - - {{17, 117}, {486, 61}} - - {0, 0} - - 67108864 - 0 - Cheat Configuration - - - - - - 1 - 0 - 2 - NO - 12 @@ -3381,6 +3342,7 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA268 {{63, 12}, {371, 18}} + YES 67108864 @@ -3409,6 +3371,7 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA268 {{114, 33}, {270, 32}} + YES 67108864 @@ -3428,10 +3391,12 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA {{1, 1}, {484, 75}} + - {{17, 182}, {486, 91}} + {{17, 117}, {486, 91}} + {0, 0} 67108864 @@ -3460,6 +3425,7 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA268 {{16, 40}, {366, 18}} + YES -2080374784 @@ -3483,6 +3449,7 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA268 {{16, 84}, {247, 18}} + YES -2080374784 @@ -3506,6 +3473,7 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA268 {{273, 10}, {196, 26}} + YES -2076180416 @@ -3600,6 +3568,7 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA268 {{15, 16}, {256, 17}} + YES 68157504 @@ -3618,6 +3587,7 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA268 {{16, 62}, {216, 18}} + YES -2080374784 @@ -3639,10 +3609,12 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXA {{1, 1}, {484, 109}} + - {{17, 277}, {486, 125}} + {{17, 212}, {486, 125}} + {0, 0} 67108864 @@ -3659,7 +3631,9 @@ L3d3dy5hZHZhbnNjZW5lLmNvbS9vZmZsaW5lL2RhdGFzL0FEVkFOc0NFbmVfUlRvb2xEUy56aXANO - {520, 422} + {520, 357} + + NSView @@ -7134,7 +7108,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSView - + 268 @@ -7145,6 +7119,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{13, 10}, {528, 441}} + 1 @@ -7165,6 +7140,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{16, 52}, {198, 18}} + YES @@ -7189,6 +7165,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{16, 32}, {217, 18}} + YES @@ -7213,6 +7190,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{16, 12}, {183, 18}} + YES -2080374784 @@ -7234,11 +7212,13 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {494, 78}} + {{6, 301}, {496, 94}} + {0, 0} @@ -7268,6 +7248,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{18, 14}, {165, 38}} + YES NO @@ -7510,6 +7491,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{242, 15}, {73, 17}} + YES @@ -7529,6 +7511,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{320, 13}, {50, 22}} + YES @@ -7589,6 +7572,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{371, 10}, {19, 27}} + YES @@ -7607,11 +7591,13 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {494, 62}} + {{6, 219}, {496, 78}} + {0, 0} @@ -7641,6 +7627,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{95, 14}, {66, 17}} + YES @@ -7660,6 +7647,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{164, 12}, {176, 26}} + YES @@ -7683,6 +7671,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{343, 14}, {52, 17}} + YES 68157504 @@ -7738,6 +7727,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{161, 36}, {26, 14}} + YES @@ -7757,6 +7747,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{239, 36}, {26, 14}} + YES @@ -7776,6 +7767,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{314, 36}, {31, 14}} + YES @@ -7793,11 +7785,13 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {494, 60}} + {{6, 139}, {496, 76}} + {0, 0} @@ -7827,6 +7821,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{16, 12}, {462, 18}} + YES @@ -7849,11 +7844,13 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {494, 38}} + {{6, 81}, {496, 54}} + {0, 0} @@ -7883,6 +7880,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{16, 32}, {146, 18}} + YES @@ -7907,6 +7905,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{16, 12}, {118, 18}} + YES 67108864 @@ -7928,11 +7927,13 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {494, 58}} + {{6, 3}, {496, 74}} + {0, 0} @@ -7952,6 +7953,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{10, 33}, {508, 395}} + General Settings @@ -9376,6 +9378,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {554, 465} + + NSView @@ -9423,10 +9427,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - + -2147483392 {{584, 0}, {16, 17}} - @@ -9593,7 +9596,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - {{-1, 60}, {622, 322}} @@ -18026,7 +18028,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {1.7976931348623157e+308, 1.7976931348623157e+308} - + 256 @@ -18034,6 +18036,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 77}, {366, 17}} + YES 67108864 @@ -18052,6 +18055,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 289 {{290, 12}, {96, 32}} + YES 67108864 @@ -18073,6 +18077,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 289 {{194, 12}, {96, 32}} + 2 YES @@ -18095,6 +18100,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 292 {{17, 53}, {366, 16}} + YES 69206017 @@ -18115,6 +18121,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {400, 114} + + {{0, 0}, {1440, 878}} {1.7976931348623157e+308, 1.7976931348623157e+308} @@ -18132,7 +18140,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {1.7976931348623157e+308, 1.7976931348623157e+308} {640, 480} - + 256 @@ -18148,6 +18156,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 256 {270, 335} + YES NO YES @@ -18156,6 +18165,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 256 {270, 17} + @@ -18273,6 +18283,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 17}, {270, 335}} + @@ -18286,6 +18297,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 0}, {270, 17}} + @@ -18294,6 +18306,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 -2147483392 {{256, 17}, {15, 306}} + NO _doScroller: @@ -18304,6 +18317,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 -2147483392 {{1, 323}, {270, 15}} + NO 1 @@ -18313,6 +18327,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{20, 49}, {272, 353}} + 133682 @@ -18324,32 +18339,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 4 1 - - - 292 - {{113, 12}, {185, 32}} - - YES - - 67108864 - 134217728 - View Cheat Database... - - - -2038284288 - 129 - - - 200 - 25 - - NO - 292 {{47, 19}, {28, 23}} + YES -2080374784 @@ -18375,6 +18370,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 292 {{20, 19}, {28, 23}} + YES -2080374784 @@ -18408,6 +18404,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{100, 372}, {209, 26}} + YES -2076180416 @@ -18472,6 +18469,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 272 {{2, 32}, {320, 274}} + NSView @@ -18479,6 +18477,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{16, 402}, {130, 18}} + YES 67108864 @@ -18502,6 +18501,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 378}, {83, 17}} + YES 68157504 @@ -18520,6 +18520,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 12 {{14, 303}, {292, 5}} + {0, 0} 67108864 @@ -18539,6 +18540,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{103, 313}, {203, 57}} + YES -1805647871 @@ -18558,6 +18560,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 353}, {83, 17}} + YES 68157504 @@ -18576,6 +18579,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 292 {{114, 3}, {96, 32}} + YES 67108864 @@ -18595,10 +18599,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {324, 428}} + {{297, 16}, {326, 444}} + {0, 0} 67108864 @@ -18619,6 +18625,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{76, 408}, {190, 18}} + YES -2080374784 @@ -18653,6 +18660,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{20, 410}, {50, 50}} + YES 134217728 @@ -18671,6 +18679,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{75, 432}, {168, 28}} + YES 69206017 @@ -18689,11 +18698,38 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{29, 419}, {32, 32}} + 28682 100 + + + 289 + {{140, 13}, {158, 32}} + + + _NS:610 + YES + + 67108864 + 134217728 + Remove All Cheats + + _NS:610 + + -2038284288 + 129 + + + 200 + 25 + + NO + {640, 480} + + {{0, 0}, {1920, 1177}} {640, 502} @@ -19118,386 +19154,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - - 15 - 2 - {{235, 143}, {500, 416}} - 1685585920 - Cheat Database - NSWindow - - - {1.7976931348623157e+308, 1.7976931348623157e+308} - {500, 272} - - - 256 - - - - 274 - - - - 2304 - - - - 256 - {500, 287} - - YES - NO - YES - - - 256 - {500, 17} - - - - - - -2147483392 - {{224, 0}, {16, 17}} - - - - 25 - 25 - 25 - - 75497536 - 2048 - - - - 3 - MC4zMzMzMzI5ODU2AA - - - - - 67108864 - 134217728 - - - - 1215582464 - 2 - - - - - 200 - 25 - - YES - - - - 464 - 40 - 1000 - - 75497536 - 2048 - Description - - - - - - 69206017 - 135168 - Text Cell - - - - - - 3 - YES - YES - - - - 3 - 2 - - - 39 - 1925185536 - - - 1 - 4 - 15 - 0 - NO - 0 - 1 - - - {{1, 17}, {500, 287}} - - - - - 4 - - - - -2147483392 - {{224, 17}, {15, 102}} - - NO - - _doScroller: - 0.94773519163763065 - - - - -2147483392 - {{1, 249}, {568, 15}} - - NO - 1 - - _doScroller: - 0.99206349206349209 - - - - 2304 - - - - {{1, 0}, {500, 17}} - - - - - - {{-1, 57}, {502, 305}} - - - 133682 - - - - - QSAAAEEgAABCJAAAQiQAAA - 0.25 - 4 - 1 - - - - 268 - {{17, 370}, {125, 14}} - - YES - - 68157504 - 272761856 - R4 Cheats Database: - - - - - - NO - 1 - - - - 268 - {{17, 392}, {68, 14}} - - YES - - 68157504 - 272761856 - ROM Title: - - - - - - NO - 1 - - - - 292 - {{14, 12}, {114, 32}} - - YES - - 67108864 - 134217728 - Select All - - - -2038284288 - 129 - - - 200 - 25 - - NO - - - - 292 - {{128, 12}, {114, 32}} - - YES - - 67108864 - 134217728 - Select None - - - -2038284288 - 129 - - - 200 - 25 - - NO - - - - 289 - {{390, 12}, {96, 32}} - - 1 - YES - - 67108864 - 134217728 - Add - - - -2038284288 - 129 - - DQ - 200 - 25 - - NO - - - - 289 - {{294, 12}, {96, 32}} - - YES - - 67108864 - 134217728 - Cancel - - - -2038284288 - 129 - - Gw - 200 - 25 - - NO - - - - 265 - {{372, 370}, {48, 14}} - - YES - - 68157504 - 71435264 - Found: - - - - - - NO - 1 - - - - 268 - {{144, 370}, {232, 14}} - - YES - - 70254657 - 272765952 - - - Database file - - - - - NO - 1 - - - - 265 - {{422, 370}, {61, 14}} - - YES - - 70254657 - 4330496 - - - Count - - - - - NO - 1 - - - - 268 - {{87, 392}, {396, 14}} - - YES - - 70254657 - 272765952 - - - ROM title - - - - - NO - 1 - - - {500, 416} - - {{0, 0}, {1920, 1177}} - {500, 294} - {1.7976931348623157e+308, 1.7976931348623157e+308} - YES - - + 268 @@ -19505,6 +19163,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{233, 54}, {80, 28}} + YES 67108864 @@ -19526,6 +19185,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{20, 59}, {210, 19}} + YES YES @@ -19580,6 +19240,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 86}, {294, 14}} + YES 67108864 @@ -19598,6 +19259,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{17, 100}, {294, 14}} + YES 67108864 @@ -19613,6 +19275,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {328, 134} + + NSView @@ -21002,7 +20666,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - 1292 + 268 {{11, 14}, {32, 32}} 28682 @@ -34276,11 +33940,11 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 YES - {{1, 1}, {213, 44}} + {{1, 1}, {213, 46}} - {{16, 357}, {215, 60}} + {{16, 357}, {215, 62}} {0, 0} @@ -34573,7 +34237,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - {{16, 421}, {215, 78}} + {{16, 423}, {215, 78}} {0, 0} @@ -42507,17 +42171,11 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 hasSelection - hasItems - cheatWindowDelegateKey cheatSearchStyle - cheatSearchSignType cheatSearchSearchValue cheatSearchAddressCount isRunningSearch isSearchStarted - cheatDBTitle - cheatDBItemCount - cheatDBDate YES @@ -42754,15 +42412,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 YES - - - willAdd - description - - YES - - YES - slot2StatusText @@ -44001,86 +43650,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 5070 - - - value: selection.R4CheatDatabaseName - - - - - - value: selection.R4CheatDatabaseName - value - selection.R4CheatDatabaseName - 2 - - - 5073 - - - - chooseCheatDatabase: - - - - 5078 - - - - viewDatabase: - - - - 5079 - - - - cheatDatabaseSheet - - - - 5108 - - - - closeCheatDatabaseSheet: - - - - 5109 - - - - closeCheatDatabaseSheet: - - - - 5110 - - - - cheatDatabaseController - - - - 5119 - - - - selectAllCheatsInDatabase: - - - - 5122 - - - - selectNoneCheatsInDatabase: - - - - 5123 - cheatWindowController @@ -44089,14 +43658,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 5143 - - - cheatDatabaseController - - - - 5145 - prefWindowController @@ -44381,42 +43942,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 5495 - - - value: arrangedObjects.willAdd - - - - - - value: arrangedObjects.willAdd - value - arrangedObjects.willAdd - 2 - - - 5497 - - - - value: arrangedObjects.description - - - - - - value: arrangedObjects.description - value - arrangedObjects.description - - NSConditionallySetsEditable - - - 2 - - - 5498 - value: selection.memAddressSixDigitString @@ -44982,54 +44507,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 5612 - - - value: selection.cheatDBTitle - - - - - - value: selection.cheatDBTitle - value - selection.cheatDBTitle - 2 - - - 5618 - - - - value: selection.cheatDBDate - - - - - - value: selection.cheatDBDate - value - selection.cheatDBDate - 2 - - - 5619 - - - - value: selection.cheatDBItemCount - - - - - - value: selection.cheatDBItemCount - value - selection.cheatDBItemCount - 2 - - - 5620 - selectedTag: selection.cheatSearchStyle @@ -46527,22 +46004,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 6656 - - - cheatDatabaseController - - - - 6657 - - - - cheatListController - - - - 6658 - cheatWindowController @@ -47103,50 +46564,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 6870 - - - enabled: selection.currentRom - - - - - - enabled: selection.currentRom - enabled - selection.currentRom - - NSValueTransformerName - NSIsNotNil - - 2 - - - 6873 - - - - enabled2: values.R4Cheat_DatabasePath - - - - - - enabled2: values.R4Cheat_DatabasePath - enabled2 - values.R4Cheat_DatabasePath - - - - - - NSIsNotNil - - - 2 - - - 6874 - enabled: selection.currentRom @@ -59338,6 +58755,58 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 12300 + + + enabled: selection.currentRom + + + + + + enabled: selection.currentRom + enabled + selection.currentRom + + NSValueTransformerName + NSIsNotNil + + 2 + + + 12385 + + + + removeAllFromList: + + + + 12386 + + + + openCheatDatabaseFile: + + + + 12397 + + + + cheatDatabaseRecentsMenu + + + + 12399 + + + + clearCheatDatabaseRecents: + + + + 12400 + @@ -59434,6 +58903,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 + + + @@ -60052,9 +59524,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - - + General Preferences View @@ -61090,10 +60561,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - + @@ -61154,19 +60625,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - - 3516 - - - - - - - - 3517 - - - 3520 @@ -63466,55 +62924,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - - 5003 - - - - - - - - - - 5004 - - - - - - - - 5005 - - - - - - - - 5006 - - - - - - - - 5007 - - - - - 5008 - - - - - 5009 - - - 5066 @@ -63541,229 +62950,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - - 5080 - - - - - - - - 5081 - - - - - - - - - - - - - - - - - - 5082 - - - - - - - - - - - 5083 - - - - - 5084 - - - - - 5085 - - - - - - - - - 5086 - - - - - 5087 - - - - - - - - 5088 - - - - - - - - 5089 - - - - - 5097 - - - - - 5098 - - - - - - - - 5099 - - - - - 5100 - - - - - - - - 5101 - - - - - 5102 - - - - - - - - 5103 - - - - - 5104 - - - - - - - - 5105 - - - - - 5106 - - - - - - - - 5107 - - - - - 5111 - - - - - - - - 5112 - - - - - 5115 - - - Cheat Database Array Controller - - - 5127 - - - - - - - - 5128 - - - - - 5133 - - - - - - - - 5134 - - - - - 5135 - - - - - - - - 5136 - - - - - 5140 - - - - - - - - 5141 - - - 5168 @@ -80936,6 +80122,50 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 + + 12382 + + + + + + + + 12383 + + + + + 12392 + + + + + 12393 + + + + + 12394 + + + + + + + + 12395 + + + + + + + + 12396 + + + @@ -81619,9 +80849,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{888, 834}, {480, 177}} + {{669, 685}, {480, 177}} com.apple.InterfaceBuilder.CocoaPlugin - {{888, 834}, {480, 177}} + {{669, 685}, {480, 177}} @@ -83738,11 +82968,20 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 Aggressively smooths the sound, eliminating the harsh sounding harmonics and noise. However, some sound detail is lost. Negligible CPU usage. + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{824, 323}, {129, 23}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + {{903, 773}, {143, 23}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{323, 434}, {520, 422}} + {{333, 427}, {520, 357}} {215, 355} com.apple.InterfaceBuilder.CocoaPlugin @@ -84105,7 +83344,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{767, 1062}, {187, 73}} + {{856, 763}, {194, 73}} com.apple.InterfaceBuilder.CocoaPlugin ToolTip @@ -84216,14 +83455,14 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{616, 836}, {512, 20}} + {{397, 836}, {512, 20}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{890, 363}, {315, 473}} + {{750, 363}, {315, 473}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -84235,7 +83474,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{339, 683}, {151, 153}} + {{541, 683}, {151, 153}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -84266,9 +83505,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{493, 199}, {640, 480}} + {{469, 376}, {640, 480}} com.apple.InterfaceBuilder.CocoaPlugin - {{493, 199}, {640, 480}} + {{469, 376}, {640, 480}} @@ -84283,8 +83522,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85072,6 +84309,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin {{520, 582}, {320, 274}} com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85121,6 +84359,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDFQAAw4UAAA + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85192,7 +84433,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{837, 1022}, {255, 113}} + {{595, 723}, {261, 113}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85206,13 +84447,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85225,46 +84459,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{21, 406}, {500, 416}} - com.apple.InterfaceBuilder.CocoaPlugin - {{21, 406}, {500, 416}} - - - {500, 272} - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + AUGIAABBgAAAA + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85291,6 +84491,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + {{757, 530}, {64, 6}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85357,12 +84558,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{207, 653}, {203, 183}} + {{488, 653}, {203, 183}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{804, 383}, {257, 453}} + {{585, 383}, {257, 453}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85377,7 +84578,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{940, 663}, {292, 173}} + {{800, 663}, {292, 173}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85827,9 +85028,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{329, 346}, {620, 442}} + {{14, 346}, {620, 442}} com.apple.InterfaceBuilder.CocoaPlugin - {{329, 346}, {620, 442}} + {{14, 346}, {620, 442}} {620, 180} @@ -86070,9 +85271,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{329, 670}, {640, 303}} + {{329, 553}, {640, 303}} com.apple.InterfaceBuilder.CocoaPlugin - {{329, 670}, {640, 303}} + {{329, 553}, {640, 303}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -86151,6 +85352,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBMAAAwjAAAA + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{811, 710}, {218, 223}} @@ -86217,7 +85421,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{297, 373}, {325, 463}} + {{499, 323}, {325, 513}} com.apple.InterfaceBuilder.CocoaPlugin {{655, 347}, {173, 339}} com.apple.InterfaceBuilder.CocoaPlugin @@ -87087,10 +86291,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - 12300 + 12400 - + AppDelegate NSObject @@ -87127,7 +86331,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSObjectController MacAVCaptureToolDelegate NSObjectController + NSObjectController NSObjectController + NSArrayController InputPrefsView NSMenu NSMenu @@ -87150,10 +86356,18 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 cdsCoreController NSObjectController + + databaseFileController + NSObjectController + emuControlController NSObjectController + + gameListController + NSArrayController + inputPrefsView InputPrefsView @@ -87188,8 +86402,84 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/appDelegate.h + IBProjectSource + userinterface/appDelegate.h + + + + CheatDatabaseWindowController + NSWindowController + + id + id + id + id + id + id + + + + addSelected: + id + + + closeErrorSheet: + id + + + openFile: + id + + + selectAll: + id + + + selectCurrentGame: + id + + + selectNone: + id + + + + NSTreeController + NSOutlineView + NSWindow + NSArrayController + NSTableView + NSSplitView + + + + entryListController + NSTreeController + + + entryOutline + NSOutlineView + + + errorSheet + NSWindow + + + gameListController + NSArrayController + + + gameTable + NSTableView + + + splitView + NSSplitView + + + + IBProjectSource + userinterface/CheatDatabaseWindowController.h @@ -87198,17 +86488,14 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 id id - id + id id id id id - id id id - id id - id @@ -87219,8 +86506,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 applyConfiguration: id - - closeCheatDatabaseSheet: + + removeAllFromList: id @@ -87239,10 +86526,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 runExactValueSearch: id - - selectAllCheatsInDatabase: - id - selectCheatSearchStyle: id @@ -87251,23 +86534,13 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 selectCheatType: id - - selectNoneCheatsInDatabase: - id - setInternalCheatValue: id - - viewDatabase: - id - NSBox - NSArrayController - NSWindow NSArrayController NSTableView NSArrayController @@ -87291,14 +86564,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 cheatConfigBox NSBox - - cheatDatabaseController - NSArrayController - - - cheatDatabaseSheet - NSWindow - cheatListController NSArrayController @@ -87369,24 +86634,24 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/cheatWindowDelegate.h + IBProjectSource + userinterface/cheatWindowDelegate.h DirectoryURLDragDestTextField NSTextField - IBDocumentRelativeSource - ../../cocoa_util.h + IBProjectSource + cocoa_util.h DisplayPreviewView NSView - - IBDocumentRelativeSource - ../../userinterface/preferencesWindowDelegate.h + + IBProjectSource + userinterface/preferencesWindowDelegate.h @@ -87621,8 +86886,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/DisplayWindowController.h + IBProjectSource + userinterface/DisplayWindowController.h @@ -87644,6 +86909,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 id id id + id id id id @@ -87657,7 +86923,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 id id id + id id + id id id id @@ -87746,6 +87014,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 chooseSlot1R4Directory: id + + clearCheatDatabaseRecents: + id + closeRom: id @@ -87798,10 +87070,18 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 newDisplayWindow: id + + openCheatDatabaseFile: + id + openEmuSaveState: id + + openRecentCheatDatabase: + id + openReplay: id @@ -87911,8 +87191,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 MacAVCaptureToolDelegate NSObjectController NSObjectController - NSArrayController - NSArrayController + NSMenu NSObjectController CheatWindowDelegate NSWindow @@ -87950,13 +87229,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 cdsSoundController NSObjectController - - cheatDatabaseController - NSArrayController - - - cheatListController - NSArrayController + + cheatDatabaseRecentsMenu + NSMenu cheatWindowController @@ -88052,8 +87327,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/EmuControllerDelegate.h + IBProjectSource + userinterface/EmuControllerDelegate.h @@ -88088,8 +87363,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/FileMigrationDelegate.h + IBProjectSource + userinterface/FileMigrationDelegate.h @@ -88110,8 +87385,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/InputManager.h + IBProjectSource + userinterface/InputManager.h @@ -88316,8 +87591,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/inputPrefsView.h + IBProjectSource + userinterface/inputPrefsView.h @@ -88338,8 +87613,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/InputProfileController.h + IBProjectSource + userinterface/InputProfileController.h @@ -88368,8 +87643,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/MacAVCaptureTool.h + IBProjectSource + userinterface/MacAVCaptureTool.h @@ -88401,8 +87676,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/MacBaseCaptureTool.h + IBProjectSource + userinterface/MacBaseCaptureTool.h @@ -88420,8 +87695,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/MacScreenshotCaptureTool.h + IBProjectSource + userinterface/MacScreenshotCaptureTool.h @@ -88432,7 +87707,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 id id id - id id id id @@ -88468,10 +87742,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 chooseAdvansceneDatabase: id - - chooseCheatDatabase: - id - chooseFirmwareImage: id @@ -88543,7 +87813,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSObjectController - NSArrayController NSObjectController NSTextField NSPopUpButton @@ -88572,10 +87841,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 cdsCoreController NSObjectController - - cheatDatabaseController - NSArrayController - cheatWindowController NSObjectController @@ -88665,14 +87930,14 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSWindow - + RomInfoContentView NSView - - IBDocumentRelativeSource - ../../userinterface/RomInfoPanel.h + + IBProjectSource + userinterface/RomInfoPanel.h @@ -88718,7 +87983,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 RomInfoPanelSectionView - + RomInfoPanelSectionView @@ -88737,7 +88002,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSTextField - + Slot2WindowDelegate @@ -88876,8 +88141,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/Slot2WindowDelegate.h + IBProjectSource + userinterface/Slot2WindowDelegate.h @@ -88957,8 +88222,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/troubleshootingWindowDelegate.h + IBProjectSource + userinterface/troubleshootingWindowDelegate.h @@ -88993,8 +88258,849 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBDocumentRelativeSource - ../../userinterface/WifiSettingsPanel.h + IBProjectSource + userinterface/WifiSettingsPanel.h + + + + + + NSActionCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSActionCell.h + + + + NSApplication + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSApplication.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSApplicationScripting.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSColorPanel.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSHelpManager.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSPageLayout.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSUserInterfaceItemSearching.h + + + + NSArrayController + NSObjectController + + IBFrameworkSource + AppKit.framework/Headers/NSArrayController.h + + + + NSBox + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSBox.h + + + + NSBrowser + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSBrowser.h + + + + NSButton + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSButton.h + + + + NSButtonCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSButtonCell.h + + + + NSCell + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSCell.h + + + + NSColorWell + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSColorWell.h + + + + NSControl + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSControl.h + + + + NSController + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSController.h + + + + NSDatePicker + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSDatePicker.h + + + + NSDatePickerCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSDatePickerCell.h + + + + NSDocumentController + NSObject + + id + id + id + id + + + + clearRecentDocuments: + id + + + newDocument: + id + + + openDocument: + id + + + saveAllDocuments: + id + + + + IBFrameworkSource + AppKit.framework/Headers/NSDocumentController.h + + + + NSDrawer + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSDrawer.h + + + + NSFormatter + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFormatter.h + + + + NSImageCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSImageCell.h + + + + NSImageView + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSImageView.h + + + + NSLevelIndicator + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSLevelIndicator.h + + + + NSLevelIndicatorCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSLevelIndicatorCell.h + + + + NSMatrix + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSMatrix.h + + + + NSMenu + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenu.h + + + + NSMenuItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItem.h + + + + NSMenuItemCell + NSButtonCell + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItemCell.h + + + + NSMovieView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSMovieView.h + + + + NSNumberFormatter + NSFormatter + + IBFrameworkSource + Foundation.framework/Headers/NSNumberFormatter.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSAccessibility.h + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDictionaryController.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDragging.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontManager.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontPanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSKeyValueBinding.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSNibLoading.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSOutlineView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSPasteboard.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSSavePanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbarItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSView.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObjectScripting.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPortCoder.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptObjectSpecifiers.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptWhoseTests.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLDownload.h + + + + NSObject + + IBFrameworkSource + QuartzCore.framework/Headers/CAAnimation.h + + + + NSObject + + IBFrameworkSource + QuartzCore.framework/Headers/CALayer.h + + + + NSObject + + IBFrameworkSource + QuartzCore.framework/Headers/CIImageProvider.h + + + + NSObjectController + NSController + + IBFrameworkSource + AppKit.framework/Headers/NSObjectController.h + + + + NSOutlineView + NSTableView + + + + NSPanel + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSPanel.h + + + + NSPopUpButton + NSButton + + IBFrameworkSource + AppKit.framework/Headers/NSPopUpButton.h + + + + NSPopUpButtonCell + NSMenuItemCell + + IBFrameworkSource + AppKit.framework/Headers/NSPopUpButtonCell.h + + + + NSProgressIndicator + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSProgressIndicator.h + + + + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSInterfaceStyle.h + + + + NSResponder + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSResponder.h + + + + NSScrollView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSScrollView.h + + + + NSScroller + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSScroller.h + + + + NSSearchField + NSTextField + + IBFrameworkSource + AppKit.framework/Headers/NSSearchField.h + + + + NSSearchFieldCell + NSTextFieldCell + + IBFrameworkSource + AppKit.framework/Headers/NSSearchFieldCell.h + + + + NSSegmentedCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSSegmentedCell.h + + + + NSSegmentedControl + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSSegmentedControl.h + + + + NSSlider + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSSlider.h + + + + NSSliderCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSSliderCell.h + + + + NSSplitView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSSplitView.h + + + + NSStepper + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSStepper.h + + + + NSStepperCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSStepperCell.h + + + + NSTabView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSTabView.h + + + + NSTabViewItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTabViewItem.h + + + + NSTableColumn + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableColumn.h + + + + NSTableHeaderView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSTableHeaderView.h + + + + NSTableView + NSControl + + + + NSText + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSText.h + + + + NSTextField + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSTextField.h + + + + NSTextFieldCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSTextFieldCell.h + + + + NSTextView + NSText + + IBFrameworkSource + AppKit.framework/Headers/NSTextView.h + + + + NSToolbar + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbar.h + + + + NSToolbarItem + NSObject + + + + NSTreeController + NSObjectController + + IBFrameworkSource + AppKit.framework/Headers/NSTreeController.h + + + + NSUserDefaultsController + NSController + + IBFrameworkSource + AppKit.framework/Headers/NSUserDefaultsController.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSClipView.h + + + + NSView + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSRulerView.h + + + + NSView + NSResponder + + + + NSWindow + + + + NSWindow + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSWindow.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSWindowScripting.h + + + + NSWindowController + NSResponder + + showWindow: + id + + + showWindow: + + showWindow: + id + + + + IBFrameworkSource + AppKit.framework/Headers/NSWindowController.h @@ -89054,7 +89160,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {515, 457} {14, 14} {8, 8} - {128, 128} + {512, 512} {11, 11} {10, 3} {32, 32} diff --git a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h new file mode 100644 index 000000000..95bd72cdc --- /dev/null +++ b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h @@ -0,0 +1,97 @@ +/* + Copyright (C) 2023 DeSmuME team + + This file 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 file 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 the this software. If not, see . + */ + +#import + +@class CocoaDSCheatDatabase; +@class CheatWindowDelegate; +@class CocoaDSCheatDBGame; + +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 +@interface CheatDatabaseWindowController : NSWindowController +#else +@interface CheatDatabaseWindowController : NSWindowController +#endif +{ + NSObject *dummyObject; + NSWindow *errorSheet; + NSString *defaultWindowTitle; + NSArrayController *gameListController; + NSTreeController *entryListController; + NSSplitView *splitView; + NSTableView *gameTable; + NSOutlineView *entryOutline; + NSFont *codeViewerFont; + + CheatWindowDelegate *cheatManagerDelegate; + CocoaDSCheatDatabase *database; + + NSString *filePath; + BOOL isFileLoading; + BOOL isCurrentGameFound; + BOOL isSelectedGameTheCurrentGame; + NSInteger currentGameTableRowIndex; + NSString *currentGameIndexString; + + NSString *errorMajorString; + NSString *errorMinorString; + + NSDictionary *initProperties; +} + +@property (readonly) IBOutlet NSObject *dummyObject; +@property (readonly) IBOutlet NSWindow *errorSheet; +@property (readonly) IBOutlet NSArrayController *gameListController; +@property (readonly) IBOutlet NSTreeController *entryListController; +@property (readonly) IBOutlet NSSplitView *splitView; +@property (readonly) IBOutlet NSTableView *gameTable; +@property (readonly) IBOutlet NSOutlineView *entryOutline; + +@property (retain) CheatWindowDelegate *cheatManagerDelegate; +@property (assign) NSFont *codeViewerFont; +@property (retain, nonatomic) CocoaDSCheatDatabase *database; +@property (readonly) NSString *filePath; +@property (readonly) NSString *databaseFormatString; +@property (readonly) NSInteger gameCount; +@property (readonly) NSString *isEncryptedString; +@property (assign) BOOL isFileLoading; +@property (assign) BOOL isCurrentGameFound; +@property (assign) BOOL isSelectedGameTheCurrentGame; + +@property (assign) NSString *errorMajorString; +@property (assign) NSString *errorMinorString; + +- (id) initWithWindowNibName:(NSString *)windowNibName delegate:(CheatWindowDelegate *)theDelegate; +- (void) loadFileStart:(NSURL *)theURL; +- (void) loadFileOnThread:(id)object; +- (void) loadFileDidFinish:(NSNotification *)aNotification; +- (void) updateWindow; +- (void) validateGameTableFonts; ++ (void) validateGameTableFontsForAllWindows; +- (BOOL) validateWillAddColumn; ++ (void) validateWillAddColumnForAllWindows; +- (void) showErrorSheet:(NSInteger)errorCode; +- (void) didEndErrorSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo; + +- (IBAction) openFile:(id)sender; +- (IBAction) selectAll:(id)sender; +- (IBAction) selectNone:(id)sender; +- (IBAction) addSelected:(id)sender; +- (IBAction) selectCurrentGame:(id)sender; +- (IBAction) closeErrorSheet:(id)sender; + +@end diff --git a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm new file mode 100644 index 000000000..b38cb6c89 --- /dev/null +++ b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm @@ -0,0 +1,759 @@ +/* + Copyright (C) 2023 DeSmuME team + + This file 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 file 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 the this software. If not, see . + */ + +#import "CheatDatabaseWindowController.h" +#import "cheatWindowDelegate.h" +#import "../cocoa_globals.h" +#import "../cocoa_cheat.h" +#import "../cocoa_util.h" + +NSMutableArray *cheatDatabaseWindowList = nil; + +@implementation CheatDatabaseWindowController + +@synthesize dummyObject; +@synthesize errorSheet; +@synthesize gameListController; +@synthesize entryListController; +@synthesize splitView; +@synthesize gameTable; +@synthesize entryOutline; + +@synthesize cheatManagerDelegate; +@synthesize codeViewerFont; +@dynamic database; +@dynamic filePath; +@dynamic databaseFormatString; +@dynamic gameCount; +@dynamic isEncryptedString; +@synthesize isFileLoading; +@synthesize isCurrentGameFound; +@synthesize isSelectedGameTheCurrentGame; + +@synthesize errorMajorString; +@synthesize errorMinorString; + +- (id) initWithWindowNibName:(NSString *)windowNibName delegate:(CheatWindowDelegate *)theDelegate +{ + self = [super initWithWindowNibName:windowNibName]; + if (self == nil) + { + return self; + } + + cheatManagerDelegate = [theDelegate retain]; + codeViewerFont = [NSFont fontWithName:@"Monaco" size:13.0]; + + dummyObject = nil; + defaultWindowTitle = [[NSString alloc] initWithString:@"Cheat Database Viewer"]; + database = nil; + isFileLoading = NO; + isCurrentGameFound = NO; + isSelectedGameTheCurrentGame = NO; + currentGameIndexString = [[NSString alloc] initWithString:@"NSNotFound"]; + currentGameTableRowIndex = NSNotFound; + errorMajorString = @"No error has occurred!"; + errorMinorString = @"This is just a placeholder message for initialization purposes."; + + if (cheatDatabaseWindowList == nil) + { + cheatDatabaseWindowList = [[NSMutableArray alloc] initWithObjects:self, nil]; + } + else + { + [cheatDatabaseWindowList addObject:self]; + } + + return self; +} + +- (void)dealloc +{ + [self setCheatManagerDelegate:nil]; + [self setDatabase:nil]; + [currentGameIndexString release]; + [defaultWindowTitle release]; + + [super dealloc]; +} + +- (void) loadFileStart:(NSURL *)theURL +{ + if (theURL == nil) + { + return; + } + + // First check if another cheat database window has already opened the file at this URL. + CheatDatabaseWindowController *foundWindowController = nil; + for (CheatDatabaseWindowController *windowController in cheatDatabaseWindowList) + { + NSURL *databaseURL = [[windowController database] lastFileURL]; + NSString *foundDatabaseFilePath = [databaseURL path]; + + if ( (foundDatabaseFilePath != nil) && ([foundDatabaseFilePath isEqualToString:[theURL path]]) ) + { + foundWindowController = windowController; + break; + } + } + + if (foundWindowController != nil) + { + // If the file is already open, then simply assign that database file to this window. + [self setDatabase:[foundWindowController database]]; + [self updateWindow]; + } + else + { + // If the file is not open, then we need to open it now. Let's do this on a separate + // thread so that we don't lock up the main thread. + [self setIsFileLoading:YES]; + [self setDatabase:nil]; + + NSString *threadNamePrefix = @"org.desmume.DeSmuME.loadDatabaseDidFinish_"; + NSString *fullThreadName = [threadNamePrefix stringByAppendingString:[theURL absoluteString]]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(loadFileDidFinish:) + name:fullThreadName + object:nil]; + + [theURL retain]; + [NSThread detachNewThreadSelector:@selector(loadFileOnThread:) toTarget:self withObject:theURL]; + } +} + +- (void) loadFileOnThread:(id)object +{ + NSAutoreleasePool *threadPool = [[NSAutoreleasePool alloc] init]; + + NSURL *workingURL = (NSURL *)object; + NSString *threadNamePrefix = @"org.desmume.DeSmuME.loadDatabaseDidFinish_"; + NSString *fullThreadName = [threadNamePrefix stringByAppendingString:[workingURL absoluteString]]; + + CheatSystemError error = CheatSystemError_NoError; + CocoaDSCheatDatabase *newDatabase = [[CocoaDSCheatDatabase alloc] initWithFileURL:workingURL error:&error]; + + NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys: + workingURL, @"URL", + [NSNumber numberWithInteger:(NSInteger)error], @"ErrorCode", + nil]; + [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:fullThreadName object:newDatabase userInfo:userInfo]; + + [threadPool release]; +} + +- (void) loadFileDidFinish:(NSNotification *)aNotification +{ + CocoaDSCheatDatabase *newDatabase = [aNotification object]; + NSDictionary *userInfo = [aNotification userInfo]; + NSURL *workingURL = (NSURL *)[userInfo valueForKey:@"URL"]; + CheatSystemError errorCode = (CheatSystemError)[(NSNumber *)[userInfo valueForKey:@"ErrorCode"] integerValue]; + + NSString *threadNamePrefix = @"org.desmume.DeSmuME.loadDatabaseDidFinish_"; + NSString *fullThreadName = [threadNamePrefix stringByAppendingString:[workingURL absoluteString]]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:fullThreadName object:nil]; + + [self setIsFileLoading:NO]; + [self setDatabase:[newDatabase autorelease]]; + [self updateWindow]; + + if (errorCode != CheatSystemError_NoError) + { + [self showErrorSheet:errorCode]; + } + + if (database == nil) + { + return; + } + + // Begin the generation of the cheat database recents menu. + NSString *legacyFilePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"R4Cheat_DatabasePath"]; + BOOL useLegacyFilePath = ( (legacyFilePath != nil) && ([legacyFilePath length] > 0) ); + + NSArray *dbRecentsList = [[NSUserDefaults standardUserDefaults] arrayForKey:@"CheatDatabase_RecentFilePath"]; + NSMutableArray *newRecentsList = [NSMutableArray arrayWithCapacity:[dbRecentsList count] + 1]; + + if (useLegacyFilePath) + { + // We need to check if the legacy file path also exists in the recents list. + // If it does, then the recents list version takes priority. + for (NSDictionary *dbRecentItem in dbRecentsList) + { + NSString *dbRecentItemFilePath = (NSString *)[dbRecentItem valueForKey:@"FilePath"]; + if ([dbRecentItemFilePath isEqualToString:legacyFilePath]) + { + useLegacyFilePath = NO; + break; + } + } + } + + if (useLegacyFilePath) + { + // The legacy file path must always be the first entry of the recents list. + NSDictionary *legacyRecentItem = [NSDictionary dictionaryWithObjectsAndKeys:legacyFilePath, @"FilePath", + [legacyFilePath lastPathComponent], @"FileName", + nil]; + [newRecentsList addObject:legacyRecentItem]; + } + + // Next, we need to add back all of the recent items in the same order in which + // they appear in user defaults, with the exception of our newest item. + NSString *newFilePath = [[database lastFileURL] path]; + for (NSDictionary *dbRecentItem in dbRecentsList) + { + NSString *dbRecentItemFilePath = (NSString *)[dbRecentItem valueForKey:@"FilePath"]; + if ( ![newFilePath isEqualToString:dbRecentItemFilePath] ) + { + [newRecentsList addObject:dbRecentItem]; + } + } + + // Create our new recent item... + NSDictionary *newRecentItem = [NSDictionary dictionaryWithObjectsAndKeys:newFilePath, @"FilePath", + [newFilePath lastPathComponent], @"FileName", + [NSDate date], @"AddedDate", + [[self window] stringWithSavedFrame], @"WindowFrame", + [NSNumber numberWithFloat:[[[splitView subviews] objectAtIndex:0] frame].size.height], @"WindowSplitViewDividerPosition", + nil]; + + // ...and then add the newest recent item, ensuring that it is always last in the list. + [newRecentsList addObject:newRecentItem]; + + // We're done generating the new recent items list, so write it back to user defaults, and then + // send a notification that UI elements needs to be updated. + [[NSUserDefaults standardUserDefaults] setObject:newRecentsList forKey:@"CheatDatabase_RecentFilePath"]; + [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:@"org.desmume.DeSmuME.updateCheatDatabaseRecentsMenu" object:[newRecentsList retain] userInfo:nil]; +} + +- (void) updateWindow +{ + if ([self database] == nil) + { + [[self window] setTitle:defaultWindowTitle]; + } + else + { + [[self window] setTitle:[database description]]; + } + + [[self window] setRepresentedURL:[database lastFileURL]]; + [gameListController setContent:[database gameList]]; + + NSIndexSet *selectedRows = [gameTable selectedRowIndexes]; + [gameTable deselectAll:nil]; + [gameTable selectRowIndexes:selectedRows byExtendingSelection:NO]; + + [self validateGameTableFonts]; + [self selectCurrentGame:nil]; +} + +- (void) validateGameTableFonts +{ + CheatWindowDelegate *delegate = [self cheatManagerDelegate]; + CocoaDSCheatManager *cheatManager = [delegate cdsCheats]; + + if ( (delegate == nil) || (cheatManager == nil) ) + { + currentGameTableRowIndex = NSNotFound; + [currentGameIndexString release]; + currentGameIndexString = [[NSString alloc] initWithString:@"NSNotFound"]; + [self setIsCurrentGameFound:NO]; + return; + } + + NSString *currentGameCode = [cheatManager currentGameCode]; + const NSUInteger currentGameCRC = [cheatManager currentGameCRC]; + + for (CocoaDSCheatDBGame *game in [gameListController content]) + { + if ( ([game crc] == currentGameCRC) && ([[game serial] isEqualToString:currentGameCode]) ) + { + [currentGameIndexString release]; + currentGameIndexString = [[NSString alloc] initWithFormat:@"%llu", (unsigned long long)[game index]]; + [self setIsCurrentGameFound:YES]; + break; + } + } +} + ++ (void) validateGameTableFontsForAllWindows +{ + if (cheatDatabaseWindowList == nil) + { + return; + } + + for (CheatDatabaseWindowController *windowController in cheatDatabaseWindowList) + { + [windowController validateGameTableFonts]; + [[windowController gameTable] setNeedsDisplay]; + } +} + +- (BOOL) validateWillAddColumn +{ + BOOL showWillAddColumn = NO; + + CheatWindowDelegate *delegate = [self cheatManagerDelegate]; + CocoaDSCheatManager *cheatManager = [delegate cdsCheats]; + + NSArray *selectedObjects = [gameListController selectedObjects]; + if ( (selectedObjects == nil) || ([selectedObjects count] == 0) ) + { + return showWillAddColumn; + } + + CocoaDSCheatDBGame *selectedGame = [selectedObjects objectAtIndex:0]; + + if ( (delegate != nil) && (cheatManager != nil) && ([selectedGame serial] != nil) ) + { + showWillAddColumn = ([[selectedGame serial] isEqualToString:[cheatManager currentGameCode]]) && ([selectedGame crc] == [cheatManager currentGameCRC]); + } + + NSTableColumn *willAddColumn = [entryOutline tableColumnWithIdentifier:@"willAdd"]; + [willAddColumn setHidden:!showWillAddColumn]; + + [self setIsSelectedGameTheCurrentGame:showWillAddColumn]; + + return showWillAddColumn; +} + ++ (void) validateWillAddColumnForAllWindows +{ + if (cheatDatabaseWindowList == nil) + { + return; + } + + for (CheatDatabaseWindowController *windowController in cheatDatabaseWindowList) + { + [windowController validateWillAddColumn]; + } +} + +- (void) showErrorSheet:(NSInteger)errorCode +{ + switch (errorCode) + { + case CheatSystemError_NoError: + [self setErrorMajorString:@"No error has occurred."]; + [self setErrorMinorString:@"This message is a placeholder. You are seeing this error as a test for this app's error handling.\n\nError Code: %i"]; + break; + + case CheatSystemError_FileOpenFailed: + [self setErrorMajorString:@"Failed to open file."]; + [self setErrorMinorString:[NSString stringWithFormat:@"The system could not open the cheat database file. This problem is usually because another app is using it, or because the file permissions disallow read access.\n\nError Code: %i", (int)errorCode]]; + break; + + case CheatSystemError_FileFormatInvalid: + [self setErrorMajorString:@"Invalid file format."]; + [self setErrorMinorString:[NSString stringWithFormat:@"DeSmuME could not recognize the file format of the cheat database file. Currently, DeSmuME only recognizes the R4 file format. It is also possible that the file data is corrupted.\n\nError Code: %i", (int)errorCode]]; + break; + + case CheatSystemError_GameNotFound: + { + CheatWindowDelegate *delegate = [self cheatManagerDelegate]; + CocoaDSCheatManager *cheatManager = [delegate cdsCheats]; + [self setErrorMajorString:@"Current game not found in database."]; + [self setErrorMinorString:[NSString stringWithFormat:@"The current game (Serial='%@', CRC=%llu) could not be found in the cheat database.\n\nError Code: %i", [cheatManager currentGameCode], (unsigned long long)[cheatManager currentGameCRC], (int)errorCode]]; + break; + } + + case CheatSystemError_LoadEntryError: + [self setErrorMajorString:@"Could not read cheat entries."]; + [self setErrorMinorString:[NSString stringWithFormat:@"The entry data for the selected game could not be read. This is usually due to file data corruption.\n\nError Code: %i", (int)errorCode]]; + break; + + case CheatSystemError_FileDoesNotExist: + [self setErrorMajorString:@"The file does not exist."]; + [self setErrorMinorString:[NSString stringWithFormat:@"If this file was selected from the Recents Menu, then it has been removed.\n\nError Code: %i", (int)errorCode]]; + break; + + default: + [self setErrorMajorString:@"An unknown error has occurred."]; + [self setErrorMinorString:[NSString stringWithFormat:@"Error Code: %i", (int)errorCode]]; + break; + } + +#if defined(MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9) + if ([[self window] respondsToSelector:@selector(beginSheet:completionHandler:)]) + { + [[self window] beginSheet:errorSheet + completionHandler:^(NSModalResponse response) { + [self didEndErrorSheet:nil returnCode:response contextInfo:nil]; + } ]; + } + else +#endif + { + SILENCE_DEPRECATION_MACOS_10_10( [NSApp beginSheet:errorSheet + modalForWindow:[self window] + modalDelegate:self + didEndSelector:@selector(didEndErrorSheet:returnCode:contextInfo:) + contextInfo:nil] ); + } +} + +- (void) didEndErrorSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo +{ + [sheet orderOut:self]; +} + +#pragma mark - +#pragma mark Dynamic Properties + +- (void) setDatabase:(CocoaDSCheatDatabase *)theDatabase +{ + [self willChangeValueForKey:@"filePath"]; + [self willChangeValueForKey:@"databaseFormatString"]; + [self willChangeValueForKey:@"gameCount"]; + [self willChangeValueForKey:@"isEncryptedString"]; + + [theDatabase retain]; + [database release]; + database = theDatabase; + + [self didChangeValueForKey:@"filePath"]; + [self didChangeValueForKey:@"databaseFormatString"]; + [self didChangeValueForKey:@"gameCount"]; + [self didChangeValueForKey:@"isEncryptedString"]; +} + +- (CocoaDSCheatDatabase *) database +{ + return database; +} + +- (NSString *) filePath +{ + if ( (database != nil) && ([database lastFileURL] != nil) ) + { + return [[database lastFileURL] path]; + } + else if ([self isFileLoading]) + { + return @"Loading database file..."; + } + + return @"No database file loaded."; +} + +- (NSString *) databaseFormatString +{ + if (database != nil) + { + return [database formatString]; + } + + return @"---"; +} + +- (NSInteger) gameCount +{ + if (database != nil) + { + return [[database gameList] count]; + } + + return 0; +} + +- (NSString *) isEncryptedString +{ + if (database != nil) + { + return [database isEncrypted] ? @"Yes" : @"No"; + } + + return @"---"; +} + +#pragma mark - +#pragma mark IBActions + +- (IBAction) openFile:(id)sender +{ + NSOpenPanel *panel = [NSOpenPanel openPanel]; + [panel setCanChooseDirectories:NO]; + [panel setCanChooseFiles:YES]; + [panel setResolvesAliases:YES]; + [panel setAllowsMultipleSelection:NO]; + [panel setTitle:NSSTRING_TITLE_OPEN_CHEAT_DB_PANEL]; + NSArray *fileTypes = [NSArray arrayWithObjects:@FILE_EXT_R4_CHEAT_DB, nil]; + + // The NSOpenPanel/NSSavePanel method -(void)beginSheetForDirectory:file:types:modalForWindow:modalDelegate:didEndSelector:contextInfo + // is deprecated in Mac OS X v10.6. +#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 + if (IsOSXVersionSupported(10, 6, 0)) + { + [panel setAllowedFileTypes:fileTypes]; + [panel beginSheetModalForWindow:[self window] + completionHandler:^(NSInteger result) { + [self chooseCheatDatabaseDidEnd:panel returnCode:(int)result contextInfo:nil]; + } ]; + } + else +#endif + { + SILENCE_DEPRECATION_MACOS_10_6( [panel beginSheetForDirectory:nil + file:nil + types:fileTypes + modalForWindow:[self window] + modalDelegate:self + didEndSelector:@selector(chooseCheatDatabaseDidEnd:returnCode:contextInfo:) + contextInfo:nil] ); + } +} + +- (void) chooseCheatDatabaseDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + [sheet orderOut:self]; + + if (returnCode == GUI_RESPONSE_CANCEL) + { + return; + } + + NSURL *selectedFileURL = [[sheet URLs] lastObject]; //hopefully also the first object + [self loadFileStart:selectedFileURL]; +} + +- (IBAction) selectAll:(id)sender +{ + NSMutableArray *entryTree = [entryListController content]; + if (entryTree == nil) + { + return; + } + + for (CocoaDSCheatDBEntry *entry in entryTree) + { + [entry setWillAdd:YES]; + } + + [entryOutline setNeedsDisplay]; +} + +- (IBAction) selectNone:(id)sender +{ + NSMutableArray *entryTree = [entryListController content]; + if (entryTree == nil) + { + return; + } + + for (CocoaDSCheatDBEntry *entry in entryTree) + { + [entry setWillAdd:NO]; + } + + [entryOutline setNeedsDisplay]; +} + +- (IBAction) addSelected:(id)sender +{ + CheatWindowDelegate *delegate = [self cheatManagerDelegate]; + if (delegate == nil) + { + return; + } + + CocoaDSCheatManager *cheatManager = [delegate cdsCheats]; + if (cheatManager == nil) + { + return; + } + + NSString *currentGameCode = [cheatManager currentGameCode]; + NSUInteger currentGameCRC = [cheatManager currentGameCRC]; + if ( (currentGameCode == nil) || (currentGameCRC == 0) ) + { + return; + } + + NSMutableArray *entryTree = [entryListController content]; + if (entryTree == nil) + { + return; + } + + NSInteger selectedIndex = [gameTable selectedRow]; + CocoaDSCheatDBGame *selectedGame = (CocoaDSCheatDBGame *)[[gameListController arrangedObjects] objectAtIndex:selectedIndex]; + + if ( (![[selectedGame serial] isEqualToString:currentGameCode]) || ([selectedGame crc] != currentGameCRC) ) + { + return; + } + + CocoaDSCheatDBEntry *rootEntry = [selectedGame entryRoot]; + if (rootEntry == nil) + { + return; + } + + const NSInteger addedItemCount = [cheatManager databaseAddSelectedInEntry:[selectedGame entryRoot]]; + if (addedItemCount > 0) + { + [[delegate cheatListController] setContent:[cheatManager sessionList]]; + [cheatManager save]; + } +} + +- (IBAction) selectCurrentGame:(id)sender +{ + CheatWindowDelegate *delegate = [self cheatManagerDelegate]; + if (delegate == nil) + { + return; + } + + CocoaDSCheatManager *cheatManager = [delegate cdsCheats]; + if (cheatManager == nil) + { + return; + } + + NSString *currentGameCode = [cheatManager currentGameCode]; + NSUInteger currentGameCRC = [cheatManager currentGameCRC]; + if ( (currentGameCode == nil) || (currentGameCRC == 0) ) + { + return; + } + + NSUInteger selectionIndex = NSNotFound; + + NSArray *arrangedObjects = (NSArray *)[gameListController arrangedObjects]; + for (CocoaDSCheatDBGame *game in arrangedObjects) + { + if ( ([game crc] == currentGameCRC) && ([[game serial] isEqualToString:currentGameCode]) ) + { + selectionIndex = [arrangedObjects indexOfObject:game]; + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:selectionIndex]; + [gameTable selectRowIndexes:indexSet byExtendingSelection:NO]; + [gameTable scrollRowToVisible:selectionIndex]; + break; + } + } +} + +- (IBAction) closeErrorSheet:(id)sender +{ + NSWindow *sheet = [(NSControl *)sender window]; + const NSInteger code = [(NSControl *)sender tag]; + + [CocoaDSUtil endSheet:sheet returnCode:code]; +} + +#pragma mark - +#pragma mark NSWindowDelegate Protocol + +- (void)windowDidLoad +{ + // Save a copy of the default window title before we replace it + // with the database file's description. + NSString *oldDefaultWindowTitle = defaultWindowTitle; + defaultWindowTitle = [[[self window] title] copy]; + [oldDefaultWindowTitle release]; +} + +- (void)windowWillClose:(NSNotification *)notification +{ + NSArray *userDefaultsRecentsList = [[NSUserDefaults standardUserDefaults] arrayForKey:@"CheatDatabase_RecentFilePath"]; + if ( (userDefaultsRecentsList != nil) && ([userDefaultsRecentsList count] > 0) ) + { + NSMutableArray *dbRecentsList = [NSMutableArray arrayWithCapacity:[userDefaultsRecentsList count]]; + + for (NSDictionary *recentItem in userDefaultsRecentsList) + { + NSString *thisFilePath = [[database lastFileURL] path]; + NSString *recentItemPath = (NSString *)[recentItem objectForKey:@"FilePath"]; + + if ( (thisFilePath != nil) && ([recentItemPath isEqualToString:thisFilePath]) ) + { + NSMutableDictionary *newRecentItem = [NSMutableDictionary dictionaryWithDictionary:recentItem]; + [newRecentItem setObject:[[self window] stringWithSavedFrame] forKey:@"WindowFrame"]; + [newRecentItem setObject:[NSNumber numberWithFloat:[[[splitView subviews] objectAtIndex:0] frame].size.height] forKey:@"WindowSplitViewDividerPosition"]; + + [dbRecentsList addObject:newRecentItem]; + } + else + { + [dbRecentsList addObject:recentItem]; + } + } + + [[NSUserDefaults standardUserDefaults] setObject:dbRecentsList forKey:@"CheatDatabase_RecentFilePath"]; + } + + [cheatDatabaseWindowList removeObject:self]; + [self release]; +} + +#pragma mark - +#pragma mark NSTableViewDelegate Protocol + +- (void)tableViewSelectionDidChange:(NSNotification *)aNotification +{ + NSTableView *table = (NSTableView *)[aNotification object]; + NSInteger rowIndex = [table selectedRow]; + + if (table == gameTable) + { + if (rowIndex >= 0) + { + NSArray *selectedObjects = [gameListController selectedObjects]; + CocoaDSCheatDBGame *selectedGame = [selectedObjects objectAtIndex:0]; + CocoaDSCheatDBEntry *entryRoot = [database loadGameEntry:selectedGame]; + [self validateWillAddColumn]; + [entryListController setContent:[entryRoot child]]; + + if (entryRoot == nil) + { + [self showErrorSheet:CheatSystemError_LoadEntryError]; + } + } + else + { + [entryListController setContent:nil]; + } + } +} + +- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + NSString *cellString = [cell stringValue]; + if ( (cellString != nil) && [cellString isEqualToString:currentGameIndexString] ) + { + currentGameTableRowIndex = row; + } + + if ( (cellString != nil) && (row == currentGameTableRowIndex) ) + { + [cell setFont:[NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]]]; + } + else + { + [cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; + currentGameTableRowIndex = NSNotFound; + } +} + +@end diff --git a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.h b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.h index bbae33a26..527cf5c5f 100644 --- a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.h +++ b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.h @@ -54,8 +54,8 @@ class AudioSampleBlockGenerator; NSObjectController *cheatWindowController; NSObjectController *slot2WindowController; NSArrayController *inputDeviceListController; - NSArrayController *cheatListController; - NSArrayController *cheatDatabaseController; + + NSMenu *cheatDatabaseRecentsMenu; RomInfoPanel *romInfoPanel; @@ -148,8 +148,8 @@ class AudioSampleBlockGenerator; @property (readonly) IBOutlet NSObjectController *cheatWindowController; @property (readonly) IBOutlet NSObjectController *slot2WindowController; @property (readonly) IBOutlet NSArrayController *inputDeviceListController; -@property (readonly) IBOutlet NSArrayController *cheatListController; -@property (readonly) IBOutlet NSArrayController *cheatDatabaseController; + +@property (readonly) IBOutlet NSMenu *cheatDatabaseRecentsMenu; @property (readonly) IBOutlet RomInfoPanel *romInfoPanel; @@ -214,6 +214,9 @@ class AudioSampleBlockGenerator; - (IBAction) stopReplay:(id)sender; - (IBAction) importRomSave:(id)sender; - (IBAction) exportRomSave:(id)sender; +- (IBAction) openCheatDatabaseFile:(id)sender; +- (IBAction) clearCheatDatabaseRecents:(id)sender; +- (IBAction) openRecentCheatDatabase:(id)sender; // Emulation Menu - (IBAction) toggleSpeedLimiter:(id)sender; @@ -299,6 +302,7 @@ class AudioSampleBlockGenerator; - (BOOL) loadRomByURL:(NSURL *)romURL asynchronous:(BOOL)willLoadAsync; - (void) loadRomDidFinish:(NSNotification *)aNotification; - (BOOL) unloadRom; +- (void) updateCheatDatabaseRecentsMenu:(NSNotification *)aNotification; - (void) addOutputToCore:(CocoaDSOutput *)theOutput; - (void) removeOutputFromCore:(CocoaDSOutput *)theOutput; diff --git a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm index 022a51e05..9a0b82b18 100644 --- a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm @@ -19,6 +19,7 @@ #import "DisplayWindowController.h" #import "InputManager.h" #import "cheatWindowDelegate.h" +#import "CheatDatabaseWindowController.h" #import "Slot2WindowDelegate.h" #import "MacAVCaptureTool.h" #import "MacScreenshotCaptureTool.h" @@ -56,11 +57,11 @@ @synthesize cdsCoreController; @synthesize cdsSoundController; @synthesize cheatWindowController; -@synthesize cheatListController; -@synthesize cheatDatabaseController; @synthesize slot2WindowController; @synthesize inputDeviceListController; +@synthesize cheatDatabaseRecentsMenu; + @synthesize romInfoPanel; @synthesize displayRotationPanel; @@ -196,6 +197,11 @@ name:@"org.desmume.DeSmuME.handleEmulatorExecutionState" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateCheatDatabaseRecentsMenu:) + name:@"org.desmume.DeSmuME.updateCheatDatabaseRecentsMenu" + object:nil]; + return self; } @@ -804,6 +810,96 @@ [self restoreCoreState]; } +- (IBAction) openCheatDatabaseFile:(id)sender +{ + CheatDatabaseWindowController *newWindowController = [[CheatDatabaseWindowController alloc] initWithWindowNibName:@"CheatDatabaseViewer" delegate:cheatWindowDelegate]; + [newWindowController window]; // Just reference the window to force the NSWindow object to load. + + [[newWindowController window] makeKeyAndOrderFront:sender]; + [[newWindowController window] makeMainWindow]; + [newWindowController openFile:sender]; +} + +- (IBAction) clearCheatDatabaseRecents:(id)sender +{ + NSArray *menuItemList = [cheatDatabaseRecentsMenu itemArray]; + + for (NSMenuItem *menuItem in menuItemList) + { + if ( ([menuItem action] == @selector(openRecentCheatDatabase:)) || [menuItem isSeparatorItem] ) + { + [cheatDatabaseRecentsMenu removeItem:menuItem]; + } + } + + NSArray *emptyArray = [[[NSArray alloc] init] autorelease]; + [[NSUserDefaults standardUserDefaults] setObject:emptyArray forKey:@"CheatDatabase_RecentFilePath"]; + + // Also remove the legacy setting. + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"R4Cheat_DatabasePath"]; +} + +- (IBAction) openRecentCheatDatabase:(id)sender +{ + CheatDatabaseWindowController *newWindowController = [[CheatDatabaseWindowController alloc] initWithWindowNibName:@"CheatDatabaseViewer" delegate:cheatWindowDelegate]; + [newWindowController window]; // Just reference the window to force the NSWindow object to load. + + [[newWindowController window] makeKeyAndOrderFront:self]; + [[newWindowController window] makeMainWindow]; + + NSArray *recentDBFilePathsList = [[NSUserDefaults standardUserDefaults] arrayForKey:@"CheatDatabase_RecentFilePath"]; + NSInteger index = [CocoaDSUtil getIBActionSenderTag:sender]; + NSDictionary *recentItem = (NSDictionary *)[recentDBFilePathsList objectAtIndex:index]; + NSString *recentItemFilePath = nil; + + if (recentItem != nil) + { + // Set up the window properties. + NSString *windowFrameString = (NSString *)[recentItem objectForKey:@"WindowFrame"]; + if (windowFrameString != nil) + { + [[newWindowController window] setFrameFromString:windowFrameString]; + } + + NSNumber *windowSplitViewDividerPositionNumber = (NSNumber *)[recentItem objectForKey:@"WindowSplitViewDividerPosition"]; + if (windowSplitViewDividerPositionNumber != nil) + { + CGFloat dividerPosition = [windowSplitViewDividerPositionNumber floatValue]; + [[newWindowController splitView] setPosition:dividerPosition ofDividerAtIndex:0]; + } + + // Check for the file's existence at its path, and then handle appropriately. + recentItemFilePath = (NSString *)[recentItem objectForKey:@"FilePath"]; + NSFileManager *fileManager = [[NSFileManager alloc] init]; + BOOL doesFileExist = [fileManager fileExistsAtPath:recentItemFilePath]; + [fileManager release]; + + if (!doesFileExist) + { + // If the file does not exist, then report the error to the user, and the remove the + // nonexistent file from the recents menu. + [newWindowController showErrorSheet:CheatSystemError_FileDoesNotExist]; + + NSMutableArray *newRecentsList = [NSMutableArray arrayWithCapacity:[recentDBFilePathsList count]]; + + for (NSDictionary *theItem in recentDBFilePathsList) + { + if (theItem != recentItem) + { + [newRecentsList addObject:theItem]; + } + } + + [[NSUserDefaults standardUserDefaults] setObject:newRecentsList forKey:@"CheatDatabase_RecentFilePath"]; + [self updateCheatDatabaseRecentsMenu:nil]; + return; + } + } + + NSURL *dbFileURL = [NSURL fileURLWithPath:recentItemFilePath]; + [newWindowController loadFileStart:dbFileURL]; +} + - (IBAction) toggleExecutePause:(id)sender { [inputManager dispatchCommandUsingIBAction:_cmd sender:sender]; @@ -2029,6 +2125,93 @@ return result; } +- (void) updateCheatDatabaseRecentsMenu:(NSNotification *)aNotification +{ + NSArray *dbRecentsList = (NSArray *)[aNotification object]; + BOOL needReleaseObject = (dbRecentsList != nil); + + if ( (dbRecentsList == nil) || ([dbRecentsList count] == 0) ) + { + dbRecentsList = [[NSUserDefaults standardUserDefaults] arrayForKey:@"CheatDatabase_RecentFilePath"]; + } + + NSMutableArray *newRecentsList = [NSMutableArray arrayWithArray:dbRecentsList]; + + // Note that we're relying on the notification object to retain this prior to + // sending the notification. + if (needReleaseObject) + { + [dbRecentsList release]; + } + + NSString *legacyFilePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"R4Cheat_DatabasePath"]; + BOOL useLegacyFilePath = ( (legacyFilePath != nil) && ([legacyFilePath length] > 0) ); + + if (useLegacyFilePath) + { + // We need to check if the legacy file path also exists in the recents list. + // If it does, then the recents list version takes priority. + for (NSDictionary *dbRecentItem in dbRecentsList) + { + NSString *dbRecentItemFilePath = (NSString *)[dbRecentItem valueForKey:@"FilePath"]; + if ([dbRecentItemFilePath isEqualToString:legacyFilePath]) + { + useLegacyFilePath = NO; + break; + } + } + } + + if (useLegacyFilePath) + { + // The legacy file path must always be the first entry of the recents list. + NSDictionary *legacyRecentItem = [NSDictionary dictionaryWithObjectsAndKeys:legacyFilePath, @"FilePath", + [legacyFilePath lastPathComponent], @"FileName", + nil]; + [newRecentsList insertObject:legacyRecentItem atIndex:0]; + + if ([newRecentsList count] == 1) + { + // If the legacy file path is the only item in the recents list, then we can write it + // back to user defaults right now. + [[NSUserDefaults standardUserDefaults] setObject:newRecentsList forKey:@"CheatDatabase_RecentFilePath"]; + } + } + + NSArray *recentsMenuItems = [cheatDatabaseRecentsMenu itemArray]; + for (NSMenuItem *menuItem in recentsMenuItems) + { + if ( [menuItem action] == @selector(openRecentCheatDatabase:) ) + { + [cheatDatabaseRecentsMenu removeItem:menuItem]; + } + } + + if ([newRecentsList count] > 0) + { + if ( ![[cheatDatabaseRecentsMenu itemAtIndex:0] isSeparatorItem] ) + { + [cheatDatabaseRecentsMenu insertItem:[NSMenuItem separatorItem] atIndex:0]; + } + } + + // Recent files are added in reverse order, in which least recent files appear below + // more recent files in the menu. The most recent file should be at the top of the menu. + for (NSDictionary *recentItem in newRecentsList) + { + NSString *menuNameString = [recentItem objectForKey:@"FileName"]; + if ( (menuNameString == nil) || ([menuNameString length] == 0) ) + { + menuNameString = [recentItem objectForKey:@"FilePath"]; + } + + NSMenuItem *newMenuItem = [[[NSMenuItem alloc] initWithTitle:menuNameString action:@selector(openRecentCheatDatabase:) keyEquivalent:@""] autorelease]; + [newMenuItem setTag:[newRecentsList indexOfObject:recentItem]]; + [newMenuItem setTarget:self]; + [cheatDatabaseRecentsMenu insertItem:newMenuItem atIndex:0]; + } +} + - (void) handleNDSError:(NSNotification *)aNotification { [self setIsUserInterfaceBlockingExecution:YES]; @@ -2980,6 +3163,13 @@ enable = NO; } } + else if (theAction == @selector(clearCheatDatabaseRecents:)) + { + if ([cheatDatabaseRecentsMenu numberOfItems] < 2) + { + enable = NO; + } + } else if (theAction == @selector(changeCoreSpeed:)) { NSInteger speedScalar = (NSInteger)([cdsCore speedScalar] * 100.0); diff --git a/desmume/src/frontend/cocoa/userinterface/appDelegate.h b/desmume/src/frontend/cocoa/userinterface/appDelegate.h index 1d15b7d98..9b6e8bfa0 100644 --- a/desmume/src/frontend/cocoa/userinterface/appDelegate.h +++ b/desmume/src/frontend/cocoa/userinterface/appDelegate.h @@ -36,6 +36,8 @@ NSObjectController *emuControlController; NSObjectController *prefWindowController; NSObjectController *cdsCoreController; + NSObjectController *databaseFileController; + NSArrayController *gameListController; FileMigrationDelegate *migrationDelegate; MacAVCaptureToolDelegate *avCaptureToolDelegate; WifiSettingsPanelDelegate *wifiSettingsPanelDelegate; @@ -63,6 +65,8 @@ @property (readonly) IBOutlet NSObjectController *emuControlController; @property (readonly) IBOutlet NSObjectController *prefWindowController; @property (readonly) IBOutlet NSObjectController *cdsCoreController; +@property (readonly) IBOutlet NSObjectController *databaseFileController; +@property (readonly) IBOutlet NSArrayController *gameListController; @property (readonly) IBOutlet FileMigrationDelegate *migrationDelegate; @property (readonly) IBOutlet MacAVCaptureToolDelegate *avCaptureToolDelegate; @property (readonly) IBOutlet WifiSettingsPanelDelegate *wifiSettingsPanelDelegate; diff --git a/desmume/src/frontend/cocoa/userinterface/appDelegate.mm b/desmume/src/frontend/cocoa/userinterface/appDelegate.mm index 416ce34e1..bcfd2bae2 100644 --- a/desmume/src/frontend/cocoa/userinterface/appDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/appDelegate.mm @@ -1,6 +1,6 @@ /* Copyright (C) 2011 Roger Manuel - Copyright (C) 2011-2022 DeSmuME Team + Copyright (C) 2011-2023 DeSmuME Team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,6 +28,7 @@ #import "inputPrefsView.h" #import "cocoa_core.h" +#import "cocoa_cheat.h" #import "cocoa_GPU.h" #import "cocoa_file.h" #import "cocoa_firmware.h" @@ -50,6 +51,8 @@ @synthesize emuControlController; @synthesize prefWindowController; @synthesize cdsCoreController; +@synthesize databaseFileController; +@synthesize gameListController; @synthesize avCaptureToolDelegate; @synthesize wifiSettingsPanelDelegate; @synthesize migrationDelegate; @@ -312,6 +315,7 @@ // Bring the application to the front [NSApp activateIgnoringOtherApps:YES]; [emuControl restoreDisplayWindowStates]; + [emuControl updateCheatDatabaseRecentsMenu:nil]; // Load a new ROM on launch per user preferences. if ([[NSUserDefaults standardUserDefaults] objectForKey:@"General_AutoloadROMOnLaunch"] != nil) diff --git a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h index 0d80e2940..099e582b2 100644 --- a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h +++ b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h @@ -37,7 +37,6 @@ NSTableView *cheatSearchListTable; NSArrayController *cheatListController; NSArrayController *cheatSearchListController; - NSArrayController *cheatDatabaseController; NSObjectController *cheatWindowController; NSObjectController *cheatSelectedItemController; @@ -54,13 +53,14 @@ NSSearchField *searchField; - NSWindow *cheatDatabaseSheet; - NSFont *codeEditorFont; NSMutableDictionary *bindings; CocoaDSCheatItem *workingCheat; CocoaDSCheatManager *cdsCheats; + + NSString *currentGameCode; + NSInteger currentGameCRC; } @property (assign) IBOutlet NSObject *dummyObject; @@ -71,7 +71,6 @@ @property (readonly) IBOutlet NSTableView *cheatSearchListTable; @property (readonly) IBOutlet NSArrayController *cheatListController; @property (readonly) IBOutlet NSArrayController *cheatSearchListController; -@property (readonly) IBOutlet NSArrayController *cheatDatabaseController; @property (readonly) IBOutlet NSObjectController *cheatWindowController; @property (readonly) IBOutlet NSObjectController *cheatSelectedItemController; @@ -87,19 +86,19 @@ @property (readonly) IBOutlet NSSearchField *searchField; -@property (readonly) IBOutlet NSWindow *cheatDatabaseSheet; - @property (assign) NSFont *codeEditorFont; @property (readonly) NSMutableDictionary *bindings; @property (retain) CocoaDSCheatItem *workingCheat; @property (retain) CocoaDSCheatManager *cdsCheats; +@property (retain) NSString *currentGameCode; +@property (assign) NSInteger currentGameCRC; - (BOOL) cheatSystemStart:(CocoaDSCheatManager *)theManager; - (void) cheatSystemEnd; - (IBAction) addToList:(id)sender; - (IBAction) removeFromList:(id)sender; -- (IBAction) viewDatabase:(id)sender; +- (IBAction) removeAllFromList:(id)sender; - (IBAction) setInternalCheatValue:(id)sender; - (IBAction) applyConfiguration:(id)sender; - (IBAction) selectCheatType:(id)sender; @@ -112,11 +111,4 @@ - (void) setCheatConfigViewByType:(NSInteger)cheatTypeID; - (void) setCheatSearchViewByStyle:(NSInteger)searchStyleID; -- (void) databaseLoadFromFile:(NSURL *)fileURL; -- (void) addSelectedFromCheatDatabase; -- (IBAction) selectAllCheatsInDatabase:(id)sender; -- (IBAction) selectNoneCheatsInDatabase:(id)sender; -- (IBAction) closeCheatDatabaseSheet:(id)sender; -- (void) didEndCheatDatabaseSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo; - @end diff --git a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm index e4816ac0f..53a421d09 100644 --- a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm @@ -17,6 +17,7 @@ */ #import "cheatWindowDelegate.h" +#import "CheatDatabaseWindowController.h" #import "cocoa_globals.h" #import "cocoa_cheat.h" @@ -33,7 +34,6 @@ @synthesize cheatSearchListTable; @synthesize cheatListController; @synthesize cheatSearchListController; -@synthesize cheatDatabaseController; @synthesize cheatWindowController; @synthesize cheatSelectedItemController; @@ -48,12 +48,12 @@ @synthesize searchField; -@synthesize cheatDatabaseSheet; - @synthesize codeEditorFont; @synthesize bindings; @synthesize cdsCheats; @synthesize workingCheat; +@synthesize currentGameCode; +@synthesize currentGameCRC; - (id)init { @@ -71,24 +71,26 @@ return self; } + currentGameCode = nil; + currentGameCRC = 0; workingCheat = nil; currentView = nil; currentSearchStyleView = nil; codeEditorFont = [NSFont fontWithName:@"Monaco" size:13.0]; [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"hasSelection"]; - [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"hasItems"]; [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"isRunningSearch"]; [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"isSearchStarted"]; - [bindings setValue:[NSNumber numberWithInteger:CHEATSEARCH_SEARCHSTYLE_EXACT_VALUE] forKey:@"cheatSearchStyle"]; + [bindings setValue:[NSNumber numberWithInteger:CheatSearchStyle_ExactValue] forKey:@"cheatSearchStyle"]; [bindings setValue:[NSNumber numberWithInteger:CHEATSEARCH_UNSIGNED] forKey:@"cheatSearchSignType"]; [bindings setValue:@"Search not started." forKey:@"cheatSearchAddressCount"]; - if ([CocoaDSCheatItem iconInternalCheat] == nil || [CocoaDSCheatItem iconActionReplay] == nil || [CocoaDSCheatItem iconCodeBreaker] == nil) + if ([CocoaDSCheatItem iconDirectory] == nil || [CocoaDSCheatItem iconInternalCheat] == nil || [CocoaDSCheatItem iconActionReplay] == nil || [CocoaDSCheatItem iconCodeBreaker] == nil) { - [CocoaDSCheatItem setIconInternalCheat:[NSImage imageNamed:@"NSApplicationIcon"]]; - [CocoaDSCheatItem setIconActionReplay:[NSImage imageNamed:@"Icon_ActionReplay_128x128"]]; - [CocoaDSCheatItem setIconCodeBreaker:[NSImage imageNamed:@"Icon_CodeBreaker_128x128"]]; + [CocoaDSCheatItem setIconDirectory:[[NSImage imageNamed:@"NSFolder"] retain]]; + [CocoaDSCheatItem setIconInternalCheat:[[NSImage imageNamed:@"NSApplicationIcon"] retain]]; + [CocoaDSCheatItem setIconActionReplay:[[NSImage imageNamed:@"Icon_ActionReplay_128x128"] retain]]; + [CocoaDSCheatItem setIconCodeBreaker:[[NSImage imageNamed:@"Icon_CodeBreaker_128x128"] retain]]; } return self; @@ -98,6 +100,7 @@ { [self setWorkingCheat:nil]; [self setCdsCheats:nil]; + [self setCurrentGameCode:nil]; [bindings release]; [super dealloc]; @@ -113,19 +116,14 @@ } [self setCdsCheats:cheatManager]; + [self setCurrentGameCode:[cheatManager currentGameCode]]; + [self setCurrentGameCRC:[cheatManager currentGameCRC]]; [cheatManager loadFromMaster]; [cheatListController setContent:[cheatManager sessionList]]; - NSMutableDictionary *cheatWindowBindings = (NSMutableDictionary *)[cheatWindowController content]; - [cheatWindowBindings setValue:self forKey:@"cheatWindowDelegateKey"]; - - NSString *dbFilePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"R4Cheat_DatabasePath"]; - if (dbFilePath != nil) - { - [self databaseLoadFromFile:[NSURL fileURLWithPath:dbFilePath]]; - } - - [self setCheatSearchViewByStyle:CHEATSEARCH_SEARCHSTYLE_EXACT_VALUE]; + [self setCheatSearchViewByStyle:CheatSearchStyle_ExactValue]; + [CheatDatabaseWindowController validateWillAddColumnForAllWindows]; + [CheatDatabaseWindowController validateGameTableFontsForAllWindows]; didStartSuccessfully = YES; return didStartSuccessfully; @@ -139,16 +137,14 @@ [cheatManager save]; } - [cheatDatabaseController setContent:nil]; [cheatListController setContent:nil]; [self resetSearch:nil]; + [self setCurrentGameCode:nil]; + [self setCurrentGameCRC:0]; [self setCdsCheats:nil]; - NSMutableDictionary *cheatWindowBindings = (NSMutableDictionary *)[cheatWindowController content]; - [cheatWindowBindings setValue:@"No ROM loaded." forKey:@"cheatDBTitle"]; - [cheatWindowBindings setValue:@"No ROM loaded." forKey:@"cheatDBDate"]; - [cheatWindowBindings setValue:@"---" forKey:@"cheatDBItemCount"]; - [cheatWindowBindings setValue:nil forKey:@"cheatWindowDelegateKey"]; + [CheatDatabaseWindowController validateWillAddColumnForAllWindows]; + [CheatDatabaseWindowController validateGameTableFontsForAllWindows]; } - (IBAction) addToList:(id)sender @@ -162,7 +158,6 @@ if (newCheatItem != nil) { [cheatListController setContent:[[self cdsCheats] sessionList]]; - [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"hasItems"]; [[self cdsCheats] save]; } } @@ -202,31 +197,27 @@ [cheatListTable selectRowIndexes:indexSet byExtendingSelection:NO]; } - else - { - [bindings setValue:[NSNumber numberWithBool:NO] forKey:@"hasItems"]; - } } -- (IBAction) viewDatabase:(id)sender +- (IBAction) removeAllFromList:(id)sender { -#if defined(MAC_OS_X_VERSION_10_9) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9) - if ([window respondsToSelector:@selector(beginSheet:completionHandler:)]) + CocoaDSCheatManager *cheatManager = [self cdsCheats]; + if (cheatManager == nil) { - [window beginSheet:cheatDatabaseSheet - completionHandler:^(NSModalResponse response) { - [self didEndCheatDatabaseSheet:nil returnCode:response contextInfo:nil]; - } ]; + return; } - else -#endif + + [cheatListTable deselectAll:sender]; + + NSUInteger itemCount = [[cheatManager sessionList] count]; + + for (NSUInteger i = 0; i < itemCount; i++) { - SILENCE_DEPRECATION_MACOS_10_10( [NSApp beginSheet:cheatDatabaseSheet - modalForWindow:window - modalDelegate:self - didEndSelector:@selector(didEndCheatDatabaseSheet:returnCode:contextInfo:) - contextInfo:nil] ); + [cheatManager removeAtIndex:0]; } + + [cheatListController setContent:[cheatManager sessionList]]; + [cheatManager save]; } - (IBAction) setInternalCheatValue:(id)sender @@ -316,9 +307,9 @@ [cheatSearchListController setContent:[[self cdsCheats] searchResultsList]]; NSInteger searchStyle = [(NSNumber *)[bindings valueForKey:@"cheatSearchStyle"] integerValue]; - if (searchStyle == CHEATSEARCH_SEARCHSTYLE_COMPARATIVE) + if (searchStyle == CheatSearchStyle_Comparative) { - [self setCheatSearchViewByStyle:CHEATSEARCH_SEARCHSTYLE_COMPARATIVE]; + [self setCheatSearchViewByStyle:CheatSearchStyle_Comparative]; } if (!wasSearchAlreadyStarted) @@ -354,15 +345,15 @@ switch (cheatTypeID) { - case CHEAT_TYPE_INTERNAL: + case CheatType_Internal: newView = viewConfigureInternalCheat; break; - case CHEAT_TYPE_ACTION_REPLAY: + case CheatType_ActionReplay: newView = viewConfigureActionReplayCheat; break; - case CHEAT_TYPE_CODE_BREAKER: + case CheatType_CodeBreaker: newView = viewConfigureCodeBreakerCheat; break; @@ -391,11 +382,11 @@ switch (searchStyleID) { - case CHEATSEARCH_SEARCHSTYLE_EXACT_VALUE: + case CheatSearchStyle_ExactValue: newView = viewSearchExactValue; break; - case CHEATSEARCH_SEARCHSTYLE_COMPARATIVE: + case CheatSearchStyle_Comparative: if ([cdsCheats searchDidStart] == 0) { newView = viewSearchComparativeStart; @@ -420,136 +411,6 @@ } } -- (void) databaseLoadFromFile:(NSURL *)fileURL -{ - CocoaDSCheatManager *cheatManager = [self cdsCheats]; - NSMutableDictionary *cheatWindowBindings = (NSMutableDictionary *)[cheatWindowController content]; - - if ( (fileURL == nil) || (cheatManager == nil) || (cheatWindowBindings == nil) ) - { - return; - } - - NSInteger error = 0; - NSMutableArray *dbList = [cheatManager databaseListLoadFromFile:fileURL errorCode:&error]; - if (dbList != nil) - { - [cheatDatabaseController setContent:dbList]; - - NSString *titleString = [cheatManager databaseTitle]; - NSString *dateString = [cheatManager databaseDate]; - - [cheatWindowBindings setValue:titleString forKey:@"cheatDBTitle"]; - [cheatWindowBindings setValue:dateString forKey:@"cheatDBDate"]; - [cheatWindowBindings setValue:[NSString stringWithFormat:@"%ld", (unsigned long)[dbList count]] forKey:@"cheatDBItemCount"]; - } - else - { - [cheatWindowBindings setValue:@"---" forKey:@"cheatDBItemCount"]; - - switch (error) - { - case CHEATEXPORT_ERROR_FILE_NOT_FOUND: - NSLog(@"R4 Cheat Database read failed! Could not load the database file!"); - [cheatWindowBindings setValue:@"Database not loaded." forKey:@"cheatDBTitle"]; - [cheatWindowBindings setValue:@"CANNOT LOAD FILE" forKey:@"cheatDBDate"]; - break; - - case CHEATEXPORT_ERROR_WRONG_FILE_FORMAT: - NSLog(@"R4 Cheat Database read failed! Wrong file format!"); - [cheatWindowBindings setValue:@"Database load error." forKey:@"cheatDBTitle"]; - [cheatWindowBindings setValue:@"FAILED TO LOAD FILE" forKey:@"cheatDBDate"]; - break; - - case CHEATEXPORT_ERROR_SERIAL_NOT_FOUND: - NSLog(@"R4 Cheat Database read failed! Could not find the serial number for this game in the database!"); - [cheatWindowBindings setValue:@"ROM not found in database." forKey:@"cheatDBTitle"]; - [cheatWindowBindings setValue:@"ROM not found." forKey:@"cheatDBDate"]; - break; - - case CHEATEXPORT_ERROR_EXPORT_FAILED: - NSLog(@"R4 Cheat Database read failed! Could not read the database file!"); - [cheatWindowBindings setValue:@"Database read error." forKey:@"cheatDBTitle"]; - [cheatWindowBindings setValue:@"CANNOT READ FILE" forKey:@"cheatDBDate"]; - break; - - default: - break; - } - } -} - -- (void) addSelectedFromCheatDatabase -{ - CocoaDSCheatManager *cheatManager = [self cdsCheats]; - if (cheatManager == nil) - { - return; - } - - const NSInteger addedItemCount = [cheatManager databaseAddSelected]; - if (addedItemCount > 0) - { - [cheatListController setContent:[[self cdsCheats] sessionList]]; - [[self cdsCheats] save]; - [bindings setValue:[NSNumber numberWithBool:YES] forKey:@"hasItems"]; - } -} - -- (IBAction) selectAllCheatsInDatabase:(id)sender -{ - NSMutableArray *dbList = [cheatDatabaseController content]; - if (dbList == nil) - { - return; - } - - for (CocoaDSCheatItem *cheatItem in dbList) - { - [cheatItem setWillAdd:YES]; - } -} - -- (IBAction) selectNoneCheatsInDatabase:(id)sender -{ - NSMutableArray *dbList = [cheatDatabaseController content]; - if (dbList == nil) - { - return; - } - - for (CocoaDSCheatItem *cheatItem in dbList) - { - [cheatItem setWillAdd:NO]; - } -} - -- (IBAction) closeCheatDatabaseSheet:(id)sender -{ - NSWindow *sheet = [(NSControl *)sender window]; - const NSInteger code = [(NSControl *)sender tag]; - - [CocoaDSUtil endSheet:sheet returnCode:code]; -} - -- (void) didEndCheatDatabaseSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo -{ - [sheet orderOut:self]; - - switch (returnCode) - { - case GUI_RESPONSE_CANCEL: - return; - - case GUI_RESPONSE_OK: - [self addSelectedFromCheatDatabase]; - break; - - default: - break; - } -} - - (void)windowDidBecomeKey:(NSNotification *)notification { [cheatWindowController setContent:bindings]; diff --git a/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.h b/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.h index 3bb44c09b..905bc6102 100644 --- a/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.h +++ b/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.h @@ -1,6 +1,6 @@ /* Copyright (C) 2011 Roger Manuel - Copyright (C) 2012-2022 DeSmuME Team + Copyright (C) 2012-2023 DeSmuME Team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,7 +55,6 @@ class OGLImage; NSObjectController *emuController; NSObjectController *prefWindowController; NSObjectController *cheatWindowController; - NSArrayController *cheatDatabaseController; NSToolbarItem *toolbarItemGeneral; NSToolbarItem *toolbarItemInput; @@ -105,7 +104,6 @@ class OGLImage; @property (readonly) IBOutlet NSObjectController *emuController; @property (readonly) IBOutlet NSObjectController *prefWindowController; @property (readonly) IBOutlet NSObjectController *cheatWindowController; -@property (readonly) IBOutlet NSArrayController *cheatDatabaseController; @property (readonly) IBOutlet NSToolbarItem *toolbarItemGeneral; @property (readonly) IBOutlet NSToolbarItem *toolbarItemInput; @property (readonly) IBOutlet NSToolbarItem *toolbarItemDisplay; @@ -139,8 +137,6 @@ class OGLImage; - (void) chooseAdvansceneDatabaseDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; - (IBAction) chooseRomForAutoload:(id)sender; - (void) chooseRomForAutoloadDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; -- (IBAction) chooseCheatDatabase:(id)sender; -- (void) chooseCheatDatabaseDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; - (IBAction) selectDisplayRotation:(id)sender; - (void) updateDisplayRotationMenu:(double)displayRotation; diff --git a/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.mm b/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.mm index 76a3b4c8a..3aef05d33 100644 --- a/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/preferencesWindowDelegate.mm @@ -36,7 +36,6 @@ #endif -#pragma mark - @implementation DisplayPreviewView @dynamic filtersPreferGPU; @@ -294,7 +293,6 @@ @synthesize emuController; @synthesize prefWindowController; @synthesize cheatWindowController; -@synthesize cheatDatabaseController; @synthesize toolbarItemGeneral; @synthesize toolbarItemInput; @@ -525,70 +523,6 @@ [bindings setValue:[selectedFile lastPathComponent] forKey:@"AdvansceneDatabaseName"]; } -- (IBAction) chooseCheatDatabase:(id)sender -{ - NSOpenPanel *panel = [NSOpenPanel openPanel]; - [panel setCanChooseDirectories:NO]; - [panel setCanChooseFiles:YES]; - [panel setResolvesAliases:YES]; - [panel setAllowsMultipleSelection:NO]; - [panel setTitle:NSSTRING_TITLE_SELECT_R4_CHEAT_DB_PANEL]; - NSArray *fileTypes = [NSArray arrayWithObjects:@FILE_EXT_R4_CHEAT_DB, nil]; - - // The NSOpenPanel/NSSavePanel method -(void)beginSheetForDirectory:file:types:modalForWindow:modalDelegate:didEndSelector:contextInfo - // is deprecated in Mac OS X v10.6. -#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 - if (IsOSXVersionSupported(10, 6, 0)) - { - [panel setAllowedFileTypes:fileTypes]; - [panel beginSheetModalForWindow:window - completionHandler:^(NSInteger result) { - [self chooseCheatDatabaseDidEnd:panel returnCode:(int)result contextInfo:nil]; - } ]; - } - else -#endif - { - SILENCE_DEPRECATION_MACOS_10_6( [panel beginSheetForDirectory:nil - file:nil - types:fileTypes - modalForWindow:window - modalDelegate:self - didEndSelector:@selector(chooseCheatDatabaseDidEnd:returnCode:contextInfo:) - contextInfo:nil] ); - } -} - -- (void) chooseCheatDatabaseDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo -{ - [sheet orderOut:self]; - - if (returnCode == GUI_RESPONSE_CANCEL) - { - return; - } - - NSURL *selectedFileURL = [[sheet URLs] lastObject]; //hopefully also the first object - if(selectedFileURL == nil) - { - return; - } - - NSString *selectedFile = [selectedFileURL path]; - - [[NSUserDefaults standardUserDefaults] setObject:selectedFile forKey:@"R4Cheat_DatabasePath"]; - [bindings setValue:[selectedFile lastPathComponent] forKey:@"R4CheatDatabaseName"]; - - const BOOL isRomLoaded = [(EmuControllerDelegate *)[emuController content] currentRom] != nil; - NSMutableDictionary *cheatWindowBindings = (NSMutableDictionary *)[cheatWindowController content]; - CheatWindowDelegate *cheatWindowDelegate = (CheatWindowDelegate *)[cheatWindowBindings valueForKey:@"cheatWindowDelegateKey"]; - - if ( (isRomLoaded == YES) && (cheatWindowDelegate != nil) ) - { - [cheatWindowDelegate databaseLoadFromFile:selectedFileURL]; - } -} - - (IBAction) selectDisplayRotation:(id)sender { const NSInteger displayRotation = [(NSMenuItem *)sender tag]; @@ -1078,12 +1012,6 @@ [bindings setValue:[advansceneDatabasePath lastPathComponent] forKey:@"AdvansceneDatabaseName"]; } - NSString *cheatDatabasePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"R4Cheat_DatabasePath"]; - if (cheatDatabasePath != nil) - { - [bindings setValue:[cheatDatabasePath lastPathComponent] forKey:@"R4CheatDatabaseName"]; - } - NSString *autoloadRomPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"General_AutoloadROMSelectedPath"]; if (autoloadRomPath != nil) { diff --git a/desmume/src/frontend/windows/cheatsWin.cpp b/desmume/src/frontend/windows/cheatsWin.cpp index dc975a2d2..c7494cc72 100755 --- a/desmume/src/frontend/windows/cheatsWin.cpp +++ b/desmume/src/frontend/windows/cheatsWin.cpp @@ -1639,19 +1639,31 @@ bool CheatsExportDialog(HWND hwnd) else { char buf2[512] = {0}; - if (cheatsExport->getErrorCode() == 1) - sprintf(buf2, "Error loading cheats database. File not found\n\"%s\"\nCheck your path (Menu->Config->Path Settings->\"Cheats\")\n\nYou can download it from http://www.codemasters-project.net/vb/forumdisplay.php?44-Nintendo-DS", buf); - else - if (cheatsExport->getErrorCode() == 2) + CheatSystemError theError = cheatsExport->getErrorCode(); + + switch (theError) + { + case CheatSystemError_FileOpenFailed: + sprintf(buf2, "Error loading cheats database. File not found\n\"%s\"\nCheck your path (Menu->Config->Path Settings->\"Cheats\")\n\nYou can download it from http://www.codemasters-project.net/vb/forumdisplay.php?44-Nintendo-DS", buf); + break; + + case CheatSystemError_FileFormatInvalid: sprintf(buf2, "File \"%s\" is not R4 cheats database.\nWrong file format!", buf); - else - if (cheatsExport->getErrorCode() == 3) - sprintf(buf2, "CRC %8X not found in database.", gameInfo.crcForCheatsDb); - else - if (cheatsExport->getErrorCode() == 4) - sprintf(buf2, "Error export from database"); - else - sprintf(buf2, "Unknown error!!!"); + break; + + case CheatSystemError_GameNotFound: + sprintf(buf2, "CRC %8X not found in database.", gameInfo.crcForCheatsDb); + break; + + case CheatSystemError_LoadEntryError: + sprintf(buf2, "Error export from database"); + break; + + default: + sprintf(buf2, "Unknown error!!!"); + break; + } + MessageBox(hwnd, buf2, "DeSmuME", MB_OK | MB_ICONERROR); } From 586c7ee199029909302f526e1b51c0d4dcd54786 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 1 Aug 2023 10:03:48 -0700 Subject: [PATCH 08/49] Cocoa Port: In the cheat database viewer, make the current game entry's font slightly larger to further differentiate it from the other games. --- .../cocoa/userinterface/CheatDatabaseWindowController.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm index b38cb6c89..b6fd6de68 100644 --- a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm +++ b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm @@ -747,7 +747,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; if ( (cellString != nil) && (row == currentGameTableRowIndex) ) { - [cell setFont:[NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]]]; + [cell setFont:[NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize] + 1.0f]]; } else { From 35976edb5f6a5d8db258e3ee3f8e14b1aae93509 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 1 Aug 2023 15:18:44 -0700 Subject: [PATCH 09/49] Cocoa Port: Conversions between Internal cheats and Action Replay cheats now respect the value length. --- desmume/src/frontend/cocoa/cocoa_cheat.mm | 73 +++++++++++++++++++---- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/desmume/src/frontend/cocoa/cocoa_cheat.mm b/desmume/src/frontend/cocoa/cocoa_cheat.mm index 31fbb83b3..c2ea5755d 100644 --- a/desmume/src/frontend/cocoa/cocoa_cheat.mm +++ b/desmume/src/frontend/cocoa/cocoa_cheat.mm @@ -571,15 +571,18 @@ void ClientCheatItem::_ConvertInternalToActionReplay() { char workingCodeBuffer[16+1+1]; + u32 function = this->_address & 0x0FFFFFFF; u32 truncatedValue = this->_value; switch (this->_valueLength) { case 1: + function |= 0x20000000; truncatedValue &= 0x000000FF; break; case 2: + function |= 0x10000000; truncatedValue &= 0x0000FFFF; break; @@ -592,11 +595,11 @@ void ClientCheatItem::_ConvertInternalToActionReplay() } memset(workingCodeBuffer, 0, sizeof(workingCodeBuffer)); - snprintf(workingCodeBuffer, 16+1+1, "%08X %08X", this->_address, truncatedValue); + snprintf(workingCodeBuffer, 16+1+1, "%08X %08X", function, truncatedValue); this->_rawCodeString = workingCodeBuffer; memset(workingCodeBuffer, 0, sizeof(workingCodeBuffer)); - snprintf(workingCodeBuffer, 16+1, "%08X%08X", this->_address, truncatedValue); + snprintf(workingCodeBuffer, 16+1, "%08X%08X", function, truncatedValue); this->_cleanCodeString = workingCodeBuffer; this->_codeCount = 1; @@ -604,18 +607,68 @@ void ClientCheatItem::_ConvertInternalToActionReplay() void ClientCheatItem::_ConvertActionReplayToInternal() { - this->_addressString[0] = '0'; - this->_addressString[1] = 'x'; - strncpy(this->_addressString + 2, this->_cleanCodeString.c_str(), 8); - this->_addressString[10] = '\0'; - sscanf(this->_addressString + 2, "%x", &this->_address); + char workingCodeBuffer[11] = {0}; + size_t cleanCodeLength = this->_cleanCodeString.length(); + size_t i = 0; + + // Note that we're only searching for the first valid command for + // a constant RAM write, since internal cheats can only support a + // single constant RAM write. + for (; i < cleanCodeLength; i+=16) + { + workingCodeBuffer[0] = '0'; + workingCodeBuffer[1] = 'x'; + strncpy(workingCodeBuffer + 2, this->_cleanCodeString.c_str() + i, 8); + workingCodeBuffer[10] = '\0'; + + if (workingCodeBuffer[2] == '2') + { + this->_valueLength = 1; + workingCodeBuffer[2] = '0'; + break; + } + else if (workingCodeBuffer[2] == '1') + { + this->_valueLength = 2; + workingCodeBuffer[2] = '0'; + break; + } + else if (workingCodeBuffer[2] == '0') + { + this->_valueLength = 4; + break; + } + else + { + continue; + } + } + + if (i >= cleanCodeLength) + { + return; + } + + strncpy(this->_addressString, workingCodeBuffer, sizeof(this->_addressString)); + sscanf(workingCodeBuffer + 2, "%x", &this->_address); - char workingCodeBuffer[9]; memset(workingCodeBuffer, 0, sizeof(workingCodeBuffer)); - strncpy(workingCodeBuffer, this->_cleanCodeString.c_str() + 8, 8); + strncpy(workingCodeBuffer, this->_cleanCodeString.c_str() + i + 8, 8); sscanf(workingCodeBuffer, "%x", &this->_value); - this->_valueLength = 4; + switch (this->_valueLength) + { + case 1: + this->_value &= 0x000000FF; + break; + + case 2: + this->_value &= 0x0000FFFF; + break; + + default: + break; + } } void ClientCheatItem::ClientToDesmumeCheatItem(CHEATS_LIST *outCheatItem) const From 6c5941689f6221c4896afd942f5e1e08cc109145 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 2 Aug 2023 10:51:00 -0700 Subject: [PATCH 10/49] Cocoa Port: In the Cheat Manager, the "Remove All Cheats" button has been moved into an Actions pop-up menu. - This change is to help avoid misclicks on the button that may instantly wipe out the user's cheat list. - The new Actions pop-up menu also exists to incorporate some new cheat list operations that will be coming very soon. --- .../translations/English.lproj/MainMenu.xib | 294 ++++++++++++------ 1 file changed, 201 insertions(+), 93 deletions(-) diff --git a/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib b/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib index d4e4698f4..03537b54a 100644 --- a/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib +++ b/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib @@ -18702,27 +18702,62 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 28682 100 - + 289 - {{140, 13}, {158, 32}} + {{185, 16}, {110, 26}} - _NS:610 YES - - 67108864 - 134217728 - Remove All Cheats + + -2076180416 + 2048 - _NS:610 - - -2038284288 + + 109199360 129 - 200 - 25 + 400 + 75 + + + YES + Actions + + 1048576 + 2147483647 + 1 + + + + _popUpItemAction: + + + YES + + CheatManagerActions + + + + + Remove All Cheats + + 2147483647 + + + _popUpItemAction: + + + + + + 1 + YES + 1 + YES + YES + 2 NO @@ -20217,7 +20252,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {1.7976931348623157e+308, 1.7976931348623157e+308} - + 256 @@ -20233,6 +20268,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{18, 152}, {230, 98}} + YES NO 5 @@ -20513,6 +20549,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 93}, {236, 42}} + YES 67108864 @@ -20531,6 +20568,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{49, 16}, {168, 32}} + YES 67108864 @@ -20552,6 +20590,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{49, 48}, {168, 32}} + YES 67108864 @@ -20573,6 +20612,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 12 {{14, 141}, {238, 5}} + {0, 0} 67108864 @@ -20590,10 +20630,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {266, 260}} + {{17, 16}, {268, 276}} + {0, 0} 67108864 @@ -20633,6 +20675,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{14, 16}, {30, 30}} + YES 134217728 @@ -20651,6 +20694,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 265 {{52, 18}, {154, 28}} + YES 69206017 @@ -20669,6 +20713,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{11, 14}, {32, 32}} + 28682 100 @@ -20677,6 +20722,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{205, 17}, {116, 26}} + YES -2076180416 @@ -21039,10 +21085,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {334, 56}} + {{287, 220}, {336, 72}} + {0, 0} 67108864 @@ -21071,6 +21119,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{14, 14}, {304, 42}} + YES 69206017 @@ -21088,10 +21137,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {334, 66}} + {{287, 16}, {336, 82}} + {0, 0} 67108864 @@ -21120,6 +21171,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{226, 6}, {96, 32}} + YES 67108864 @@ -21141,6 +21193,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{18, 45}, {298, 18}} + YES 77594689 @@ -21161,6 +21214,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 71}, {150, 17}} + YES 68157504 @@ -21177,10 +21231,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {334, 98}} + {{287, 102}, {336, 114}} + {0, 0} 67108864 @@ -21198,6 +21254,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {640, 303} + + {{0, 0}, {1920, 1177}} {1.7976931348623157e+308, 1.7976931348623157e+308} @@ -21215,7 +21273,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {1.7976931348623157e+308, 1.7976931348623157e+308} - + 256 @@ -21231,6 +21289,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 256 {188, 304} + YES NO YES @@ -21239,13 +21298,13 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 256 {188, 17} + - - + + -2147483392 {{224, 0}, {16, 17}} - @@ -21295,6 +21354,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 17}, {188, 304}} + @@ -21308,6 +21368,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 0}, {188, 17}} + @@ -21316,6 +21377,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 -2147483392 {{224, 17}, {15, 102}} + NO _doScroller: @@ -21326,16 +21388,17 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 -2147483392 {{1, 306}, {188.95699999999999, 15}} + NO 1 _doScroller: 0.9943820224719101 - {{20, 106}, {190, 322}} + 133682 @@ -21360,15 +21423,18 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{3, 4}, {400, 320}} + NSView {{1, 1}, {406, 326}} + {{215, 102}, {408, 328}} + {0, 0} 67108864 @@ -21389,6 +21455,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{530, 12}, {96, 32}} + YES 67108864 @@ -21418,6 +21485,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 14}, {482, 42}} + YES 69206017 @@ -21435,10 +21503,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {512, 66}} + {{17, 16}, {514, 82}} + {0, 0} 67108864 @@ -21456,6 +21526,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {640, 448} + + {{0, 0}, {1920, 1177}} {1.7976931348623157e+308, 1.7976931348623157e+308} @@ -58755,34 +58827,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 12300 - - - enabled: selection.currentRom - - - - - - enabled: selection.currentRom - enabled - selection.currentRom - - NSValueTransformerName - NSIsNotNil - - 2 - - - 12385 - - - - removeAllFromList: - - - - 12386 - openCheatDatabaseFile: @@ -58807,6 +58851,34 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 12400 + + + enabled: selection.currentRom + + + + + + enabled: selection.currentRom + enabled + selection.currentRom + + NSValueTransformerName + NSIsNotNil + + 2 + + + 12459 + + + + removeAllFromList: + + + + 12460 + @@ -60564,7 +60636,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - + @@ -80122,19 +80194,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - - 12382 - - - - - - - - 12383 - - - 12392 @@ -80166,6 +80225,41 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 + + 12401 + + + + + + + + 12402 + + + + + + + + 12403 + + + + + + + + + 12409 + + + + + 12412 + + + @@ -82968,8 +83062,6 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 Aggressively smooths the sound, eliminating the harsh sounding harmonics and noise. However, some sound detail is lost. Negligible CPU usage. - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -82977,6 +83069,15 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDMwAAwiAAAA + + com.apple.InterfaceBuilder.CocoaPlugin + {{647, 375}, {193, 43}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin {{903, 773}, {143, 23}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85271,9 +85372,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{329, 553}, {640, 303}} + {{42, 553}, {640, 303}} com.apple.InterfaceBuilder.CocoaPlugin - {{329, 553}, {640, 303}} + {{42, 553}, {640, 303}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -85356,6 +85457,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 P4AAAL+AAABBMAAAwjAAAA com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDTQAAwiQAAA + com.apple.InterfaceBuilder.CocoaPlugin {{811, 710}, {218, 223}} com.apple.InterfaceBuilder.CocoaPlugin @@ -85380,6 +85484,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABClgAAw+UAAA + com.apple.InterfaceBuilder.CocoaPlugin P4AAAL+AAABB6AAAw+CAAA @@ -85531,8 +85638,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + {{0, 386}, {640, 448}} com.apple.InterfaceBuilder.CocoaPlugin - {{509, 91}, {640, 448}} + {{0, 386}, {640, 448}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -86291,7 +86399,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - 12400 + 12460 @@ -86649,7 +86757,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 DisplayPreviewView NSView - + IBProjectSource userinterface/preferencesWindowDelegate.h @@ -87930,12 +88038,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSWindow - + RomInfoContentView NSView - + IBProjectSource userinterface/RomInfoPanel.h @@ -87983,7 +88091,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 RomInfoPanelSectionView - + RomInfoPanelSectionView @@ -88002,7 +88110,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSTextField - + Slot2WindowDelegate @@ -88275,21 +88383,21 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSApplication NSResponder - + IBFrameworkSource AppKit.framework/Headers/NSApplication.h NSApplication - + IBFrameworkSource AppKit.framework/Headers/NSApplicationScripting.h NSApplication - + IBFrameworkSource AppKit.framework/Headers/NSColorPanel.h @@ -88374,7 +88482,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSControl NSView - + IBFrameworkSource AppKit.framework/Headers/NSControl.h @@ -88438,7 +88546,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSDrawer NSResponder - + IBFrameworkSource AppKit.framework/Headers/NSDrawer.h @@ -88494,7 +88602,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSMenu NSObject - + IBFrameworkSource AppKit.framework/Headers/NSMenu.h @@ -88502,7 +88610,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSMenuItem NSObject - + IBFrameworkSource AppKit.framework/Headers/NSMenuItem.h @@ -88540,19 +88648,19 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSObject - + NSObject - + NSObject - + NSObject - + NSObject @@ -88591,7 +88699,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSObject - + NSObject @@ -88602,7 +88710,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSObject - + IBFrameworkSource AppKit.framework/Headers/NSOutlineView.h @@ -88623,21 +88731,21 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSObject - + IBFrameworkSource AppKit.framework/Headers/NSTableView.h NSObject - + IBFrameworkSource AppKit.framework/Headers/NSToolbarItem.h NSObject - + IBFrameworkSource AppKit.framework/Headers/NSView.h @@ -88807,7 +88915,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSOutlineView NSTableView - + NSPanel @@ -88979,7 +89087,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSTableView NSControl - + NSText @@ -89024,7 +89132,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSToolbarItem NSObject - + NSTreeController @@ -89051,7 +89159,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSView - + NSView @@ -89063,11 +89171,11 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSView NSResponder - + NSWindow - + NSWindow From 751ab0255b3439846181262a100232ceabc35aff Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 2 Aug 2023 10:53:58 -0700 Subject: [PATCH 11/49] Cocoa Port: The Cheat Database Viewer now displays the current game's serial and CRC to help users verify the existence of a game in the database file. --- .../English.lproj/CheatDatabaseViewer.xib | 999 ++++++------------ .../CheatDatabaseWindowController.h | 8 +- .../CheatDatabaseWindowController.mm | 114 +- .../userinterface/cheatWindowDelegate.mm | 6 +- 4 files changed, 388 insertions(+), 739 deletions(-) diff --git a/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib b/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib index f4df17c48..bca64a637 100644 --- a/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib +++ b/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib @@ -56,7 +56,7 @@ 268 - {{17, 452}, {60, 14}} + {{17, 453}, {60, 14}} YES @@ -166,7 +166,7 @@ 265 - {{429, 414}, {103, 14}} + {{429, 412}, {103, 14}} YES @@ -185,7 +185,7 @@ 266 - {{82, 451}, {444, 16}} + {{82, 452}, {444, 16}} YES @@ -209,7 +209,7 @@ 265 - {{534, 414}, {89, 14}} + {{534, 412}, {89, 14}} YES @@ -229,7 +229,7 @@ 265 - {{449, 397}, {83, 14}} + {{449, 394}, {83, 14}} YES @@ -251,7 +251,7 @@ YES - {{534, 397}, {89, 14}} + {{534, 394}, {89, 14}} YES @@ -335,7 +335,7 @@ 265 - {{434, 431}, {98, 14}} + {{434, 430}, {98, 14}} YES @@ -351,19 +351,101 @@ NO 1 - + 268 - {{17, 422}, {90, 14}} + {{17, 414}, {90, 14}} YES - + 68157504 4326400 Game Search: - + + + + + NO + 1 + + + + 265 + {{303, 412}, {36, 14}} + + + YES + + 68157504 + 71435264 + CRC: + + LucidaGrande-Bold + 11 + 16 + + + + + + NO + 1 + + + + 265 + {{294, 430}, {45, 14}} + + + YES + + 68157504 + 71435264 + Serial: + + + + + + NO + 1 + + + + 265 + {{340, 412}, {83, 14}} + + + YES + + 70254657 + 4330496 + + + CRC + + + + + NO + 1 + + + + 265 + {{340, 430}, {83, 14}} + + + YES + + 70254657 + 4330496 + + + gameCode + @@ -373,7 +455,7 @@ 265 - {{534, 431}, {89, 14}} + {{534, 430}, {89, 14}} YES @@ -393,7 +475,7 @@ 265 - {{529, 444}, {96, 28}} + {{529, 445}, {96, 28}} _NS:610 @@ -453,7 +535,7 @@ 269 - {{304, 35.5}, {32, 32}} + {{304, 33}, {32, 32}} _NS:4186 @@ -473,7 +555,7 @@ 256 - {638, 87} + {638, 84.5} _NS:1843 @@ -590,7 +672,7 @@ - 361 + 347 70 10000 @@ -648,8 +730,8 @@ - 70 - 70 + 80 + 80 3.4028234663852886e+38 75497536 @@ -677,8 +759,8 @@ - 86 - 86 + 90 + 90 3.4028234663852886e+38 75497536 @@ -730,7 +812,7 @@ 1 - {{1, 17}, {638, 87}} + {{1, 17}, {638, 84.5}} _NS:1841 @@ -779,7 +861,7 @@ 4 - {640, 105} + {640, 102.5} _NS:1839 @@ -794,7 +876,7 @@ 1 - {640, 105} + {640, 102.5} _NS:1030 @@ -818,7 +900,7 @@ 256 - {638, 214} + {638, 208.5} _NS:1718 @@ -976,7 +1058,7 @@ - {{1, 17}, {638, 214}} + {{1, 17}, {638, 208.5}} _NS:1716 @@ -1025,7 +1107,7 @@ 4 - {640, 232} + {640, 226.5} _NS:1714 @@ -1040,14 +1122,14 @@ 1 - {{0, 115}, {640, 233}} + {{0, 112.5}, {640, 227.5}} _NS:1033 NSView - {{0, 41}, {640, 348}} + {{0, 41}, {640, 340}} _NS:1028 @@ -1060,7 +1142,7 @@ YES - {{20, 397}, {265, 22}} + {{20, 389}, {265, 22}} _NS:845 @@ -1129,21 +1211,21 @@ NO 1 - + 265 - {{288, 393}, {136, 28}} + {{289, 385}, {136, 28}} _NS:610 YES - + 67108864 134348800 Select Current Game _NS:610 - + -2038284288 129 @@ -1330,7 +1412,7 @@ 69206017 272633856 - + LucidaGrande-Bold 13 16 @@ -1397,7 +1479,7 @@ NO - + 268 {{17, 148}, {446, 17}} @@ -1405,21 +1487,21 @@ _NS:4068 YES - + 70254657 272634880 - + Major String _NS:4068 - + NO 1 - + 268 {{17, 44}, {446, 96}} @@ -1427,14 +1509,14 @@ _NS:4068 YES - + 69206017 272764928 Minor String _NS:4068 - + @@ -1964,17 +2046,17 @@ selectCurrentGame: - + 196 enabled: isCurrentGameFound - + - + enabled: isCurrentGameFound enabled @@ -1989,7 +2071,7 @@ enabled: isCurrentGameFound - + enabled: isCurrentGameFound @@ -2005,7 +2087,7 @@ enabled: isCurrentGameFound - + enabled: isCurrentGameFound @@ -2021,7 +2103,7 @@ enabled: isCurrentGameFound - + enabled: isCurrentGameFound @@ -2060,7 +2142,7 @@ - + 2 @@ -2094,7 +2176,7 @@ - + 2 @@ -2128,7 +2210,7 @@ - + 2 @@ -2153,10 +2235,10 @@ value: errorMajorString - + - + value: errorMajorString value @@ -2169,10 +2251,10 @@ value: errorMajorString - + - + value: errorMajorString value @@ -2185,10 +2267,10 @@ value: errorMinorString - + - + value: errorMinorString value @@ -2203,7 +2285,7 @@ predicate: filterPredicate - + predicate: filterPredicate @@ -2232,7 +2314,7 @@ predicate2: filterPredicate - + predicate2: filterPredicate @@ -2251,7 +2333,7 @@ serial CONTAINS[cd] $value - + 2 @@ -2281,12 +2363,52 @@ crcString CONTAINS[cd] $value - + 2 222 + + + selectCurrentGameButton + + + + 229 + + + + value: currentGameSerial + + + + + + value: currentGameSerial + value + currentGameSerial + 2 + + + 238 + + + + value: currentGameCRCString + + + + + + value: currentGameCRCString + value + currentGameCRCString + 2 + + + 241 + @@ -2344,8 +2466,12 @@ - - + + + + + + @@ -2548,9 +2674,9 @@ YES - + - + @@ -2907,59 +3033,115 @@ 187 - + YES - + 188 - - + + 190 - + YES - + 191 - - + + 210 - + YES - + 211 - - + + 213 - + YES - + 214 - - + + + + + 230 + + + YES + + + + + + 231 + + + + + 232 + + + YES + + + + + + 233 + + + + + 234 + + + YES + + + + + + 235 + + + YES + + + + + + 236 + + + + + 237 + + @@ -3015,6 +3197,18 @@ 214.IBPluginDependency 22.IBPluginDependency 23.IBPluginDependency + 230.IBPluginDependency + 230.IBViewBoundsToFrameTransform + 231.IBPluginDependency + 232.IBPluginDependency + 232.IBViewBoundsToFrameTransform + 233.IBPluginDependency + 234.IBPluginDependency + 234.IBViewBoundsToFrameTransform + 235.IBPluginDependency + 235.IBViewBoundsToFrameTransform + 236.IBPluginDependency + 237.IBPluginDependency 25.IBPluginDependency 26.IBPluginDependency 27.IBPluginDependency @@ -3137,7 +3331,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - P4AAAL+AAABD2gAAw9sAAA + P4AAAL+AAABBiAAAw9kAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3160,6 +3354,26 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDlYAAw9YAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDkQAAw90AAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDhgAAw9eAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDkQAAw92AAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3285,10 +3499,10 @@ - 228 + 241 - + YES CheatDatabaseWindowController @@ -3362,6 +3576,7 @@ errorSheet gameListController gameTable + selectCurrentGameButton splitView @@ -3371,6 +3586,7 @@ NSWindow NSArrayController NSTableView + NSButton NSSplitView @@ -3383,6 +3599,7 @@ errorSheet gameListController gameTable + selectCurrentGameButton splitView @@ -3407,6 +3624,10 @@ gameTable NSTableView + + selectCurrentGameButton + NSButton + splitView NSSplitView @@ -3414,616 +3635,8 @@ - IBProjectSource - userinterface/CheatDatabaseWindowController.h - - - - - YES - - NSActionCell - NSCell - - IBFrameworkSource - AppKit.framework/Headers/NSActionCell.h - - - - NSApplication - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSApplication.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSApplicationScripting.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSColorPanel.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSHelpManager.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSPageLayout.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSUserInterfaceItemSearching.h - - - - NSArrayController - NSObjectController - - IBFrameworkSource - AppKit.framework/Headers/NSArrayController.h - - - - NSButton - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSButton.h - - - - NSButtonCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSButtonCell.h - - - - NSCell - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSCell.h - - - - NSControl - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSControl.h - - - - NSController - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSController.h - - - - NSDrawer - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSDrawer.h - - - - NSFormatter - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFormatter.h - - - - NSImageCell - NSCell - - IBFrameworkSource - AppKit.framework/Headers/NSImageCell.h - - - - NSMenu - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSMenu.h - - - - NSNumberFormatter - NSFormatter - - IBFrameworkSource - Foundation.framework/Headers/NSNumberFormatter.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSAccessibility.h - - - - NSObject - - - - NSObject - - - - NSObject - - - - NSObject - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSDictionaryController.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSDragging.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSFontManager.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSFontPanel.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSKeyValueBinding.h - - - - NSObject - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSNibLoading.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSOutlineView.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSPasteboard.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSSavePanel.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSTableView.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSToolbarItem.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSView.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSClassDescription.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSError.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFileManager.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueObserving.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyedArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObject.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObjectScripting.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSPortCoder.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSRunLoop.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptClassDescription.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptObjectSpecifiers.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptWhoseTests.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSThread.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURL.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLConnection.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLDownload.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CAAnimation.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CALayer.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CIImageProvider.h - - - - NSObjectController - NSController - - IBFrameworkSource - AppKit.framework/Headers/NSObjectController.h - - - - NSOutlineView - NSTableView - - - - NSProgressIndicator - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSProgressIndicator.h - - - - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSInterfaceStyle.h - - - - NSResponder - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSResponder.h - - - - NSScrollView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSScrollView.h - - - - NSScroller - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSScroller.h - - - - NSSearchField - NSTextField - - IBFrameworkSource - AppKit.framework/Headers/NSSearchField.h - - - - NSSearchFieldCell - NSTextFieldCell - - IBFrameworkSource - AppKit.framework/Headers/NSSearchFieldCell.h - - - - NSSplitView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSSplitView.h - - - - NSTableColumn - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSTableColumn.h - - - - NSTableHeaderView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSTableHeaderView.h - - - - NSTableView - NSControl - - - - NSText - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSText.h - - - - NSTextField - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSTextField.h - - - - NSTextFieldCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSTextFieldCell.h - - - - NSTextView - NSText - - IBFrameworkSource - AppKit.framework/Headers/NSTextView.h - - - - NSTreeController - NSObjectController - - IBFrameworkSource - AppKit.framework/Headers/NSTreeController.h - - - - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSClipView.h - - - - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSMenuItem.h - - - - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSRulerView.h - - - - NSView - NSResponder - - - - NSWindow - - - - NSWindow - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSWindow.h - - - - NSWindow - - IBFrameworkSource - AppKit.framework/Headers/NSWindowScripting.h - - - - NSWindowController - NSResponder - - showWindow: - id - - - showWindow: - - showWindow: - id - - - - IBFrameworkSource - AppKit.framework/Headers/NSWindowController.h + IBDocumentRelativeSource + ../../userinterface/CheatDatabaseWindowController.h diff --git a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h index 95bd72cdc..e8f1622a4 100644 --- a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h +++ b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h @@ -46,6 +46,8 @@ BOOL isSelectedGameTheCurrentGame; NSInteger currentGameTableRowIndex; NSString *currentGameIndexString; + NSString *currentGameSerial; + NSUInteger currentGameCRC; NSString *errorMajorString; NSString *errorMinorString; @@ -71,6 +73,9 @@ @property (assign) BOOL isFileLoading; @property (assign) BOOL isCurrentGameFound; @property (assign) BOOL isSelectedGameTheCurrentGame; +@property (retain, nonatomic) NSString *currentGameSerial; +@property (assign, nonatomic) NSUInteger currentGameCRC; +@property (readonly, nonatomic) NSString *currentGameCRCString; @property (assign) NSString *errorMajorString; @property (assign) NSString *errorMinorString; @@ -80,10 +85,9 @@ - (void) loadFileOnThread:(id)object; - (void) loadFileDidFinish:(NSNotification *)aNotification; - (void) updateWindow; ++ (void) setCurrentGameForAllWindowsSerial:(NSString *)serialString crc:(NSUInteger)crc; - (void) validateGameTableFonts; -+ (void) validateGameTableFontsForAllWindows; - (BOOL) validateWillAddColumn; -+ (void) validateWillAddColumnForAllWindows; - (void) showErrorSheet:(NSInteger)errorCode; - (void) didEndErrorSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo; diff --git a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm index b6fd6de68..2ec9cb352 100644 --- a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm +++ b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm @@ -43,6 +43,9 @@ NSMutableArray *cheatDatabaseWindowList = nil; @synthesize isFileLoading; @synthesize isCurrentGameFound; @synthesize isSelectedGameTheCurrentGame; +@dynamic currentGameSerial; +@synthesize currentGameCRC; +@dynamic currentGameCRCString; @synthesize errorMajorString; @synthesize errorMinorString; @@ -66,6 +69,8 @@ NSMutableArray *cheatDatabaseWindowList = nil; isSelectedGameTheCurrentGame = NO; currentGameIndexString = [[NSString alloc] initWithString:@"NSNotFound"]; currentGameTableRowIndex = NSNotFound; + currentGameSerial = nil; + currentGameCRC = 0; errorMajorString = @"No error has occurred!"; errorMinorString = @"This is just a placeholder message for initialization purposes."; @@ -261,10 +266,34 @@ NSMutableArray *cheatDatabaseWindowList = nil; [gameTable deselectAll:nil]; [gameTable selectRowIndexes:selectedRows byExtendingSelection:NO]; + CheatWindowDelegate *delegate = [self cheatManagerDelegate]; + CocoaDSCheatManager *cheatManager = [delegate cdsCheats]; + [self setCurrentGameSerial:[cheatManager currentGameCode]]; + [self setCurrentGameCRC:[cheatManager currentGameCRC]]; + [self validateGameTableFonts]; [self selectCurrentGame:nil]; } ++ (void) setCurrentGameForAllWindowsSerial:(NSString *)serialString crc:(NSUInteger)crc +{ + if (cheatDatabaseWindowList == nil) + { + return; + } + + for (CheatDatabaseWindowController *windowController in cheatDatabaseWindowList) + { + [windowController setCurrentGameSerial:serialString]; + [windowController setCurrentGameCRC:crc]; + + [windowController validateGameTableFonts]; + [[windowController gameTable] setNeedsDisplay]; + + [windowController validateWillAddColumn]; + } +} + - (void) validateGameTableFonts { CheatWindowDelegate *delegate = [self cheatManagerDelegate]; @@ -279,12 +308,9 @@ NSMutableArray *cheatDatabaseWindowList = nil; return; } - NSString *currentGameCode = [cheatManager currentGameCode]; - const NSUInteger currentGameCRC = [cheatManager currentGameCRC]; - for (CocoaDSCheatDBGame *game in [gameListController content]) { - if ( ([game crc] == currentGameCRC) && ([[game serial] isEqualToString:currentGameCode]) ) + if ( ([game crc] == [self currentGameCRC]) && ([[game serial] isEqualToString:[self currentGameSerial]]) ) { [currentGameIndexString release]; currentGameIndexString = [[NSString alloc] initWithFormat:@"%llu", (unsigned long long)[game index]]; @@ -294,20 +320,6 @@ NSMutableArray *cheatDatabaseWindowList = nil; } } -+ (void) validateGameTableFontsForAllWindows -{ - if (cheatDatabaseWindowList == nil) - { - return; - } - - for (CheatDatabaseWindowController *windowController in cheatDatabaseWindowList) - { - [windowController validateGameTableFonts]; - [[windowController gameTable] setNeedsDisplay]; - } -} - - (BOOL) validateWillAddColumn { BOOL showWillAddColumn = NO; @@ -325,7 +337,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; if ( (delegate != nil) && (cheatManager != nil) && ([selectedGame serial] != nil) ) { - showWillAddColumn = ([[selectedGame serial] isEqualToString:[cheatManager currentGameCode]]) && ([selectedGame crc] == [cheatManager currentGameCRC]); + showWillAddColumn = ([[selectedGame serial] isEqualToString:currentGameSerial]) && ([selectedGame crc] == currentGameCRC); } NSTableColumn *willAddColumn = [entryOutline tableColumnWithIdentifier:@"willAdd"]; @@ -336,19 +348,6 @@ NSMutableArray *cheatDatabaseWindowList = nil; return showWillAddColumn; } -+ (void) validateWillAddColumnForAllWindows -{ - if (cheatDatabaseWindowList == nil) - { - return; - } - - for (CheatDatabaseWindowController *windowController in cheatDatabaseWindowList) - { - [windowController validateWillAddColumn]; - } -} - - (void) showErrorSheet:(NSInteger)errorCode { switch (errorCode) @@ -486,6 +485,45 @@ NSMutableArray *cheatDatabaseWindowList = nil; return @"---"; } +- (void) setCurrentGameSerial:(NSString *)newString +{ + NSString *oldString = currentGameSerial; + currentGameSerial = [newString retain]; + [oldString release]; +} + +- (NSString *) currentGameSerial +{ + if ( (currentGameSerial != nil) && ([currentGameSerial length] > 0) ) + { + return currentGameSerial; + } + + return @"---"; +} + +- (void) setCurrentGameCRC:(NSUInteger)crc +{ + [self willChangeValueForKey:@"currentGameCRCString"]; + currentGameCRC = crc; + [self didChangeValueForKey:@"currentGameCRCString"]; +} + +- (NSUInteger) currentGameCRC +{ + return currentGameCRC; +} + +- (NSString *) currentGameCRCString +{ + if (currentGameCRC != 0) + { + return [NSString stringWithFormat:@"%08lX", (unsigned long)currentGameCRC]; + } + + return @"---"; +} + #pragma mark - #pragma mark IBActions @@ -582,9 +620,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; return; } - NSString *currentGameCode = [cheatManager currentGameCode]; - NSUInteger currentGameCRC = [cheatManager currentGameCRC]; - if ( (currentGameCode == nil) || (currentGameCRC == 0) ) + if ( ([self currentGameSerial] == nil) || ([self currentGameCRC] == 0) ) { return; } @@ -598,7 +634,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; NSInteger selectedIndex = [gameTable selectedRow]; CocoaDSCheatDBGame *selectedGame = (CocoaDSCheatDBGame *)[[gameListController arrangedObjects] objectAtIndex:selectedIndex]; - if ( (![[selectedGame serial] isEqualToString:currentGameCode]) || ([selectedGame crc] != currentGameCRC) ) + if ( (![[selectedGame serial] isEqualToString:[self currentGameSerial]]) || ([selectedGame crc] != [self currentGameCRC]) ) { return; } @@ -631,9 +667,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; return; } - NSString *currentGameCode = [cheatManager currentGameCode]; - NSUInteger currentGameCRC = [cheatManager currentGameCRC]; - if ( (currentGameCode == nil) || (currentGameCRC == 0) ) + if ( ([self currentGameSerial] == nil) || ([self currentGameCRC] == 0) ) { return; } @@ -643,7 +677,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; NSArray *arrangedObjects = (NSArray *)[gameListController arrangedObjects]; for (CocoaDSCheatDBGame *game in arrangedObjects) { - if ( ([game crc] == currentGameCRC) && ([[game serial] isEqualToString:currentGameCode]) ) + if ( ([game crc] == [self currentGameCRC]) && ([[game serial] isEqualToString:[self currentGameSerial]]) ) { selectionIndex = [arrangedObjects indexOfObject:game]; NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:selectionIndex]; diff --git a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm index 53a421d09..9c35b251c 100644 --- a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm @@ -122,8 +122,7 @@ [cheatListController setContent:[cheatManager sessionList]]; [self setCheatSearchViewByStyle:CheatSearchStyle_ExactValue]; - [CheatDatabaseWindowController validateWillAddColumnForAllWindows]; - [CheatDatabaseWindowController validateGameTableFontsForAllWindows]; + [CheatDatabaseWindowController setCurrentGameForAllWindowsSerial:[cheatManager currentGameCode] crc:[cheatManager currentGameCRC]]; didStartSuccessfully = YES; return didStartSuccessfully; @@ -143,8 +142,7 @@ [self setCurrentGameCRC:0]; [self setCdsCheats:nil]; - [CheatDatabaseWindowController validateWillAddColumnForAllWindows]; - [CheatDatabaseWindowController validateGameTableFontsForAllWindows]; + [CheatDatabaseWindowController setCurrentGameForAllWindowsSerial:nil crc:0]; } - (IBAction) addToList:(id)sender From 41e3401765468965e52ffedd84462d585395a488 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 2 Aug 2023 13:23:18 -0700 Subject: [PATCH 12/49] Cocoa Port: In the Cheat Database Viewer, add the option to ignore any game compatibility checks when adding new cheats. - At their own risk, this option allows the user to add any cheat from the database to any game that they want, regardless of any potential dangers that may arise from doing so. Use this option responsibly. --- .../English.lproj/CheatDatabaseViewer.xib | 580 ++++++++++-------- .../CheatDatabaseWindowController.h | 4 + .../CheatDatabaseWindowController.mm | 39 +- .../userinterface/EmuControllerDelegate.mm | 8 + 4 files changed, 383 insertions(+), 248 deletions(-) diff --git a/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib b/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib index bca64a637..f18057cd5 100644 --- a/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib +++ b/desmume/src/frontend/cocoa/translations/English.lproj/CheatDatabaseViewer.xib @@ -95,7 +95,7 @@ 292 - {{43, 3}, {114, 32}} + {{44, 3}, {110, 32}} YES @@ -121,7 +121,7 @@ 292 - {{157, 3}, {114, 32}} + {{149, 3}, {110, 32}} YES @@ -351,101 +351,101 @@ NO 1 - + 268 {{17, 414}, {90, 14}} YES - + 68157504 4326400 Game Search: - + NO 1 - + 265 {{303, 412}, {36, 14}} YES - + 68157504 71435264 CRC: - + LucidaGrande-Bold 11 16 - + NO 1 - + 265 {{294, 430}, {45, 14}} YES - + 68157504 71435264 Serial: - - + + NO 1 - + 265 {{340, 412}, {83, 14}} YES - + 70254657 4330496 CRC - + NO 1 - + 265 {{340, 430}, {83, 14}} YES - + 70254657 4330496 gameCode - + @@ -499,7 +499,7 @@ 292 - {{11, 7}, {27, 27}} + {{12, 7}, {27, 27}} YES @@ -511,7 +511,7 @@ -2033434624 160 - + NSImage NSActionTemplate @@ -1211,7 +1211,7 @@ NO 1 - + 265 {{289, 385}, {136, 28}} @@ -1219,13 +1219,13 @@ _NS:610 YES - + 67108864 134348800 Select Current Game _NS:610 - + -2038284288 129 @@ -1235,6 +1235,71 @@ NO + + + 289 + {{424.9296875, 7}, {106, 26}} + + + YES + + -2076180416 + 2048 + + + 109199360 + 129 + + + 400 + 75 + + + YES + Options + + 1048576 + 2147483647 + + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + OtherViews + + YES + + + + Ignore Compatibility Check + + 2147483647 + + + _popUpItemAction: + + + + + + 1 + YES + 1 + YES + YES + 2 + + NO + {640, 480} @@ -1412,7 +1477,7 @@ 69206017 272633856 - + LucidaGrande-Bold 13 16 @@ -1479,7 +1544,7 @@ NO - + 268 {{17, 148}, {446, 17}} @@ -1487,21 +1552,21 @@ _NS:4068 YES - + 70254657 272634880 - + Major String _NS:4068 - + NO 1 - + 268 {{17, 44}, {446, 96}} @@ -1509,14 +1574,14 @@ _NS:4068 YES - + 69206017 272764928 Minor String _NS:4068 - + @@ -2046,17 +2111,17 @@ selectCurrentGame: - + 196 enabled: isCurrentGameFound - + - + enabled: isCurrentGameFound enabled @@ -2066,156 +2131,6 @@ 197 - - - enabled: isCurrentGameFound - - - - - - enabled: isCurrentGameFound - enabled - isCurrentGameFound - 2 - - - 198 - - - - enabled: isCurrentGameFound - - - - - - enabled: isCurrentGameFound - enabled - isCurrentGameFound - 2 - - - 199 - - - - enabled: isCurrentGameFound - - - - - - enabled: isCurrentGameFound - enabled - isCurrentGameFound - 2 - - - 200 - - - - enabled2: isSelectedGameTheCurrentGame - - - - - - enabled2: isSelectedGameTheCurrentGame - enabled2 - isSelectedGameTheCurrentGame - - YES - - YES - NSMultipleValuesPlaceholder - NSNoSelectionPlaceholder - NSNotApplicablePlaceholder - NSNullPlaceholder - - - YES - - - - - - - - 2 - - - 201 - - - - enabled2: isSelectedGameTheCurrentGame - - - - - - enabled2: isSelectedGameTheCurrentGame - enabled2 - isSelectedGameTheCurrentGame - - YES - - YES - NSMultipleValuesPlaceholder - NSNoSelectionPlaceholder - NSNotApplicablePlaceholder - NSNullPlaceholder - - - YES - - - - - - - - 2 - - - 202 - - - - enabled2: isSelectedGameTheCurrentGame - - - - - - enabled2: isSelectedGameTheCurrentGame - enabled2 - isSelectedGameTheCurrentGame - - YES - - YES - NSMultipleValuesPlaceholder - NSNoSelectionPlaceholder - NSNotApplicablePlaceholder - NSNullPlaceholder - - - YES - - - - - - - - 2 - - - 203 - errorSheet @@ -2235,10 +2150,10 @@ value: errorMajorString - + - + value: errorMajorString value @@ -2251,10 +2166,10 @@ value: errorMajorString - + - + value: errorMajorString value @@ -2267,10 +2182,10 @@ value: errorMinorString - + - + value: errorMinorString value @@ -2285,7 +2200,7 @@ predicate: filterPredicate - + predicate: filterPredicate @@ -2314,7 +2229,7 @@ predicate2: filterPredicate - + predicate2: filterPredicate @@ -2333,7 +2248,7 @@ serial CONTAINS[cd] $value - + 2 @@ -2363,7 +2278,7 @@ crcString CONTAINS[cd] $value - + 2 @@ -2373,17 +2288,17 @@ selectCurrentGameButton - + 229 value: currentGameSerial - + - + value: currentGameSerial value @@ -2396,10 +2311,10 @@ value: currentGameCRCString - + - + value: currentGameCRCString value @@ -2409,6 +2324,121 @@ 241 + + + value: isCompatibilityCheckIgnored + + + + + + value: isCompatibilityCheckIgnored + value + isCompatibilityCheckIgnored + 2 + + + 278 + + + + enabled: isSelectedGameTheCurrentGame + + + + + + enabled: isSelectedGameTheCurrentGame + enabled + isSelectedGameTheCurrentGame + + YES + + YES + NSMultipleValuesPlaceholder + NSNoSelectionPlaceholder + NSNotApplicablePlaceholder + NSNullPlaceholder + + + YES + + + + + + + 2 + + + 279 + + + + enabled: isSelectedGameTheCurrentGame + + + + + + enabled: isSelectedGameTheCurrentGame + enabled + isSelectedGameTheCurrentGame + + YES + + YES + NSMultipleValuesPlaceholder + NSNoSelectionPlaceholder + NSNotApplicablePlaceholder + NSNullPlaceholder + + + YES + + + + + + + 2 + + + 280 + + + + enabled: isSelectedGameTheCurrentGame + + + + + + enabled: isSelectedGameTheCurrentGame + enabled + isSelectedGameTheCurrentGame + + YES + + YES + NSMultipleValuesPlaceholder + NSNoSelectionPlaceholder + NSNotApplicablePlaceholder + NSNullPlaceholder + + + YES + + + + + + + 2 + + + 281 + @@ -2466,12 +2496,13 @@ - - - - - - + + + + + + + @@ -2674,9 +2705,9 @@ YES - + - + @@ -3033,115 +3064,153 @@ 187 - + YES - + 188 - - + + 190 - + YES - + 191 - - + + 210 - + YES - + 211 - - + + 213 - + YES - + 214 - - + + 230 - + YES - + 231 - - + + 232 - + YES - + 233 - - + + 234 - + YES - + 235 - + YES - + 236 - - + + 237 - - + + + + + 270 + + + YES + + + + + + 271 + + + YES + + + + + + 272 + + + YES + + + + + + + 275 + + + + + 277 + + @@ -3212,6 +3281,14 @@ 25.IBPluginDependency 26.IBPluginDependency 27.IBPluginDependency + 270.IBPluginDependency + 270.IBViewBoundsToFrameTransform + 271.IBPluginDependency + 272.IBEditorWindowLastContentRect + 272.IBPluginDependency + 275.IBAttributePlaceholdersKey + 275.IBPluginDependency + 277.IBPluginDependency 28.IBPluginDependency 3.IBEditorWindowLastContentRect 3.IBPluginDependency @@ -3377,6 +3454,23 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD0YAAwcgAAA + + com.apple.InterfaceBuilder.CocoaPlugin + {{916, 204}, {251, 43}} + com.apple.InterfaceBuilder.CocoaPlugin + + ToolTip + + ToolTip + + Renders NDS shadow polygons. Disabling this option may cause some shadows to disappear. Low performance impact. + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin {{502, 214}, {640, 480}} com.apple.InterfaceBuilder.CocoaPlugin {{502, 214}, {640, 480}} @@ -3499,7 +3593,7 @@ - 241 + 281 @@ -3659,11 +3753,15 @@ YES NSActionTemplate + NSMenuCheckmark + NSMenuMixedState NSSwitch YES {14, 14} + {11, 11} + {10, 3} {15, 15} diff --git a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h index e8f1622a4..80e0c6156 100644 --- a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h +++ b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.h @@ -48,6 +48,8 @@ NSString *currentGameIndexString; NSString *currentGameSerial; NSUInteger currentGameCRC; + BOOL isCompatibilityCheckIgnored; + BOOL isOptionWarningSilenced; NSString *errorMajorString; NSString *errorMinorString; @@ -76,6 +78,8 @@ @property (retain, nonatomic) NSString *currentGameSerial; @property (assign, nonatomic) NSUInteger currentGameCRC; @property (readonly, nonatomic) NSString *currentGameCRCString; +@property (assign, nonatomic) BOOL isCompatibilityCheckIgnored; +@property (assign) BOOL isOptionWarningSilenced; @property (assign) NSString *errorMajorString; @property (assign) NSString *errorMinorString; diff --git a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm index 2ec9cb352..c71e759b0 100644 --- a/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm +++ b/desmume/src/frontend/cocoa/userinterface/CheatDatabaseWindowController.mm @@ -46,6 +46,8 @@ NSMutableArray *cheatDatabaseWindowList = nil; @dynamic currentGameSerial; @synthesize currentGameCRC; @dynamic currentGameCRCString; +@dynamic isCompatibilityCheckIgnored; +@synthesize isOptionWarningSilenced; @synthesize errorMajorString; @synthesize errorMinorString; @@ -71,6 +73,8 @@ NSMutableArray *cheatDatabaseWindowList = nil; currentGameTableRowIndex = NSNotFound; currentGameSerial = nil; currentGameCRC = 0; + isCompatibilityCheckIgnored = NO; + isOptionWarningSilenced = NO; errorMajorString = @"No error has occurred!"; errorMinorString = @"This is just a placeholder message for initialization purposes."; @@ -237,6 +241,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; [NSDate date], @"AddedDate", [[self window] stringWithSavedFrame], @"WindowFrame", [NSNumber numberWithFloat:[[[splitView subviews] objectAtIndex:0] frame].size.height], @"WindowSplitViewDividerPosition", + [NSNumber numberWithBool:[self isCompatibilityCheckIgnored]], @"OptionIgnoreCompatibilityCheck", nil]; // ...and then add the newest recent item, ensuring that it is always last in the list. @@ -337,7 +342,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; if ( (delegate != nil) && (cheatManager != nil) && ([selectedGame serial] != nil) ) { - showWillAddColumn = ([[selectedGame serial] isEqualToString:currentGameSerial]) && ([selectedGame crc] == currentGameCRC); + showWillAddColumn = ( [self isCompatibilityCheckIgnored] || (([[selectedGame serial] isEqualToString:currentGameSerial]) && ([selectedGame crc] == currentGameCRC)) ); } NSTableColumn *willAddColumn = [entryOutline tableColumnWithIdentifier:@"willAdd"]; @@ -524,6 +529,30 @@ NSMutableArray *cheatDatabaseWindowList = nil; return @"---"; } +- (BOOL) isCompatibilityCheckIgnored +{ + return isCompatibilityCheckIgnored; +} + +- (void) setIsCompatibilityCheckIgnored:(BOOL)theState +{ + isCompatibilityCheckIgnored = theState; + + if (![self isOptionWarningSilenced] && theState) + { + NSAlert *criticalErrorAlert = [[[NSAlert alloc] init] autorelease]; + [criticalErrorAlert setAlertStyle:ALERTSTYLE_CRITICAL]; + [criticalErrorAlert setMessageText:@"Using an incompatible cheat may ruin your game."]; + [criticalErrorAlert setInformativeText:@"Cheats are normally restricted to the current game \ +for compatibility reasons. By choosing to ignore the compatibility check, you can add any cheat to \ +any game that you want, but you must also assume the risk of an incompatible cheat ruining your game \ +session or corrupting your game's save data."]; + [criticalErrorAlert runModal]; + } + + [self validateWillAddColumn]; +} + #pragma mark - #pragma mark IBActions @@ -620,11 +649,6 @@ NSMutableArray *cheatDatabaseWindowList = nil; return; } - if ( ([self currentGameSerial] == nil) || ([self currentGameCRC] == 0) ) - { - return; - } - NSMutableArray *entryTree = [entryListController content]; if (entryTree == nil) { @@ -634,7 +658,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; NSInteger selectedIndex = [gameTable selectedRow]; CocoaDSCheatDBGame *selectedGame = (CocoaDSCheatDBGame *)[[gameListController arrangedObjects] objectAtIndex:selectedIndex]; - if ( (![[selectedGame serial] isEqualToString:[self currentGameSerial]]) || ([selectedGame crc] != [self currentGameCRC]) ) + if ( ![self isCompatibilityCheckIgnored] && ((![[selectedGame serial] isEqualToString:[self currentGameSerial]]) || ([selectedGame crc] != [self currentGameCRC])) ) { return; } @@ -725,6 +749,7 @@ NSMutableArray *cheatDatabaseWindowList = nil; NSMutableDictionary *newRecentItem = [NSMutableDictionary dictionaryWithDictionary:recentItem]; [newRecentItem setObject:[[self window] stringWithSavedFrame] forKey:@"WindowFrame"]; [newRecentItem setObject:[NSNumber numberWithFloat:[[[splitView subviews] objectAtIndex:0] frame].size.height] forKey:@"WindowSplitViewDividerPosition"]; + [newRecentItem setObject:[NSNumber numberWithBool:[self isCompatibilityCheckIgnored]] forKey:@"OptionIgnoreCompatibilityCheck"]; [dbRecentsList addObject:newRecentItem]; } diff --git a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm index 9a0b82b18..2fe9e93c5 100644 --- a/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/EmuControllerDelegate.mm @@ -854,6 +854,14 @@ if (recentItem != nil) { + NSNumber *compatibilityCheckNumber = (NSNumber *)[recentItem objectForKey:@"OptionIgnoreCompatibilityCheck"]; + if (compatibilityCheckNumber != nil) + { + [newWindowController setIsOptionWarningSilenced:YES]; + [newWindowController setIsCompatibilityCheckIgnored:[compatibilityCheckNumber boolValue]]; + [newWindowController setIsOptionWarningSilenced:NO]; + } + // Set up the window properties. NSString *windowFrameString = (NSString *)[recentItem objectForKey:@"WindowFrame"]; if (windowFrameString != nil) From 402e9f0a31bcd087dc3c60ad0d1c789defd14ce4 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 2 Aug 2023 13:50:41 -0700 Subject: [PATCH 13/49] Cocoa Port: Add two new Cheat Manager actions, "Enable All Cheats" and "Disable All Cheats", which do exactly as their descriptions would suggest. --- .../translations/English.lproj/MainMenu.xib | 1147 ++++------------- .../cocoa/userinterface/cheatWindowDelegate.h | 4 + .../userinterface/cheatWindowDelegate.mm | 32 + 3 files changed, 267 insertions(+), 916 deletions(-) diff --git a/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib b/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib index 03537b54a..f7d728067 100644 --- a/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib +++ b/desmume/src/frontend/cocoa/translations/English.lproj/MainMenu.xib @@ -18702,26 +18702,26 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 28682 100 - + 289 {{185, 16}, {110, 26}} YES - + -2076180416 2048 - + 109199360 129 400 75 - - + + YES Actions @@ -18732,27 +18732,59 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 _popUpItemAction: - + YES - + CheatManagerActions - - - + + + + Enable All Cheats + + 2147483647 + + + _popUpItemAction: + + + + + Disable All Cheats + + 2147483647 + + + _popUpItemAction: + + + + + YES + YES + + + 2147483647 + + + _popUpItemAction: + + + + Remove All Cheats 2147483647 _popUpItemAction: - + - 1 + 4 YES 1 YES @@ -30344,7 +30376,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {1.7976931348623157e+308, 1.7976931348623157e+308} - + 256 @@ -30360,6 +30392,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 77}, {206, 18}} + YES -2080374784 @@ -30383,6 +30416,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{12, 15}, {112, 14}} + YES 68157504 @@ -30401,6 +30435,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 57}, {115, 18}} + YES -2080374784 @@ -30424,6 +30459,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 37}, {195, 18}} + YES -2080374784 @@ -30447,6 +30483,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{126, 10}, {96, 22}} + YES -2076180416 @@ -30566,10 +30603,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {237, 102}} + {{17, 134}, {239, 118}} + {0, 0} 67108864 @@ -30590,6 +30629,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{56, 7}, {162, 19}} + YES -2080374784 @@ -30619,6 +30659,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{18, 14}, {107, 58}} + YES NO 3 @@ -30872,10 +30913,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {237, 82}} + {{17, 444}, {239, 98}} + {0, 0} 67108864 @@ -30904,6 +30947,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 52}, {108, 18}} + YES -2080374784 @@ -30927,6 +30971,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 32}, {135, 18}} + YES -2080374784 @@ -30950,6 +30995,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 12}, {82, 18}} + YES -2080374784 @@ -30973,6 +31019,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{32, 143}, {113, 14}} + YES 68157504 @@ -30991,6 +31038,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{150, 141}, {48, 19}} + YES -1804599231 @@ -31049,6 +31097,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{203, 137}, {19, 27}} + YES 0 @@ -31066,6 +31115,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 72}, {137, 18}} + YES 67108864 @@ -31089,6 +31139,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{6, 96}, {139, 14}} + YES 68157504 @@ -31107,6 +31158,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{203, 89}, {19, 27}} + YES 67895328 @@ -31126,6 +31178,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{163, 96}, {38, 14}} + YES 68157504 @@ -31183,6 +31236,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{41, 119}, {104, 14}} + YES 68157504 @@ -31201,6 +31255,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{147, 114}, {75, 22}} + YES -2076180416 @@ -31266,10 +31321,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {237, 168}} + {{17, 256}, {239, 184}} + {0, 0} 67108864 @@ -31298,6 +31355,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 11}, {116, 18}} + YES 67108864 @@ -31321,6 +31379,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{150, 31}, {72, 22}} + YES -2076180416 @@ -31364,6 +31423,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15, 36}, {142, 14}} + YES 68157504 @@ -31382,6 +31442,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{15.8672, 59}, {120, 14}} + YES 68157504 @@ -31400,6 +31461,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 268 {{126.867, 54}, {95, 22}} + YES -2076180416 @@ -31489,10 +31551,12 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {{1, 1}, {235, 84}} + {{17, 30}, {237, 100}} + {0, 0} 67108864 @@ -31510,6 +31574,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 {273, 562} + + {{0, 0}, {1920, 1177}} {1.7976931348623157e+308, 1.7976931348623157e+308} @@ -58854,10 +58920,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 enabled: selection.currentRom - + - + enabled: selection.currentRom enabled @@ -58875,10 +58941,66 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 removeAllFromList: - + 12460 + + + enabled: selection.currentRom + + + + + + enabled: selection.currentRom + enabled + selection.currentRom + + NSValueTransformerName + NSIsNotNil + + 2 + + + 12466 + + + + enabled: selection.currentRom + + + + + + enabled: selection.currentRom + enabled + selection.currentRom + + NSValueTransformerName + NSIsNotNil + + 2 + + + 12467 + + + + disableAllInList: + + + + 12468 + + + + enableAllInList: + + + + 12469 + @@ -60636,7 +60758,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - + @@ -80227,38 +80349,56 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 12401 - + - + 12402 - + - + - + 12403 - + - - + + + + + - + 12409 - - + + 12412 - - + + + + + 12461 + + + + + 12462 + + + + + 12463 + + @@ -82937,6 +83077,9 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABC/bvnwpQAAA + com.apple.InterfaceBuilder.CocoaPlugin {{917, 188}, {221, 88}} com.apple.InterfaceBuilder.CocoaPlugin @@ -83071,13 +83214,16 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - P4AAAL+AAABDMwAAwiAAAA + P4AAAL+AAABDOQAAwiAAAA com.apple.InterfaceBuilder.CocoaPlugin - {{647, 375}, {193, 43}} + {{643, 325}, {193, 93}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin {{903, 773}, {143, 23}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -86399,10 +86545,10 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - 12460 + 12469 - + AppDelegate NSObject @@ -86510,8 +86656,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/appDelegate.h + IBDocumentRelativeSource + ../../userinterface/appDelegate.h @@ -86586,8 +86732,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/CheatDatabaseWindowController.h + IBDocumentRelativeSource + ../../userinterface/CheatDatabaseWindowController.h @@ -86596,6 +86742,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 id id + id + id id id id @@ -86614,6 +86762,14 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 applyConfiguration: id + + disableAllInList: + id + + + enableAllInList: + id + removeAllFromList: id @@ -86742,24 +86898,24 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/cheatWindowDelegate.h + IBDocumentRelativeSource + ../../userinterface/cheatWindowDelegate.h DirectoryURLDragDestTextField NSTextField - IBProjectSource - cocoa_util.h + IBDocumentRelativeSource + ../../cocoa_util.h DisplayPreviewView NSView - - IBProjectSource - userinterface/preferencesWindowDelegate.h + + IBDocumentRelativeSource + ../../userinterface/preferencesWindowDelegate.h @@ -86994,8 +87150,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/DisplayWindowController.h + IBDocumentRelativeSource + ../../userinterface/DisplayWindowController.h @@ -87435,8 +87591,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/EmuControllerDelegate.h + IBDocumentRelativeSource + ../../userinterface/EmuControllerDelegate.h @@ -87471,8 +87627,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/FileMigrationDelegate.h + IBDocumentRelativeSource + ../../userinterface/FileMigrationDelegate.h @@ -87493,8 +87649,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/InputManager.h + IBDocumentRelativeSource + ../../userinterface/InputManager.h @@ -87699,8 +87855,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/inputPrefsView.h + IBDocumentRelativeSource + ../../userinterface/inputPrefsView.h @@ -87721,8 +87877,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/InputProfileController.h + IBDocumentRelativeSource + ../../userinterface/InputProfileController.h @@ -87751,8 +87907,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/MacAVCaptureTool.h + IBDocumentRelativeSource + ../../userinterface/MacAVCaptureTool.h @@ -87784,8 +87940,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/MacBaseCaptureTool.h + IBDocumentRelativeSource + ../../userinterface/MacBaseCaptureTool.h @@ -87803,8 +87959,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/MacScreenshotCaptureTool.h + IBDocumentRelativeSource + ../../userinterface/MacScreenshotCaptureTool.h @@ -88038,14 +88194,14 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSWindow - + RomInfoContentView NSView - - IBProjectSource - userinterface/RomInfoPanel.h + + IBDocumentRelativeSource + ../../userinterface/RomInfoPanel.h @@ -88091,7 +88247,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 RomInfoPanelSectionView - + RomInfoPanelSectionView @@ -88110,7 +88266,7 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 NSTextField - + Slot2WindowDelegate @@ -88249,8 +88405,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/Slot2WindowDelegate.h + IBDocumentRelativeSource + ../../userinterface/Slot2WindowDelegate.h @@ -88330,8 +88486,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/troubleshootingWindowDelegate.h + IBDocumentRelativeSource + ../../userinterface/troubleshootingWindowDelegate.h @@ -88366,849 +88522,8 @@ y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 - IBProjectSource - userinterface/WifiSettingsPanel.h - - - - - - NSActionCell - NSCell - - IBFrameworkSource - AppKit.framework/Headers/NSActionCell.h - - - - NSApplication - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSApplication.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSApplicationScripting.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSColorPanel.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSHelpManager.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSPageLayout.h - - - - NSApplication - - IBFrameworkSource - AppKit.framework/Headers/NSUserInterfaceItemSearching.h - - - - NSArrayController - NSObjectController - - IBFrameworkSource - AppKit.framework/Headers/NSArrayController.h - - - - NSBox - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSBox.h - - - - NSBrowser - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSBrowser.h - - - - NSButton - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSButton.h - - - - NSButtonCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSButtonCell.h - - - - NSCell - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSCell.h - - - - NSColorWell - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSColorWell.h - - - - NSControl - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSControl.h - - - - NSController - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSController.h - - - - NSDatePicker - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSDatePicker.h - - - - NSDatePickerCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSDatePickerCell.h - - - - NSDocumentController - NSObject - - id - id - id - id - - - - clearRecentDocuments: - id - - - newDocument: - id - - - openDocument: - id - - - saveAllDocuments: - id - - - - IBFrameworkSource - AppKit.framework/Headers/NSDocumentController.h - - - - NSDrawer - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSDrawer.h - - - - NSFormatter - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFormatter.h - - - - NSImageCell - NSCell - - IBFrameworkSource - AppKit.framework/Headers/NSImageCell.h - - - - NSImageView - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSImageView.h - - - - NSLevelIndicator - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSLevelIndicator.h - - - - NSLevelIndicatorCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSLevelIndicatorCell.h - - - - NSMatrix - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSMatrix.h - - - - NSMenu - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSMenu.h - - - - NSMenuItem - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSMenuItem.h - - - - NSMenuItemCell - NSButtonCell - - IBFrameworkSource - AppKit.framework/Headers/NSMenuItemCell.h - - - - NSMovieView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSMovieView.h - - - - NSNumberFormatter - NSFormatter - - IBFrameworkSource - Foundation.framework/Headers/NSNumberFormatter.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSAccessibility.h - - - - NSObject - - - - NSObject - - - - NSObject - - - - NSObject - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSDictionaryController.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSDragging.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSFontManager.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSFontPanel.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSKeyValueBinding.h - - - - NSObject - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSNibLoading.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSOutlineView.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSPasteboard.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSSavePanel.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSTableView.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSToolbarItem.h - - - - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSView.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSClassDescription.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSError.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFileManager.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueObserving.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyedArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObject.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObjectScripting.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSPortCoder.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSRunLoop.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptClassDescription.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptObjectSpecifiers.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSScriptWhoseTests.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSThread.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURL.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLConnection.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLDownload.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CAAnimation.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CALayer.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CIImageProvider.h - - - - NSObjectController - NSController - - IBFrameworkSource - AppKit.framework/Headers/NSObjectController.h - - - - NSOutlineView - NSTableView - - - - NSPanel - NSWindow - - IBFrameworkSource - AppKit.framework/Headers/NSPanel.h - - - - NSPopUpButton - NSButton - - IBFrameworkSource - AppKit.framework/Headers/NSPopUpButton.h - - - - NSPopUpButtonCell - NSMenuItemCell - - IBFrameworkSource - AppKit.framework/Headers/NSPopUpButtonCell.h - - - - NSProgressIndicator - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSProgressIndicator.h - - - - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSInterfaceStyle.h - - - - NSResponder - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSResponder.h - - - - NSScrollView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSScrollView.h - - - - NSScroller - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSScroller.h - - - - NSSearchField - NSTextField - - IBFrameworkSource - AppKit.framework/Headers/NSSearchField.h - - - - NSSearchFieldCell - NSTextFieldCell - - IBFrameworkSource - AppKit.framework/Headers/NSSearchFieldCell.h - - - - NSSegmentedCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSSegmentedCell.h - - - - NSSegmentedControl - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSSegmentedControl.h - - - - NSSlider - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSSlider.h - - - - NSSliderCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSSliderCell.h - - - - NSSplitView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSSplitView.h - - - - NSStepper - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSStepper.h - - - - NSStepperCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSStepperCell.h - - - - NSTabView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSTabView.h - - - - NSTabViewItem - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSTabViewItem.h - - - - NSTableColumn - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSTableColumn.h - - - - NSTableHeaderView - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSTableHeaderView.h - - - - NSTableView - NSControl - - - - NSText - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSText.h - - - - NSTextField - NSControl - - IBFrameworkSource - AppKit.framework/Headers/NSTextField.h - - - - NSTextFieldCell - NSActionCell - - IBFrameworkSource - AppKit.framework/Headers/NSTextFieldCell.h - - - - NSTextView - NSText - - IBFrameworkSource - AppKit.framework/Headers/NSTextView.h - - - - NSToolbar - NSObject - - IBFrameworkSource - AppKit.framework/Headers/NSToolbar.h - - - - NSToolbarItem - NSObject - - - - NSTreeController - NSObjectController - - IBFrameworkSource - AppKit.framework/Headers/NSTreeController.h - - - - NSUserDefaultsController - NSController - - IBFrameworkSource - AppKit.framework/Headers/NSUserDefaultsController.h - - - - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSClipView.h - - - - NSView - - - - NSView - - IBFrameworkSource - AppKit.framework/Headers/NSRulerView.h - - - - NSView - NSResponder - - - - NSWindow - - - - NSWindow - NSResponder - - IBFrameworkSource - AppKit.framework/Headers/NSWindow.h - - - - NSWindow - - IBFrameworkSource - AppKit.framework/Headers/NSWindowScripting.h - - - - NSWindowController - NSResponder - - showWindow: - id - - - showWindow: - - showWindow: - id - - - - IBFrameworkSource - AppKit.framework/Headers/NSWindowController.h + IBDocumentRelativeSource + ../../userinterface/WifiSettingsPanel.h diff --git a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h index 099e582b2..9d4dc9a29 100644 --- a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h +++ b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.h @@ -98,7 +98,11 @@ - (IBAction) addToList:(id)sender; - (IBAction) removeFromList:(id)sender; + +- (IBAction) enableAllInList:(id)sender; +- (IBAction) disableAllInList:(id)sender; - (IBAction) removeAllFromList:(id)sender; + - (IBAction) setInternalCheatValue:(id)sender; - (IBAction) applyConfiguration:(id)sender; - (IBAction) selectCheatType:(id)sender; diff --git a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm index 9c35b251c..8ce840a61 100644 --- a/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm +++ b/desmume/src/frontend/cocoa/userinterface/cheatWindowDelegate.mm @@ -197,6 +197,38 @@ } } +- (IBAction) enableAllInList:(id)sender +{ + NSArray *cheatListArray = [cheatListController content]; + if (cheatListArray == nil) + { + return; + } + + for (CocoaDSCheatItem *cheatItem in cheatListArray) + { + [cheatItem setEnabled:YES]; + } + + [[self cdsCheats] save]; +} + +- (IBAction) disableAllInList:(id)sender +{ + NSArray *cheatListArray = [cheatListController content]; + if (cheatListArray == nil) + { + return; + } + + for (CocoaDSCheatItem *cheatItem in cheatListArray) + { + [cheatItem setEnabled:NO]; + } + + [[self cdsCheats] save]; +} + - (IBAction) removeAllFromList:(id)sender { CocoaDSCheatManager *cheatManager = [self cdsCheats]; From 357ff8a2c55900a3db99888a563443c4f69b2941 Mon Sep 17 00:00:00 2001 From: Johan Mattsson <39247600+mjunix@users.noreply.github.com> Date: Sun, 6 Aug 2023 00:20:22 +0200 Subject: [PATCH 14/49] Fix potential index out of bounds --- desmume/src/slot2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desmume/src/slot2.cpp b/desmume/src/slot2.cpp index 8dd6ce993..7463d3e23 100644 --- a/desmume/src/slot2.cpp +++ b/desmume/src/slot2.cpp @@ -163,7 +163,7 @@ bool slot2_Change(NDS_SLOT2_TYPE changeToType) void slot2_setDeviceByType(NDS_SLOT2_TYPE theType) { - if (theType > NDS_SLOT2_COUNT || theType < 0) + if (theType >= NDS_SLOT2_COUNT || theType < 0) { return; } From ca799e60b7a1cdcc8479c34e0565ead7430a4b6a Mon Sep 17 00:00:00 2001 From: Johan Mattsson <39247600+mjunix@users.noreply.github.com> Date: Sun, 6 Aug 2023 00:35:40 +0200 Subject: [PATCH 15/49] Fix potential index out of bounds --- desmume/src/slot2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desmume/src/slot2.cpp b/desmume/src/slot2.cpp index 7463d3e23..4640b5a0b 100644 --- a/desmume/src/slot2.cpp +++ b/desmume/src/slot2.cpp @@ -106,7 +106,7 @@ void slot2_Reset() bool slot2_Change(NDS_SLOT2_TYPE changeToType) { - if (changeToType > NDS_SLOT2_COUNT || changeToType < 0) + if (changeToType >= NDS_SLOT2_COUNT || changeToType < 0) return false; if (slot2_device_type == changeToType) From 25cbcd255e6d42fc66baa368b042c3c7a9577965 Mon Sep 17 00:00:00 2001 From: zeromus Date: Sun, 3 Sep 2023 06:00:05 -0400 Subject: [PATCH 16/49] fix buffer overflow (by one value only) in spu that happened basically 100% of the time a sample ended. whether it corrupted the heap or not is a matter of luck. should fix #717 --- desmume/src/SPU.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/desmume/src/SPU.cpp b/desmume/src/SPU.cpp index 4045be3c6..96c449bbf 100644 --- a/desmume/src/SPU.cpp +++ b/desmume/src/SPU.cpp @@ -1179,7 +1179,6 @@ template static FORCEINLINE void TestForLoop(SPU_struct *SPU, channe if(chan->repeat != 1) { SPU->KeyOff(chan->num); - SPU->bufpos = SPU->buflength; return; } @@ -1235,13 +1234,16 @@ template { s16 data = 0; s32 pos = chan->sampcntInt; - switch(FORMAT) + if(chan->status != CHANSTAT_STOPPED) { - case 0: data = Fetch8BitData (chan, pos); break; - case 1: data = Fetch16BitData(chan, pos); break; - case 2: data = FetchADPCMData(chan, pos); break; - case 3: data = FetchPSGData (chan, pos); break; - default: break; + switch(FORMAT) + { + case 0: data = Fetch8BitData (chan, pos); break; + case 1: data = Fetch16BitData(chan, pos); break; + case 2: data = FetchADPCMData(chan, pos); break; + case 3: data = FetchPSGData (chan, pos); break; + default: break; + } } chan->pcm16bOffs++; chan->pcm16b[SPUCHAN_PCM16B_AT(chan->pcm16bOffs)] = data; From 7a3b748d77f31390263564341fa2bb90fb39b443 Mon Sep 17 00:00:00 2001 From: Roger Manuel Date: Wed, 4 Oct 2023 09:45:02 -0700 Subject: [PATCH 17/49] Fix erroneous copyright date in slot1_retail_auto.cpp (related to commit 8fefb4f) --- desmume/src/addons/slot1_retail_auto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desmume/src/addons/slot1_retail_auto.cpp b/desmume/src/addons/slot1_retail_auto.cpp index 43fedcf9b..368415950 100644 --- a/desmume/src/addons/slot1_retail_auto.cpp +++ b/desmume/src/addons/slot1_retail_auto.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2105 DeSmuME team + Copyright (C) 2013-2015 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From 0a34ef8e0b5efa43672de8e584b959cb3bf157ed Mon Sep 17 00:00:00 2001 From: windwakr <284886+windwakr@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:05:01 -0400 Subject: [PATCH 18/49] Slot2: Add Sega Card Reader(HCV-1000) --- desmume/src/Makefile.am | 1 + desmume/src/addons/slot2_hcv1000.cpp | 81 +++++++++++++++++++ desmume/src/frontend/interface/meson.build | 2 +- .../windows/DeSmuME_Interface.vcxproj | 1 + .../windows/DeSmuME_Interface.vcxproj.filters | 3 + desmume/src/frontend/posix/Makefile.am | 2 +- desmume/src/frontend/posix/meson.build | 2 +- desmume/src/frontend/windows/DeSmuME.vcxproj | 1 + .../frontend/windows/DeSmuME.vcxproj.filters | 3 + .../src/frontend/windows/gbaslot_config.cpp | 68 +++++++++++++++- desmume/src/frontend/windows/gbaslot_config.h | 3 +- desmume/src/frontend/windows/inputdx.cpp | 30 ++++++- desmume/src/frontend/windows/inputdx.h | 8 +- desmume/src/frontend/windows/main.cpp | 8 +- desmume/src/frontend/windows/resource.h | 5 +- desmume/src/frontend/windows/resources.rc | 11 +++ desmume/src/slot2.cpp | 7 +- desmume/src/slot2.h | 5 +- 18 files changed, 229 insertions(+), 12 deletions(-) create mode 100644 desmume/src/addons/slot2_hcv1000.cpp diff --git a/desmume/src/Makefile.am b/desmume/src/Makefile.am index f3185e918..b17d4df7f 100644 --- a/desmume/src/Makefile.am +++ b/desmume/src/Makefile.am @@ -95,6 +95,7 @@ libdesmume_a_SOURCES = \ addons/slot2_none.cpp \ addons/slot2_rumblepak.cpp \ addons/slot2_guitarGrip.cpp \ + addons/slot2_hcv1000.cpp \ addons/slot2_expMemory.cpp \ addons/slot2_piano.cpp \ addons/slot2_passme.cpp \ diff --git a/desmume/src/addons/slot2_hcv1000.cpp b/desmume/src/addons/slot2_hcv1000.cpp new file mode 100644 index 000000000..8135fe003 --- /dev/null +++ b/desmume/src/addons/slot2_hcv1000.cpp @@ -0,0 +1,81 @@ +//HCV-1000 emulation code adapted from GBE+: https://github.com/shonumi/gbe-plus + +/* + Modifications Copyright (C) 2023 DeSmuME team + + This file 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 file 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 the this software. If not, see . +*/ + +#include + +#include "../slot2.h" + +u8 hcv1000_cnt; +char hcv1000_data[16]; + +class Slot2_HCV1000 : public ISlot2Interface +{ +public: + + virtual Slot2Info const* info() + { + static Slot2InfoSimple info("Sega Card Reader", "Sega Card Reader(HCV-1000) add-on", 0x09); + return &info; + } + + virtual bool init() + { + hcv1000_cnt = 0; + memset(hcv1000_data, 0x5F, 16); + + return TRUE; + } + + virtual void writeByte(u8 PROCNUM, u32 addr, u8 val) + { + if (addr == 0xA000000) { hcv1000_cnt = (val & 0x83); } + } + + virtual u8 readByte(u8 PROCNUM, u32 addr) + { + u8 slot_byte = 0xFF; + //Reading these cart addresses is for detection + if (addr < 0x8020000) + { + u8 data = 0xF0 | ((addr & 0x1F) >> 1); + slot_byte = (addr & 0x1) ? 0xFD : data; + } + + //HCV_CNT + else if (addr == 0xA000000) { slot_byte = hcv1000_cnt; } + + //HCV_DATA + else if ((addr >= 0xA000010) && (addr <= 0xA00001F)) + { + slot_byte = (u8)hcv1000_data[addr & 0xF]; + } + + return slot_byte; + } + + virtual u16 readWord(u8 PROCNUM, u32 addr) { return 0xFDFD; }; + virtual u32 readLong(u8 PROCNUM, u32 addr) { return 0xFDFDFDFD; }; +}; + +ISlot2Interface* construct_Slot2_HCV1000() { return new Slot2_HCV1000(); } + +void HCV1000_setReady() +{ + hcv1000_cnt &= ~0x80; +} diff --git a/desmume/src/frontend/interface/meson.build b/desmume/src/frontend/interface/meson.build index 1a6328a1a..6a62fbb2e 100644 --- a/desmume/src/frontend/interface/meson.build +++ b/desmume/src/frontend/interface/meson.build @@ -109,7 +109,7 @@ libdesmume_src += [ '../../utils/tinyxml/tinyxmlerror.cpp', '../../utils/tinyxml/tinyxmlparser.cpp', '../../utils/colorspacehandler/colorspacehandler.cpp', - '../../addons/slot2_auto.cpp', '../../addons/slot2_mpcf.cpp', '../../addons/slot2_paddle.cpp', '../../addons/slot2_gbagame.cpp', '../../addons/slot2_none.cpp', '../../addons/slot2_rumblepak.cpp', '../../addons/slot2_guitarGrip.cpp', '../../addons/slot2_expMemory.cpp', '../../addons/slot2_piano.cpp', '../../addons/slot2_passme.cpp', '../../addons/slot1_none.cpp', '../../addons/slot1_r4.cpp', '../../addons/slot1_retail_nand.cpp', '../../addons/slot1_retail_auto.cpp', '../../addons/slot1_retail_mcrom.cpp', '../../addons/slot1_retail_mcrom_debug.cpp', '../../addons/slot1comp_mc.cpp', '../../addons/slot1comp_rom.cpp', '../../addons/slot1comp_protocol.cpp', + '../../addons/slot2_auto.cpp', '../../addons/slot2_mpcf.cpp', '../../addons/slot2_paddle.cpp', '../../addons/slot2_gbagame.cpp', '../../addons/slot2_none.cpp', '../../addons/slot2_rumblepak.cpp', '../../addons/slot2_guitarGrip.cpp', '../../addons/slot2_hcv1000.cpp', '../../addons/slot2_expMemory.cpp', '../../addons/slot2_piano.cpp', '../../addons/slot2_passme.cpp', '../../addons/slot1_none.cpp', '../../addons/slot1_r4.cpp', '../../addons/slot1_retail_nand.cpp', '../../addons/slot1_retail_auto.cpp', '../../addons/slot1_retail_mcrom.cpp', '../../addons/slot1_retail_mcrom_debug.cpp', '../../addons/slot1comp_mc.cpp', '../../addons/slot1comp_rom.cpp', '../../addons/slot1comp_protocol.cpp', '../../cheatSystem.cpp', '../../texcache.cpp', '../../rasterize.cpp', '../../metaspu/metaspu.cpp', diff --git a/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj b/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj index 35638797a..ab87e284e 100644 --- a/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj +++ b/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj @@ -268,6 +268,7 @@ + diff --git a/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj.filters b/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj.filters index db90b8e93..cb3248c43 100755 --- a/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj.filters +++ b/desmume/src/frontend/interface/windows/DeSmuME_Interface.vcxproj.filters @@ -132,6 +132,9 @@ addons + + addons + addons diff --git a/desmume/src/frontend/posix/Makefile.am b/desmume/src/frontend/posix/Makefile.am index 59b0fb3bc..4329a89e7 100644 --- a/desmume/src/frontend/posix/Makefile.am +++ b/desmume/src/frontend/posix/Makefile.am @@ -98,7 +98,7 @@ libdesmume_a_SOURCES = \ ../../utils/tinyxml/tinyxmlparser.cpp \ ../../utils/glcorearb.h \ ../../utils/colorspacehandler/colorspacehandler.cpp ../../utils/colorspacehandler/colorspacehandler.h \ - ../../addons/slot2_auto.cpp ../../addons/slot2_mpcf.cpp ../../addons/slot2_paddle.cpp ../../addons/slot2_gbagame.cpp ../../addons/slot2_none.cpp ../../addons/slot2_rumblepak.cpp ../../addons/slot2_guitarGrip.cpp ../../addons/slot2_expMemory.cpp ../../addons/slot2_piano.cpp ../../addons/slot2_passme.cpp ../../addons/slot1_none.cpp ../../addons/slot1_r4.cpp ../../addons/slot1_retail_nand.cpp ../../addons/slot1_retail_auto.cpp ../../addons/slot1_retail_mcrom.cpp ../../addons/slot1_retail_mcrom_debug.cpp ../../addons/slot1comp_mc.cpp ../../addons/slot1comp_mc.h ../../addons/slot1comp_rom.h ../../addons/slot1comp_rom.cpp ../../addons/slot1comp_protocol.h ../../addons/slot1comp_protocol.cpp \ + ../../addons/slot2_auto.cpp ../../addons/slot2_mpcf.cpp ../../addons/slot2_paddle.cpp ../../addons/slot2_gbagame.cpp ../../addons/slot2_none.cpp ../../addons/slot2_rumblepak.cpp ../../addons/slot2_guitarGrip.cpp ../../addons/slot2_hcv1000.cpp ../../addons/slot2_expMemory.cpp ../../addons/slot2_piano.cpp ../../addons/slot2_passme.cpp ../../addons/slot1_none.cpp ../../addons/slot1_r4.cpp ../../addons/slot1_retail_nand.cpp ../../addons/slot1_retail_auto.cpp ../../addons/slot1_retail_mcrom.cpp ../../addons/slot1_retail_mcrom_debug.cpp ../../addons/slot1comp_mc.cpp ../../addons/slot1comp_mc.h ../../addons/slot1comp_rom.h ../../addons/slot1comp_rom.cpp ../../addons/slot1comp_protocol.h ../../addons/slot1comp_protocol.cpp \ ../../cheatSystem.cpp ../../cheatSystem.h \ ../../texcache.cpp ../../texcache.h ../../rasterize.cpp ../../rasterize.h \ ../../metaspu/metaspu.cpp ../../metaspu/metaspu.h \ diff --git a/desmume/src/frontend/posix/meson.build b/desmume/src/frontend/posix/meson.build index 901c4defc..89e0e4bef 100644 --- a/desmume/src/frontend/posix/meson.build +++ b/desmume/src/frontend/posix/meson.build @@ -104,7 +104,7 @@ libdesmume_src = [ '../../utils/tinyxml/tinyxmlerror.cpp', '../../utils/tinyxml/tinyxmlparser.cpp', '../../utils/colorspacehandler/colorspacehandler.cpp', - '../../addons/slot2_auto.cpp', '../../addons/slot2_mpcf.cpp', '../../addons/slot2_paddle.cpp', '../../addons/slot2_gbagame.cpp', '../../addons/slot2_none.cpp', '../../addons/slot2_rumblepak.cpp', '../../addons/slot2_guitarGrip.cpp', '../../addons/slot2_expMemory.cpp', '../../addons/slot2_piano.cpp', '../../addons/slot2_passme.cpp', '../../addons/slot1_none.cpp', '../../addons/slot1_r4.cpp', '../../addons/slot1_retail_nand.cpp', '../../addons/slot1_retail_auto.cpp', '../../addons/slot1_retail_mcrom.cpp', '../../addons/slot1_retail_mcrom_debug.cpp', '../../addons/slot1comp_mc.cpp', '../../addons/slot1comp_rom.cpp', '../../addons/slot1comp_protocol.cpp', + '../../addons/slot2_auto.cpp', '../../addons/slot2_mpcf.cpp', '../../addons/slot2_paddle.cpp', '../../addons/slot2_gbagame.cpp', '../../addons/slot2_none.cpp', '../../addons/slot2_rumblepak.cpp', '../../addons/slot2_guitarGrip.cpp', '../../addons/slot2_hcv1000.cpp', '../../addons/slot2_expMemory.cpp', '../../addons/slot2_piano.cpp', '../../addons/slot2_passme.cpp', '../../addons/slot1_none.cpp', '../../addons/slot1_r4.cpp', '../../addons/slot1_retail_nand.cpp', '../../addons/slot1_retail_auto.cpp', '../../addons/slot1_retail_mcrom.cpp', '../../addons/slot1_retail_mcrom_debug.cpp', '../../addons/slot1comp_mc.cpp', '../../addons/slot1comp_rom.cpp', '../../addons/slot1comp_protocol.cpp', '../../cheatSystem.cpp', '../../texcache.cpp', '../../rasterize.cpp', '../../metaspu/metaspu.cpp', diff --git a/desmume/src/frontend/windows/DeSmuME.vcxproj b/desmume/src/frontend/windows/DeSmuME.vcxproj index abf978664..bd4484362 100644 --- a/desmume/src/frontend/windows/DeSmuME.vcxproj +++ b/desmume/src/frontend/windows/DeSmuME.vcxproj @@ -65,6 +65,7 @@ + diff --git a/desmume/src/frontend/windows/DeSmuME.vcxproj.filters b/desmume/src/frontend/windows/DeSmuME.vcxproj.filters index 20bfe9dc2..3e18bf156 100644 --- a/desmume/src/frontend/windows/DeSmuME.vcxproj.filters +++ b/desmume/src/frontend/windows/DeSmuME.vcxproj.filters @@ -930,6 +930,9 @@ frontend\Windows + + addons + diff --git a/desmume/src/frontend/windows/gbaslot_config.cpp b/desmume/src/frontend/windows/gbaslot_config.cpp index 75bb02053..5797b67c9 100644 --- a/desmume/src/frontend/windows/gbaslot_config.cpp +++ b/desmume/src/frontend/windows/gbaslot_config.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2016 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,18 +36,21 @@ u8 last_type = 0; char tmp_cflash_filename[MAX_PATH] = { 0 }; char tmp_cflash_path[MAX_PATH] = { 0 }; char tmp_gbagame_filename[MAX_PATH] = { 0 }; +TCHAR tmp_hcv1000_barcode[17] = { 0 }; ADDON_CFLASH_MODE tmp_CFlashMode = ADDON_CFLASH_MODE_RomPath; HWND OKbutton = NULL; bool _OKbutton = false; SGuitar tmp_Guitar; SPiano tmp_Piano; SPaddle tmp_Paddle; +SHCV1000 tmp_HCV1000; //these are the remembered preset values for directory and filename //they are named very verbosely to distinguish them from the currently-configured values in addons.cpp std::string win32_CFlash_cfgDirectory, win32_CFlash_cfgFileName; UINT win32_CFlash_cfgMode; std::string win32_GBA_cfgRomPath; +std::string win32_HCV1000_barcode; INT_PTR CALLBACK GbaSlotNone(HWND dialog, UINT msg,WPARAM wparam,LPARAM lparam) { @@ -263,6 +266,54 @@ INT_PTR CALLBACK GbaSlotPaddle(HWND dialog, UINT msg,WPARAM wparam,LPARAM lparam return FALSE; } +INT_PTR CALLBACK GbaSlotHCV1000(HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam) +{ + int which = 0; + + switch (msg) + { + case WM_INITDIALOG: + _OKbutton = TRUE; + SendDlgItemMessage(dialog, IDC_HCVSCAN, WM_USER + 44, tmp_HCV1000.SCANKEY, 0); + SendDlgItemMessage(dialog, IDC_HCVBARCODE, EM_SETLIMITTEXT, 16, 0); + SendDlgItemMessage(dialog, IDC_HCVBARCODE, EM_SETSEL, 0, 16); + SetWindowText(GetDlgItem(dialog, IDC_HCVBARCODE), tmp_hcv1000_barcode); + + return TRUE; + + case WM_USER + 46: + SendDlgItemMessage(dialog, IDC_HCVSCAN, WM_USER + 44, tmp_HCV1000.SCANKEY, 0); + return TRUE; + + case WM_USER + 43: + //MessageBox(hDlg,"USER+43 CAUGHT","moo",MB_OK); + which = GetDlgCtrlID((HWND)lparam); + switch (which) + { + case IDC_HCVSCAN: + tmp_HCV1000.SCANKEY = wparam; + + break; + } + + SendDlgItemMessage(dialog, IDC_HCVSCAN, WM_USER + 44, tmp_HCV1000.SCANKEY, 0); + PostMessage(dialog, WM_NEXTDLGCTL, 0, 0); + return true; + + case WM_COMMAND: + case EN_UPDATE: + switch (LOWORD(wparam)) + { + case IDC_HCVBARCODE: + GetWindowText(GetDlgItem(dialog, IDC_HCVBARCODE), tmp_hcv1000_barcode, 16); + + return FALSE; + } + break; + } + return FALSE; +} + INT_PTR CALLBACK GbaSlotRumblePak(HWND dialog, UINT msg,WPARAM wparam,LPARAM lparam) { switch(msg) @@ -478,6 +529,7 @@ u32 GBAslot_IDDs[NDS_SLOT2_COUNT] = { IDD_GBASLOT_PIANO, IDD_GBASLOT_PADDLE, //paddle IDD_GBASLOT_NONE, //PassME + IDD_GBASLOT_HCV1000, //HCV-1000 }; DLGPROC GBAslot_Procs[NDS_SLOT2_COUNT] = { @@ -490,7 +542,8 @@ DLGPROC GBAslot_Procs[NDS_SLOT2_COUNT] = { GbaSlotNone, //expmem GbaSlotPiano, GbaSlotPaddle, - GbaSlotNone // PassME + GbaSlotNone, // PassME + GbaSlotHCV1000, //HCV-1000 }; @@ -566,9 +619,11 @@ void GBAslotDialog(HWND hwnd) strcpy(tmp_cflash_filename, win32_CFlash_cfgFileName.c_str()); strcpy(tmp_cflash_path, win32_CFlash_cfgDirectory.c_str()); strcpy(tmp_gbagame_filename, win32_GBA_cfgRomPath.c_str()); + strcpy(tmp_hcv1000_barcode, win32_HCV1000_barcode.c_str()); memcpy(&tmp_Guitar, &Guitar, sizeof(Guitar)); memcpy(&tmp_Piano, &Piano, sizeof(Piano)); memcpy(&tmp_Paddle, &Paddle, sizeof(Paddle)); + memcpy(&tmp_HCV1000, &HCV1000, sizeof(HCV1000)); tmp_CFlashMode = CFlash_Mode; _OKbutton = false; @@ -633,6 +688,14 @@ void GBAslotDialog(HWND hwnd) break; case NDS_SLOT2_PASSME: break; + case NDS_SLOT2_HCV1000: + win32_HCV1000_barcode = tmp_hcv1000_barcode; + memcpy(&HCV1000, &tmp_HCV1000, sizeof(tmp_HCV1000)); + memset(hcv1000_data, 0x5F, 16); + memcpy(hcv1000_data, win32_HCV1000_barcode.c_str(), (win32_HCV1000_barcode.length() <= 16) ? win32_HCV1000_barcode.length() : 16); + WritePrivateProfileString("Slot2.HCV1000", "barcode", tmp_hcv1000_barcode, IniName); + WritePrivateProfileInt("Slot2.HCV1000", "scankey", HCV1000.SCANKEY, IniName); + break; default: return; } @@ -644,6 +707,7 @@ void GBAslotDialog(HWND hwnd) Guitar.Enabled = (slot2_GetCurrentType() == NDS_SLOT2_GUITARGRIP)?true:false; Piano.Enabled = (slot2_GetCurrentType() == NDS_SLOT2_EASYPIANO)?true:false; Paddle.Enabled = (slot2_GetCurrentType() == NDS_SLOT2_PADDLE)?true:false; + HCV1000.Enabled = (slot2_GetCurrentType() == NDS_SLOT2_HCV1000)?true:false; } } diff --git a/desmume/src/frontend/windows/gbaslot_config.h b/desmume/src/frontend/windows/gbaslot_config.h index ccc7937a2..f06140d7c 100644 --- a/desmume/src/frontend/windows/gbaslot_config.h +++ b/desmume/src/frontend/windows/gbaslot_config.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2015 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ extern std::string win32_CFlash_cfgDirectory, win32_CFlash_cfgFileName; extern UINT win32_CFlash_cfgMode; extern std::string win32_GBA_cfgRomPath; +extern std::string win32_HCV1000_barcode; extern void GBAslotDialog(HWND hwnd); diff --git a/desmume/src/frontend/windows/inputdx.cpp b/desmume/src/frontend/windows/inputdx.cpp index 9772aa785..c6a6b40a9 100644 --- a/desmume/src/frontend/windows/inputdx.cpp +++ b/desmume/src/frontend/windows/inputdx.cpp @@ -3,7 +3,7 @@ licensed under the terms supplied at the end of this file (for the terms are very long!) Differences from that baseline version are: - Copyright (C) 2009-2019 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -258,6 +258,9 @@ SPiano DefaultPiano = { false, 'Z', 'S', 'X', 'D', 'C', 'V', 'G', 'B', 'H', 'N', SPaddle Paddle; SPaddle DefaultPaddle = { false, 'K', 'L' }; +SHCV1000 HCV1000; +SHCV1000 DefaultHCV1000 = { false, 'L'}; + bool killStylusTopScreen = false; bool killStylusOffScreen = false; bool allowUpAndDown = false; @@ -390,6 +393,15 @@ static void ReadPaddleControl(const char* name, WORD& output) } } +static void ReadHCV1000Control(const char* name, WORD& output) +{ + UINT temp; + temp = GetPrivateProfileInt("Slot2.HCV1000", name, -1, IniName); + if (temp != -1) { + output = temp; + } +} + void LoadHotkeyConfig() { SCustomKey *key = &CustomKeys.key(0); @@ -452,6 +464,15 @@ static void LoadPaddleConfig() ReadPaddleControl("INC", Paddle.INC); } +static void LoadHCV1000Config() +{ + memcpy(&HCV1000, &DefaultHCV1000, sizeof(HCV1000)); + +#define DO(X) ReadHCV1000Control(#X,HCV1000.X); + DO(SCANKEY); +#undef DO +} + static void LoadInputConfig() { @@ -2690,6 +2711,7 @@ void input_init() LoadGuitarConfig(); LoadPianoConfig(); LoadPaddleConfig(); + LoadHCV1000Config(); di_init(); FeedbackON = input_feedback; @@ -2816,6 +2838,12 @@ void input_acquire() if (inc) nds.paddle += 5; if (dec) nds.paddle -= 5; } + + if (HCV1000.Enabled) + { + bool scan = !S9xGetState(HCV1000.SCANKEY); + if (scan) HCV1000_setReady(); + } } else { diff --git a/desmume/src/frontend/windows/inputdx.h b/desmume/src/frontend/windows/inputdx.h index 4ed3bd45a..5b23b2c3f 100644 --- a/desmume/src/frontend/windows/inputdx.h +++ b/desmume/src/frontend/windows/inputdx.h @@ -3,7 +3,7 @@ licensed under the terms supplied at the end of this file (for the terms are very long!) Differences from that baseline version are: - Copyright (C) 2008-2010 DeSmuME team + Copyright (C) 2008-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -153,9 +153,15 @@ struct SPaddle { WORD INC; }; +struct SHCV1000 { + BOOL Enabled; + WORD SCANKEY; +}; + extern SGuitar Guitar; extern SPiano Piano; extern SPaddle Paddle; +extern SHCV1000 HCV1000; #endif diff --git a/desmume/src/frontend/windows/main.cpp b/desmume/src/frontend/windows/main.cpp index 292266afa..052c4f5cb 100644 --- a/desmume/src/frontend/windows/main.cpp +++ b/desmume/src/frontend/windows/main.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2006 Theo Berkau - Copyright (C) 2006-2019 DeSmuME team + Copyright (C) 2006-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1580,6 +1580,7 @@ static BOOL LoadROM(const char * filename, const char * physicalName, const char Guitar.Enabled = (selectedSlot2Type == NDS_SLOT2_GUITARGRIP)?true:false; Piano.Enabled = (selectedSlot2Type == NDS_SLOT2_EASYPIANO)?true:false; Paddle.Enabled = (selectedSlot2Type == NDS_SLOT2_PADDLE)?true:false; + HCV1000.Enabled = (selectedSlot2Type == NDS_SLOT2_HCV1000)?true:false; LoadSaveStateInfo(); lagframecounter=0; @@ -2197,6 +2198,8 @@ int _main() win32_CFlash_cfgDirectory = GetPrivateProfileStdString("Slot2.CFlash", "path", ""); win32_CFlash_cfgFileName = GetPrivateProfileStdString("Slot2.CFlash", "filename", ""); win32_GBA_cfgRomPath = GetPrivateProfileStdString("Slot2.GBAgame", "filename", ""); + win32_HCV1000_barcode = GetPrivateProfileStdString("Slot2.HCV1000", "barcode", ""); + memcpy(hcv1000_data, win32_HCV1000_barcode.c_str(), (win32_HCV1000_barcode.length() <= 16) ? win32_HCV1000_barcode.length() : 16); cmdline.process_addonCommands(); WIN_InstallCFlash(); @@ -2258,6 +2261,8 @@ int _main() break; case NDS_SLOT2_PASSME: break; + case NDS_SLOT2_HCV1000: + break; default: slot2_device_type = NDS_SLOT2_NONE; break; @@ -2268,6 +2273,7 @@ int _main() Guitar.Enabled = (slot2_device_type == NDS_SLOT2_GUITARGRIP)?true:false; Piano.Enabled = (slot2_device_type == NDS_SLOT2_EASYPIANO)?true:false; Paddle.Enabled = (slot2_device_type == NDS_SLOT2_PADDLE)?true:false; + HCV1000.Enabled = (slot2_device_type == NDS_SLOT2_HCV1000)?true:false; CommonSettings.WifiBridgeDeviceID = GetPrivateProfileInt("Wifi", "BridgeAdapter", 0, IniName); diff --git a/desmume/src/frontend/windows/resource.h b/desmume/src/frontend/windows/resource.h index a753958ae..8dd6224cc 100644 --- a/desmume/src/frontend/windows/resource.h +++ b/desmume/src/frontend/windows/resource.h @@ -514,7 +514,9 @@ #define IDC_WIFI_ENABLED 1065 #define IDC_STATIC_RANGE 1066 #define IDC_WIFI_COMPAT 1066 +#define IDC_HCVSCAN 1066 #define IDC_TEXSCALE 1067 +#define IDC_HCVBARCODE 1067 #define IDC_BADD 1068 #define IDC_LIST 1069 #define IDC_TEX_DEPOSTERIZE 1070 @@ -923,6 +925,7 @@ #define IDD_SLOT1_R4 10012 #define IDD_SLOT1_DEBUG 10013 #define IDD_GBASLOT_PADDLE 10014 +#define IDD_GBASLOT_HCV1000 10015 #define IDM_FILE_STOPAVI 40000 #define IDM_SCREENSEP_NONE 40000 #define IDM_FILE_STOPWAV 40001 @@ -1156,7 +1159,7 @@ #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 128 #define _APS_NEXT_COMMAND_VALUE 40159 -#define _APS_NEXT_CONTROL_VALUE 1066 +#define _APS_NEXT_CONTROL_VALUE 1068 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/desmume/src/frontend/windows/resources.rc b/desmume/src/frontend/windows/resources.rc index 2fe3bc9c6..e60a04fb7 100644 --- a/desmume/src/frontend/windows/resources.rc +++ b/desmume/src/frontend/windows/resources.rc @@ -1591,6 +1591,17 @@ BEGIN RTEXT "Decrease",-1,81,40,44,8 END +IDD_GBASLOT_HCV1000 DIALOGEX 7, 48, 302, 109 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_HCVBARCODE,129,42,72,14,ES_AUTOHSCROLL + CONTROL " ",IDC_HCVSCAN,"InputCustomGuitar",WS_TABSTOP,129,24,71,12,WS_EX_CLIENTEDGE + RTEXT "Scan key",-1,80,27,46,8 + LTEXT "Card reader",-1,137,8,53,15 + RTEXT "Barcode",-1,79,46,46,8 +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/desmume/src/slot2.cpp b/desmume/src/slot2.cpp index 4640b5a0b..a947fe7b6 100644 --- a/desmume/src/slot2.cpp +++ b/desmume/src/slot2.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2015 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -58,6 +58,7 @@ void slot2_Init() extern TISlot2InterfaceConstructor construct_Slot2_EasyPiano; extern TISlot2InterfaceConstructor construct_Slot2_Paddle; extern TISlot2InterfaceConstructor construct_Slot2_PassME; + extern TISlot2InterfaceConstructor construct_Slot2_HCV1000; slot2_List[NDS_SLOT2_NONE] = construct_Slot2_None(); slot2_List[NDS_SLOT2_AUTO] = construct_Slot2_Auto(); @@ -69,6 +70,7 @@ void slot2_Init() slot2_List[NDS_SLOT2_EASYPIANO] = construct_Slot2_EasyPiano(); slot2_List[NDS_SLOT2_PADDLE] = construct_Slot2_Paddle(); slot2_List[NDS_SLOT2_PASSME] = construct_Slot2_PassME(); + slot2_List[NDS_SLOT2_HCV1000] = construct_Slot2_HCV1000(); } @@ -252,6 +254,9 @@ NDS_SLOT2_TYPE slot2_DetermineTypeByGameCode(const char *theGameCode) {"CV8", NDS_SLOT2_PADDLE}, // Space Invaders Extreme 2 {"AMH", NDS_SLOT2_RUMBLEPAK}, // Metroid Prime Hunters {"AP2", NDS_SLOT2_RUMBLEPAK}, // Metroid Prime Pinball + {"C4A", NDS_SLOT2_HCV1000}, // Card de Asobu! Hajimete no DS + {"A6I", NDS_SLOT2_HCV1000}, // Kouchuu Ouja: Mushi King Super Collection + {"ALB", NDS_SLOT2_HCV1000}, // Oshare Majo Berry and Love }; for(size_t i = 0; i < ARRAY_SIZE(gameCodeDeviceTypes); i++) diff --git a/desmume/src/slot2.h b/desmume/src/slot2.h index dd015fe23..a50631629 100644 --- a/desmume/src/slot2.h +++ b/desmume/src/slot2.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2015 DeSmuME team + Copyright (C) 2009-2023 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -97,6 +97,7 @@ enum NDS_SLOT2_TYPE NDS_SLOT2_EASYPIANO, // 0x06 - Easy Piano NDS_SLOT2_PADDLE, // 0x07 - Arkanoids DS paddle NDS_SLOT2_PASSME, // 0x08 - PassME/Homebrew + NDS_SLOT2_HCV1000, // 0x09 - HCV-1000 Sega Card Reader NDS_SLOT2_COUNT // use for counter addons - MUST TO BE LAST!!! }; @@ -142,6 +143,7 @@ bool slot2_read(u32 addr, T &val); extern std::string GBACartridge_RomPath; extern std::string GBACartridge_SRAMPath; extern void (*FeedbackON)(bool enable); // feedback on/off +extern char hcv1000_data[16]; enum ADDON_CFLASH_MODE { @@ -157,4 +159,5 @@ void Paddle_SetValue(u16 theValue); extern void guitarGrip_setKey(bool green, bool red, bool yellow, bool blue); // Guitar grip keys extern void piano_setKey(bool c, bool cs, bool d, bool ds, bool e, bool f, bool fs, bool g, bool gs, bool a, bool as, bool b, bool hic); //piano keys +extern void HCV1000_setReady(); #endif //__SLOT_H__ From 8be30fe971ae5471554690e79381af8b2eed61c7 Mon Sep 17 00:00:00 2001 From: windwakr <284886+windwakr@users.noreply.github.com> Date: Sat, 7 Oct 2023 00:35:48 -0400 Subject: [PATCH 19/49] Slot2: Sega Card Reader fixes --- desmume/src/addons/slot2_hcv1000.cpp | 6 ++++++ desmume/src/frontend/windows/gbaslot_config.cpp | 14 +++++++------- desmume/src/frontend/windows/gbaslot_config.h | 3 ++- desmume/src/frontend/windows/main.cpp | 5 +++-- desmume/src/slot2.h | 2 +- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/desmume/src/addons/slot2_hcv1000.cpp b/desmume/src/addons/slot2_hcv1000.cpp index 8135fe003..5c8747bb1 100644 --- a/desmume/src/addons/slot2_hcv1000.cpp +++ b/desmume/src/addons/slot2_hcv1000.cpp @@ -79,3 +79,9 @@ void HCV1000_setReady() { hcv1000_cnt &= ~0x80; } + +void HCV1000_setBarcode(std::string barcode) +{ + barcode.resize(16, '_'); + memcpy(hcv1000_data, barcode.c_str(), barcode.length()); +} diff --git a/desmume/src/frontend/windows/gbaslot_config.cpp b/desmume/src/frontend/windows/gbaslot_config.cpp index 5797b67c9..9109eba18 100644 --- a/desmume/src/frontend/windows/gbaslot_config.cpp +++ b/desmume/src/frontend/windows/gbaslot_config.cpp @@ -36,7 +36,7 @@ u8 last_type = 0; char tmp_cflash_filename[MAX_PATH] = { 0 }; char tmp_cflash_path[MAX_PATH] = { 0 }; char tmp_gbagame_filename[MAX_PATH] = { 0 }; -TCHAR tmp_hcv1000_barcode[17] = { 0 }; +char tmp_hcv1000_barcode[17] = { 0 }; ADDON_CFLASH_MODE tmp_CFlashMode = ADDON_CFLASH_MODE_RomPath; HWND OKbutton = NULL; bool _OKbutton = false; @@ -50,7 +50,8 @@ SHCV1000 tmp_HCV1000; std::string win32_CFlash_cfgDirectory, win32_CFlash_cfgFileName; UINT win32_CFlash_cfgMode; std::string win32_GBA_cfgRomPath; -std::string win32_HCV1000_barcode; + +std::string slot2_HCV1000_barcode; INT_PTR CALLBACK GbaSlotNone(HWND dialog, UINT msg,WPARAM wparam,LPARAM lparam) { @@ -305,7 +306,7 @@ INT_PTR CALLBACK GbaSlotHCV1000(HWND dialog, UINT msg, WPARAM wparam, LPARAM lpa switch (LOWORD(wparam)) { case IDC_HCVBARCODE: - GetWindowText(GetDlgItem(dialog, IDC_HCVBARCODE), tmp_hcv1000_barcode, 16); + GetWindowText(GetDlgItem(dialog, IDC_HCVBARCODE), tmp_hcv1000_barcode, 17); return FALSE; } @@ -619,7 +620,7 @@ void GBAslotDialog(HWND hwnd) strcpy(tmp_cflash_filename, win32_CFlash_cfgFileName.c_str()); strcpy(tmp_cflash_path, win32_CFlash_cfgDirectory.c_str()); strcpy(tmp_gbagame_filename, win32_GBA_cfgRomPath.c_str()); - strcpy(tmp_hcv1000_barcode, win32_HCV1000_barcode.c_str()); + strcpy(tmp_hcv1000_barcode, slot2_HCV1000_barcode.c_str()); memcpy(&tmp_Guitar, &Guitar, sizeof(Guitar)); memcpy(&tmp_Piano, &Piano, sizeof(Piano)); memcpy(&tmp_Paddle, &Paddle, sizeof(Paddle)); @@ -689,10 +690,9 @@ void GBAslotDialog(HWND hwnd) case NDS_SLOT2_PASSME: break; case NDS_SLOT2_HCV1000: - win32_HCV1000_barcode = tmp_hcv1000_barcode; + slot2_HCV1000_barcode = tmp_hcv1000_barcode; memcpy(&HCV1000, &tmp_HCV1000, sizeof(tmp_HCV1000)); - memset(hcv1000_data, 0x5F, 16); - memcpy(hcv1000_data, win32_HCV1000_barcode.c_str(), (win32_HCV1000_barcode.length() <= 16) ? win32_HCV1000_barcode.length() : 16); + HCV1000_setBarcode(slot2_HCV1000_barcode); WritePrivateProfileString("Slot2.HCV1000", "barcode", tmp_hcv1000_barcode, IniName); WritePrivateProfileInt("Slot2.HCV1000", "scankey", HCV1000.SCANKEY, IniName); break; diff --git a/desmume/src/frontend/windows/gbaslot_config.h b/desmume/src/frontend/windows/gbaslot_config.h index f06140d7c..2516a5365 100644 --- a/desmume/src/frontend/windows/gbaslot_config.h +++ b/desmume/src/frontend/windows/gbaslot_config.h @@ -24,7 +24,8 @@ extern std::string win32_CFlash_cfgDirectory, win32_CFlash_cfgFileName; extern UINT win32_CFlash_cfgMode; extern std::string win32_GBA_cfgRomPath; -extern std::string win32_HCV1000_barcode; + +extern std::string slot2_HCV1000_barcode; extern void GBAslotDialog(HWND hwnd); diff --git a/desmume/src/frontend/windows/main.cpp b/desmume/src/frontend/windows/main.cpp index 052c4f5cb..5588ace62 100644 --- a/desmume/src/frontend/windows/main.cpp +++ b/desmume/src/frontend/windows/main.cpp @@ -2198,8 +2198,9 @@ int _main() win32_CFlash_cfgDirectory = GetPrivateProfileStdString("Slot2.CFlash", "path", ""); win32_CFlash_cfgFileName = GetPrivateProfileStdString("Slot2.CFlash", "filename", ""); win32_GBA_cfgRomPath = GetPrivateProfileStdString("Slot2.GBAgame", "filename", ""); - win32_HCV1000_barcode = GetPrivateProfileStdString("Slot2.HCV1000", "barcode", ""); - memcpy(hcv1000_data, win32_HCV1000_barcode.c_str(), (win32_HCV1000_barcode.length() <= 16) ? win32_HCV1000_barcode.length() : 16); + + slot2_HCV1000_barcode = GetPrivateProfileStdString("Slot2.HCV1000", "barcode", "").substr(0, 16); + HCV1000_setBarcode(slot2_HCV1000_barcode); cmdline.process_addonCommands(); WIN_InstallCFlash(); diff --git a/desmume/src/slot2.h b/desmume/src/slot2.h index a50631629..66f84f708 100644 --- a/desmume/src/slot2.h +++ b/desmume/src/slot2.h @@ -143,7 +143,6 @@ bool slot2_read(u32 addr, T &val); extern std::string GBACartridge_RomPath; extern std::string GBACartridge_SRAMPath; extern void (*FeedbackON)(bool enable); // feedback on/off -extern char hcv1000_data[16]; enum ADDON_CFLASH_MODE { @@ -160,4 +159,5 @@ void Paddle_SetValue(u16 theValue); extern void guitarGrip_setKey(bool green, bool red, bool yellow, bool blue); // Guitar grip keys extern void piano_setKey(bool c, bool cs, bool d, bool ds, bool e, bool f, bool fs, bool g, bool gs, bool a, bool as, bool b, bool hic); //piano keys extern void HCV1000_setReady(); +extern void HCV1000_setBarcode(std::string barcode); #endif //__SLOT_H__ From b06537cf51b5ad5dae70378e9fb995b9a4dcafc0 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 10 Oct 2023 13:45:07 -0700 Subject: [PATCH 20/49] Cocoa Port: Fix building on Cocoa port related to new files being added in commit 8be30fe. - Note that this commit ONLY fixes building, but DOES NOT actually add barcode reader support to the Cocoa port just yet. --- .../project.pbxproj | 24 +++++++++++++++++++ .../project.pbxproj | 16 +++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj index 172267841..f1b964a5a 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (Latest).xcodeproj/project.pbxproj @@ -2446,6 +2446,17 @@ AB8493C01B4E614D00CD1C73 /* Icon_VolumeOneThird_16x16@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AB8493AD1B4E614D00CD1C73 /* Icon_VolumeOneThird_16x16@2x.png */; }; AB8493C11B4E614D00CD1C73 /* Icon_VolumeTwoThird_16x16@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AB8493AE1B4E614D00CD1C73 /* Icon_VolumeTwoThird_16x16@2x.png */; }; AB8493C31B4E614D00CD1C73 /* Icon_VolumeTwoThird_16x16@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AB8493AE1B4E614D00CD1C73 /* Icon_VolumeTwoThird_16x16@2x.png */; }; + AB8800542AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB8800552AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB8800562AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB8800572AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB8800582AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB8800592AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB88005A2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB88005B2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB88005C2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB88005D2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; + AB88005E2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */; }; AB8967D916D2ED0700F826F1 /* DisplayWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8967D816D2ED0700F826F1 /* DisplayWindowController.mm */; }; AB8967DD16D2ED2700F826F1 /* DisplayWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB8967DB16D2ED2700F826F1 /* DisplayWindow.xib */; }; AB8B7AAC17CE8C440051CEBF /* slot1comp_protocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB8B7AAB17CE8C440051CEBF /* slot1comp_protocol.cpp */; }; @@ -4062,6 +4073,7 @@ AB8493AC1B4E614D00CD1C73 /* Icon_VolumeMute_16x16@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon_VolumeMute_16x16@2x.png"; path = "images/Icon_VolumeMute_16x16@2x.png"; sourceTree = ""; }; AB8493AD1B4E614D00CD1C73 /* Icon_VolumeOneThird_16x16@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon_VolumeOneThird_16x16@2x.png"; path = "images/Icon_VolumeOneThird_16x16@2x.png"; sourceTree = ""; }; AB8493AE1B4E614D00CD1C73 /* Icon_VolumeTwoThird_16x16@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon_VolumeTwoThird_16x16@2x.png"; path = "images/Icon_VolumeTwoThird_16x16@2x.png"; sourceTree = ""; }; + AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slot2_hcv1000.cpp; sourceTree = ""; }; AB8967D716D2ED0700F826F1 /* DisplayWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayWindowController.h; sourceTree = ""; }; AB8967D816D2ED0700F826F1 /* DisplayWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DisplayWindowController.mm; sourceTree = ""; }; AB8967DC16D2ED2700F826F1 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = translations/English.lproj/DisplayWindow.xib; sourceTree = ""; }; @@ -5765,6 +5777,7 @@ ABD1FF031345AC9B00AF11D1 /* slot2_expMemory.cpp */, ABD1FF041345AC9B00AF11D1 /* slot2_gbagame.cpp */, ABD1FF051345AC9B00AF11D1 /* slot2_guitarGrip.cpp */, + AB8800532AD5EC4F0090D47F /* slot2_hcv1000.cpp */, ABD1FF061345AC9B00AF11D1 /* slot2_mpcf.cpp */, ABD1FF071345AC9C00AF11D1 /* slot2_none.cpp */, ABD1FF081345AC9C00AF11D1 /* slot2_paddle.cpp */, @@ -8064,6 +8077,7 @@ 8C43E86627E3CD0100A35F65 /* ftfstype.c in Sources */, 8C43E86B27E3CD0100A35F65 /* macosx_10_5_compat.cpp in Sources */, 8C43E86C27E3CD0100A35F65 /* retro_dirent.c in Sources */, + AB8800562AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, 8C43E87427E3CD0100A35F65 /* slot2_passme.cpp in Sources */, 8C43E87727E3CD0100A35F65 /* psnames.c in Sources */, 8C43E87827E3CD0100A35F65 /* ftotval.c in Sources */, @@ -8128,6 +8142,7 @@ 8C43E92F27E3CD4C00A35F65 /* common.cpp in Sources */, 8C43E93027E3CD4C00A35F65 /* cp15.cpp in Sources */, 8C43E93127E3CD4C00A35F65 /* psaux.c in Sources */, + AB8800572AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, 8C43E93227E3CD4C00A35F65 /* cpu_detect_x86_gcc.cpp in Sources */, 8C43E93327E3CD4C00A35F65 /* crc.cpp in Sources */, 8C43E93427E3CD4C00A35F65 /* MacOGLDisplayView.mm in Sources */, @@ -8465,6 +8480,7 @@ 8CCD84DF27E40B730024BDD5 /* type1cid.c in Sources */, 8CCD84E427E40B730024BDD5 /* cocoa_slot2.mm in Sources */, 8CCD84E627E40B730024BDD5 /* ftbase.c in Sources */, + AB88005D2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, 8CCD84EA27E40B730024BDD5 /* fsnitro.cpp in Sources */, 8CCD84EB27E40B730024BDD5 /* macosx_10_5_compat.cpp in Sources */, 8CCD84EC27E40B730024BDD5 /* OGLRender_3_2.cpp in Sources */, @@ -8509,6 +8525,7 @@ AB36C7AF27F2C8AE00C763C8 /* decrypt.cpp in Sources */, AB36C7B027F2C8AE00C763C8 /* directory.cpp in Sources */, AB36C7B127F2C8AE00C763C8 /* Disassembler.cpp in Sources */, + AB88005A2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, AB36C7B227F2C8AE00C763C8 /* disc.cpp in Sources */, AB36C7B327F2C8AE00C763C8 /* dlditool.cpp in Sources */, AB36C7B427F2C8AE00C763C8 /* driver.cpp in Sources */, @@ -8884,6 +8901,7 @@ AB7900EF215B84E50082AE82 /* coreaudiosound.cpp in Sources */, AB7900F0215B84E50082AE82 /* ringbuffer.cpp in Sources */, AB7900F1215B84E50082AE82 /* arm_jit.cpp in Sources */, + AB8800582AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, AB7900F2215B84E50082AE82 /* smooth.c in Sources */, AB7900F3215B84E50082AE82 /* troubleshootingWindowDelegate.mm in Sources */, AB7900F4215B84E50082AE82 /* macOS_driver.cpp in Sources */, @@ -9000,6 +9018,7 @@ AB7901DD215B84F20082AE82 /* driver.cpp in Sources */, AB7901DE215B84F20082AE82 /* emufat.cpp in Sources */, AB7901DF215B84F20082AE82 /* type1cid.c in Sources */, + AB8800592AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, AB7901E0215B84F20082AE82 /* emufile.cpp in Sources */, AB7901E1215B84F20082AE82 /* fatdir.cpp in Sources */, AB7901E2215B84F20082AE82 /* fatfile.cpp in Sources */, @@ -9343,6 +9362,7 @@ AB796D6215CDCBA200C59155 /* coreaudiosound.cpp in Sources */, AB796D6315CDCBA200C59155 /* ringbuffer.cpp in Sources */, AB796D6415CDCBA200C59155 /* arm_jit.cpp in Sources */, + AB8800542AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, ABFEA8CA1BB4EC1100B08C25 /* smooth.c in Sources */, ABF2B9FB16904133000FF7C0 /* troubleshootingWindowDelegate.mm in Sources */, AB28625920AE3E9F00EAED43 /* macOS_driver.cpp in Sources */, @@ -9459,6 +9479,7 @@ AB8F3C871A53AC2600A80BF6 /* driver.cpp in Sources */, AB8F3C881A53AC2600A80BF6 /* emufat.cpp in Sources */, ABA7316A1BB51FDC00B26147 /* type1cid.c in Sources */, + AB8800552AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, AB8F3C891A53AC2600A80BF6 /* emufile.cpp in Sources */, AB8F3C8A1A53AC2600A80BF6 /* fatdir.cpp in Sources */, AB8F3C8B1A53AC2600A80BF6 /* fatfile.cpp in Sources */, @@ -9763,6 +9784,7 @@ AB2ABA461C9F9CFA00173B15 /* rthreads.c in Sources */, ABB3C6CB1501C04F00E0C22E /* rasterize.cpp in Sources */, ABB3C6CC1501C04F00E0C22E /* readwrite.cpp in Sources */, + AB88005E2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, AB49B553281687B90069F1D7 /* truetype.c in Sources */, ABB3C6CD1501C04F00E0C22E /* render3D.cpp in Sources */, ABB3C6CE1501C04F00E0C22E /* ROMReader.cpp in Sources */, @@ -9974,6 +9996,7 @@ ABC8594228273FEE00A03EA9 /* buffer.cpp in Sources */, ABC8594328273FEE00A03EA9 /* ftotval.c in Sources */, ABC8594428273FEE00A03EA9 /* compiler.cpp in Sources */, + AB88005B2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, ABC8594528273FEE00A03EA9 /* compilercontext.cpp in Sources */, ABC8594628273FEE00A03EA9 /* rthreads.c in Sources */, ABC8594728273FEE00A03EA9 /* macOS_driver.cpp in Sources */, @@ -10203,6 +10226,7 @@ ABD2CDF626E05CB000FB15F7 /* buffer.cpp in Sources */, ABD2CDF726E05CB000FB15F7 /* ftotval.c in Sources */, ABD2CDF826E05CB000FB15F7 /* compiler.cpp in Sources */, + AB88005C2AD5EC500090D47F /* slot2_hcv1000.cpp in Sources */, ABD2CDF926E05CB000FB15F7 /* compilercontext.cpp in Sources */, ABD2CDFA26E05CB000FB15F7 /* rthreads.c in Sources */, ABD2CDFB26E05CB000FB15F7 /* macOS_driver.cpp in Sources */, diff --git a/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj b/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj index 735f6235c..2454b2d97 100755 --- a/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj +++ b/desmume/src/frontend/cocoa/DeSmuME (XCode 3).xcodeproj/project.pbxproj @@ -266,6 +266,11 @@ AB142028186E2CD80015D52F /* Image_MemoryExpansionPak.png in Resources */ = {isa = PBXBuildFile; fileRef = AB142025186E2CD80015D52F /* Image_MemoryExpansionPak.png */; }; AB142029186E2CD80015D52F /* Image_MemoryExpansionPak.png in Resources */ = {isa = PBXBuildFile; fileRef = AB142025186E2CD80015D52F /* Image_MemoryExpansionPak.png */; }; AB14202A186E2CD80015D52F /* Image_MemoryExpansionPak.png in Resources */ = {isa = PBXBuildFile; fileRef = AB142025186E2CD80015D52F /* Image_MemoryExpansionPak.png */; }; + AB1B20AC2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B20AB2AD5ED59007CA7EB /* slot2_hcv1000.cpp */; }; + AB1B20AD2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B20AB2AD5ED59007CA7EB /* slot2_hcv1000.cpp */; }; + AB1B20AE2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B20AB2AD5ED59007CA7EB /* slot2_hcv1000.cpp */; }; + AB1B20AF2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B20AB2AD5ED59007CA7EB /* slot2_hcv1000.cpp */; }; + AB1B20B02AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB1B20AB2AD5ED59007CA7EB /* slot2_hcv1000.cpp */; }; AB1CC8001AA509C2008B0A16 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1CC7FF1AA509C2008B0A16 /* CoreAudio.framework */; }; AB1CC80A1AA509DF008B0A16 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1CC7FF1AA509C2008B0A16 /* CoreAudio.framework */; }; AB1CC80B1AA509E0008B0A16 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1CC7FF1AA509C2008B0A16 /* CoreAudio.framework */; }; @@ -1915,6 +1920,7 @@ AB0F29A514BE7213009ABC6F /* Icon_Speaker_420x420.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_Speaker_420x420.png; path = images/Icon_Speaker_420x420.png; sourceTree = ""; }; AB126D06182ECB9500EBCF22 /* slot2_passme.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slot2_passme.cpp; sourceTree = ""; }; AB142025186E2CD80015D52F /* Image_MemoryExpansionPak.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Image_MemoryExpansionPak.png; path = images/Image_MemoryExpansionPak.png; sourceTree = ""; }; + AB1B20AB2AD5ED59007CA7EB /* slot2_hcv1000.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slot2_hcv1000.cpp; sourceTree = ""; }; AB1CC7FF1AA509C2008B0A16 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; AB1CC8161AA50C8D008B0A16 /* Icon_MicrophoneBlack_256x256.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_MicrophoneBlack_256x256.png; path = images/Icon_MicrophoneBlack_256x256.png; sourceTree = ""; }; AB1CC8171AA50C8D008B0A16 /* Icon_MicrophoneBlueGlow_256x256.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon_MicrophoneBlueGlow_256x256.png; path = images/Icon_MicrophoneBlueGlow_256x256.png; sourceTree = ""; }; @@ -3511,6 +3517,7 @@ ABD1FF031345AC9B00AF11D1 /* slot2_expMemory.cpp */, ABD1FF041345AC9B00AF11D1 /* slot2_gbagame.cpp */, ABD1FF051345AC9B00AF11D1 /* slot2_guitarGrip.cpp */, + AB1B20AB2AD5ED59007CA7EB /* slot2_hcv1000.cpp */, ABD1FF061345AC9B00AF11D1 /* slot2_mpcf.cpp */, ABD1FF071345AC9C00AF11D1 /* slot2_none.cpp */, ABD1FF081345AC9C00AF11D1 /* slot2_paddle.cpp */, @@ -3886,7 +3893,7 @@ attributes = { ORGANIZATIONNAME = "DeSmuME Team"; }; - buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME (XCode 3)" */; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME (Xcode 3)" */; compatibilityVersion = "Xcode 3.1"; developmentRegion = English; hasScannedForEncodings = 1; @@ -4857,6 +4864,7 @@ ABD1267820AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A22217E47E400381363 /* WifiSettingsPanel.mm in Sources */, ABEBCE382A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, + AB1B20AD2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5052,6 +5060,7 @@ ABD1267A20AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A23217E47E400381363 /* WifiSettingsPanel.mm in Sources */, ABEBCE392A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, + AB1B20AE2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5277,6 +5286,7 @@ ABD1267620AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A21217E47E400381363 /* WifiSettingsPanel.mm in Sources */, ABEBCE372A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, + AB1B20AC2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5502,6 +5512,7 @@ ABD1267E20AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A25217E47E400381363 /* WifiSettingsPanel.mm in Sources */, ABEBCE3B2A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, + AB1B20B02AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5697,6 +5708,7 @@ ABD1267C20AE812900EFE1B2 /* macOS_driver.cpp in Sources */, AB4B5A24217E47E400381363 /* WifiSettingsPanel.mm in Sources */, ABEBCE3A2A703E260028CE8A /* CheatDatabaseWindowController.mm in Sources */, + AB1B20AF2AD5ED59007CA7EB /* slot2_hcv1000.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6041,7 +6053,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME (XCode 3)" */ = { + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME (Xcode 3)" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4F08A954540054247B /* Debug */, From f2cfd23ef20e0b43dbcb4ac17d080ea8e072dc1a Mon Sep 17 00:00:00 2001 From: Max Fedotov Date: Thu, 25 Jan 2024 17:28:46 +0300 Subject: [PATCH 21/49] gtk: implement GPU scale factor feature (#764) * [WIP] gtk: implement GPU scale factor feature * Replace combobox with spin button, fix taking screenshot * Fix distorted image, add some checks for scale factor value * Make OSD at least properly visible --- desmume/src/frontend/posix/gtk/config.cpp | 18 ++++++ desmume/src/frontend/posix/gtk/config_opts.h | 1 + desmume/src/frontend/posix/gtk/graphics.ui | 29 ++++++++-- desmume/src/frontend/posix/gtk/main.cpp | 61 ++++++++++++++++---- desmume/src/frontend/posix/gtk/sdl_3Demu.cpp | 6 +- 5 files changed, 98 insertions(+), 17 deletions(-) diff --git a/desmume/src/frontend/posix/gtk/config.cpp b/desmume/src/frontend/posix/gtk/config.cpp index eceb2f06b..a0e593a5b 100644 --- a/desmume/src/frontend/posix/gtk/config.cpp +++ b/desmume/src/frontend/posix/gtk/config.cpp @@ -63,6 +63,24 @@ void value::save() { g_key_file_set_integer(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData); } +/*class value */ + +template<> +void value::load() { + GError* err = NULL; + float val = g_key_file_get_double(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), &err); + if (err != NULL) { + g_error_free(err); + } else { + this->mData = val; + } +} + +template<> +void value::save() { + g_key_file_set_double(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData); +} + /* class value */ template<> diff --git a/desmume/src/frontend/posix/gtk/config_opts.h b/desmume/src/frontend/posix/gtk/config_opts.h index 151d0f874..7481ab634 100644 --- a/desmume/src/frontend/posix/gtk/config_opts.h +++ b/desmume/src/frontend/posix/gtk/config_opts.h @@ -60,6 +60,7 @@ OPT(core3D, int, 1, Config, Core3D) OPT(textureDeposterize, bool, false, Config, 3DTextureDeposterization) OPT(textureSmoothing, bool, false, Config, 3DTextureSmoothing) OPT(textureUpscale, int, 1, Config, 3DTextureUpscaling) +OPT(gpuScaleFactor, float, 1.0, Config, GPUScaleFactor) OPT(highColorInterpolation, bool, true, Config, HighResolutionColorInterpolation) OPT(multisampling, bool, false, Config, OpenGLMultisampling) OPT(multisamplingSize, int, 0, Config, OpenGLMultisamplingSize) diff --git a/desmume/src/frontend/posix/gtk/graphics.ui b/desmume/src/frontend/posix/gtk/graphics.ui index 44eed71fc..f8dc2976b 100644 --- a/desmume/src/frontend/posix/gtk/graphics.ui +++ b/desmume/src/frontend/posix/gtk/graphics.ui @@ -94,6 +94,25 @@ 1 + + + GPU scale factor: + + + 0 + 2 + + + + + true + 0 + + + 1 + 2 + + 3D Texture Deposterization @@ -101,7 +120,7 @@ 0 - 2 + 3 @@ -111,7 +130,7 @@ 0 - 3 + 4 @@ -121,7 +140,7 @@ 1 - 3 + 4 @@ -130,7 +149,7 @@ 0 - 4 + 5 @@ -146,7 +165,7 @@ 1 - 4 + 5 diff --git a/desmume/src/frontend/posix/gtk/main.cpp b/desmume/src/frontend/posix/gtk/main.cpp index 2cecb5313..1bf5bd492 100644 --- a/desmume/src/frontend/posix/gtk/main.cpp +++ b/desmume/src/frontend/posix/gtk/main.cpp @@ -99,6 +99,14 @@ static int draw_count; extern int _scanline_filter_a, _scanline_filter_b, _scanline_filter_c, _scanline_filter_d; VideoFilter* video; +#define GPU_SCALE_FACTOR_MIN 1.0f +#define GPU_SCALE_FACTOR_MAX 10.0f + +float gpu_scale_factor = 1.0f; +int real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH; +int real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT; + + desmume::config::Config config; #ifdef GDB_STUB @@ -1310,7 +1318,8 @@ static int ConfigureDrawingArea(GtkWidget *widget, GdkEventConfigure *event, gpo static inline void gpu_screen_to_rgb(u32* dst) { - ColorspaceConvertBuffer555To8888Opaque(GPU->GetDisplayInfo().masterNativeBuffer16, dst, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2); + ColorspaceConvertBuffer555To8888Opaque(GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16, + dst, real_framebuffer_width * real_framebuffer_height * 2); } static inline void drawScreen(cairo_t* cr, u32* buf, gint w, gint h) { @@ -1384,7 +1393,7 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo gint dstW = video->GetDstWidth(); gint dstH = video->GetDstHeight(); - gint dstScale = dstW * 2 / 256; // Actual scale * 2 to handle 1.5x filters + gint dstScale = dstW * 2 / GPU_FRAMEBUFFER_NATIVE_WIDTH; // Actual scale * 2 to handle 1.5x filters gint gap = nds_screen.orientation == ORIENT_VERTICAL ? nds_screen.gap_size * dstScale / 2 : 0; gint imgW, imgH; @@ -1436,9 +1445,11 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo } static void RedrawScreen() { - ColorspaceConvertBuffer555To8888Opaque(GPU->GetDisplayInfo().masterNativeBuffer16, (uint32_t *)video->GetSrcBufferPtr(), GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2); + ColorspaceConvertBuffer555To8888Opaque( + GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16, + (uint32_t *)video->GetSrcBufferPtr(), real_framebuffer_width * real_framebuffer_height * 2); #ifdef HAVE_LIBAGG - aggDraw.hud->attach((u8*)video->GetSrcBufferPtr(), 256, 384, 1024); + aggDraw.hud->attach((u8*)video->GetSrcBufferPtr(), real_framebuffer_width, real_framebuffer_height * 2, 1024 * gpu_scale_factor); osd->update(); DrawHUD(); osd->clear(); @@ -1989,12 +2000,16 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g GtkGrid *wGrid; GtkComboBox *coreCombo, *wScale, *wMultisample; GtkToggleButton *wPosterize, *wSmoothing, *wHCInterpolate; + GtkSpinButton *wGPUScale; GtkBuilder *builder = gtk_builder_new_from_resource("/org/desmume/DeSmuME/graphics.ui"); dialog = GTK_DIALOG(gtk_builder_get_object(builder, "dialog")); wGrid = GTK_GRID(gtk_builder_get_object(builder, "graphics_grid")); coreCombo = GTK_COMBO_BOX(gtk_builder_get_object(builder, "core_combo")); wScale = GTK_COMBO_BOX(gtk_builder_get_object(builder, "scale")); + wGPUScale = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "gpuscale")); + gtk_spin_button_set_range(wGPUScale, GPU_SCALE_FACTOR_MIN, GPU_SCALE_FACTOR_MAX); + gtk_spin_button_set_increments(wGPUScale, 1.0, 1.0); wMultisample = GTK_COMBO_BOX(gtk_builder_get_object(builder, "multisample")); wPosterize = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "posterize")); wSmoothing = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "smoothing")); @@ -2010,6 +2025,9 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g // The shift it work for scale up to 4. For scaling more than 4, a mapping function is required gtk_combo_box_set_active(wScale, CommonSettings.GFX3D_Renderer_TextureScalingFactor >> 1); + //GPU scaling factor + gtk_spin_button_set_value(wGPUScale, gpu_scale_factor); + // 3D Texture Deposterization gtk_toggle_button_set_active(wPosterize, CommonSettings.GFX3D_Renderer_TextureDeposterize); @@ -2080,6 +2098,17 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g default: break; } + gpu_scale_factor = gtk_spin_button_get_value(wGPUScale); + if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) + gpu_scale_factor = GPU_SCALE_FACTOR_MIN; + if(gpu_scale_factor > GPU_SCALE_FACTOR_MAX) + gpu_scale_factor = GPU_SCALE_FACTOR_MAX; + gtk_spin_button_set_value(wGPUScale, gpu_scale_factor); + config.gpuScaleFactor = gpu_scale_factor; + real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor; + real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor; + GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); + video->SetSourceSize(real_framebuffer_width, real_framebuffer_height * 2); CommonSettings.GFX3D_Renderer_TextureDeposterize = config.textureDeposterize = gtk_toggle_button_get_active(wPosterize); CommonSettings.GFX3D_Renderer_TextureSmoothing = config.textureSmoothing = gtk_toggle_button_get_active(wSmoothing); CommonSettings.GFX3D_Renderer_TextureScalingFactor = config.textureUpscale = scale; @@ -2140,7 +2169,7 @@ static void Printscreen(GSimpleAction *action, GVariant *parameter, gpointer use const gchar *dir; gchar *filename = NULL, *filen = NULL; GError *error = NULL; - u8 rgb[256 * 384 * 4]; + u8 *rgb = (u8*)malloc(real_framebuffer_width * real_framebuffer_height * 2 * 4); static int seq = 0; gint H, W; @@ -2149,11 +2178,11 @@ static void Printscreen(GSimpleAction *action, GVariant *parameter, gpointer use // return; if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) { - W = screen_size[nds_screen.orientation].width; - H = screen_size[nds_screen.orientation].height; + W = real_framebuffer_width; + H = real_framebuffer_height * 2; } else { - W = screen_size[nds_screen.orientation].height; - H = screen_size[nds_screen.orientation].width; + W = real_framebuffer_height * 2; + H = real_framebuffer_width; } gpu_screen_to_rgb((u32*)rgb); @@ -2190,7 +2219,7 @@ static void Printscreen(GSimpleAction *action, GVariant *parameter, gpointer use seq--; } - //free(rgb); + free(rgb); g_object_unref(screenshot); g_free(filename); g_free(filen); @@ -3026,8 +3055,18 @@ common_gtk_main(GApplication *app, gpointer user_data) memset(&nds_screen, 0, sizeof(nds_screen)); nds_screen.orientation = ORIENT_VERTICAL; + gpu_scale_factor = config.gpuScaleFactor; + if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) + gpu_scale_factor = GPU_SCALE_FACTOR_MIN; + if(gpu_scale_factor > GPU_SCALE_FACTOR_MAX) + gpu_scale_factor = GPU_SCALE_FACTOR_MAX; + config.gpuScaleFactor = gpu_scale_factor; + real_framebuffer_width = GPU_FRAMEBUFFER_NATIVE_WIDTH * gpu_scale_factor; + real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor; + g_printerr("Using %d threads for video filter.\n", CommonSettings.num_cores); - video = new VideoFilter(256, 384, VideoFilterTypeID_None, CommonSettings.num_cores); + GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); + video = new VideoFilter(real_framebuffer_width, real_framebuffer_height * 2, VideoFilterTypeID_None, CommonSettings.num_cores); /* Fetch the main elements from the window */ GtkBuilder *builder = gtk_builder_new_from_resource("/org/desmume/DeSmuME/main.ui"); diff --git a/desmume/src/frontend/posix/gtk/sdl_3Demu.cpp b/desmume/src/frontend/posix/gtk/sdl_3Demu.cpp index fb05b157c..39c5d0d57 100644 --- a/desmume/src/frontend/posix/gtk/sdl_3Demu.cpp +++ b/desmume/src/frontend/posix/gtk/sdl_3Demu.cpp @@ -28,6 +28,9 @@ static bool sdl_init(void) { return is_sdl_initialized(); } static SDL_Window *win = NULL; static SDL_GLContext ctx = NULL; +extern int real_framebuffer_width; +extern int real_framebuffer_height; + bool deinit_sdl_3Demu(void) { bool ret = false; @@ -60,7 +63,8 @@ bool init_sdl_3Demu(void) SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - win = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 256, 192, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); + win = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, real_framebuffer_width, + real_framebuffer_height, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); if (!win) { fprintf(stderr, "SDL: Failed to create a window: %s\n", SDL_GetError()); return false; From 6508c2b115f954afece4243e36e9e35e1d459ea8 Mon Sep 17 00:00:00 2001 From: zeromus Date: Thu, 1 Feb 2024 04:26:27 -0500 Subject: [PATCH 22/49] placate -Werror=format-security (probably) (re: #768) --- desmume/src/commandline.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desmume/src/commandline.cpp b/desmume/src/commandline.cpp index cb6c23ac4..4c7bcc4a0 100644 --- a/desmume/src/commandline.cpp +++ b/desmume/src/commandline.cpp @@ -397,7 +397,7 @@ bool CommandLine::parse(int argc,char **argv) if(opt_help) { - printf(help_string); + printf("%s",help_string); exit(1); } @@ -571,7 +571,7 @@ bool CommandLine::validate() void CommandLine::errorHelp(const char* binName) { - printerror(help_string); + printerror("%s",help_string); } void CommandLine::process_movieCommands() From 45738beb88323248ba21817d6a81b51cf9e8fd9f Mon Sep 17 00:00:00 2001 From: Max Fedotov Date: Wed, 14 Feb 2024 11:20:57 +0300 Subject: [PATCH 23/49] GTK: make OSD scalable (#769) * gtk: make OSD scalable * Scale save slot indicator (oops), make text outlines look smoother, use larger font when not scaling * Save and load HUD layout, prefer raster font on low resolution, select vector font size close to raster one, make OSDCLASS::scale floating point * Build fix * Add reset HUD layout action, only require fontconfig if libagg is found. * Try another font in case we could not locate monospace * Detect screen bytes per pixel instead of hardcoding it, define AGG2D_USE_VECTORFONTS if fontconfig is found. * Different pixel formats are handled by different draw target implementations --- .../src/frontend/modules/osd/agg/agg2d.inl | 15 +- .../src/frontend/modules/osd/agg/agg_osd.cpp | 253 ++++++++++++------ .../src/frontend/modules/osd/agg/agg_osd.h | 9 +- .../src/frontend/modules/osd/agg/aggdraw.cpp | 47 +++- .../src/frontend/modules/osd/agg/aggdraw.h | 65 ++++- desmume/src/frontend/posix/gtk/config.cpp | 19 ++ desmume/src/frontend/posix/gtk/config_opts.h | 1 + desmume/src/frontend/posix/gtk/main.cpp | 172 +++++++++++- desmume/src/frontend/posix/gtk/menu.ui | 4 + desmume/src/frontend/posix/meson.build | 6 + 10 files changed, 470 insertions(+), 121 deletions(-) diff --git a/desmume/src/frontend/modules/osd/agg/agg2d.inl b/desmume/src/frontend/modules/osd/agg/agg2d.inl index 756d193b9..2f4ee6a5d 100644 --- a/desmume/src/frontend/modules/osd/agg/agg2d.inl +++ b/desmume/src/frontend/modules/osd/agg/agg2d.inl @@ -1370,6 +1370,17 @@ AGG2D_TEMPLATE void TAGG2D::text(double x, double y, const wchar_t* str, unsigne } } + +AGG2D_TEMPLATE double TAGG2D::textWidth(const char* str) +{ + return textWidth(str, (unsigned int)strlen(str)); +} + +AGG2D_TEMPLATE void TAGG2D::text(double x, double y, const char* str, bool roundOff, double dx, double dy) +{ + text(x, y, str, (unsigned int)strlen(str), roundOff, dx, dy); +} + #endif //------------------------------------------------------------------------ @@ -1945,11 +1956,11 @@ AGG2D_TEMPLATE void TAGG2D::render(FontRasterizer& ras, FontScanline& sl) { if(m_blendMode == BlendAlpha) { - Agg2DRenderer::render(*this, m_renBase, m_renSolid, ras, sl); + Agg2DRenderer::render(*this, m_renBase, m_renSolid, ras, sl); } else { - Agg2DRenderer::render(*this, m_renBaseComp, m_renSolidComp, ras, sl); + Agg2DRenderer::render(*this, m_renBaseComp, m_renSolidComp, ras, sl); } } diff --git a/desmume/src/frontend/modules/osd/agg/agg_osd.cpp b/desmume/src/frontend/modules/osd/agg/agg_osd.cpp index 06332ddab..5534ad0ab 100644 --- a/desmume/src/frontend/modules/osd/agg/agg_osd.cpp +++ b/desmume/src/frontend/modules/osd/agg/agg_osd.cpp @@ -50,13 +50,23 @@ static s64 hudTimer; static void SetHudDummy (HudCoordinates *hud) { - hud->x=666; - hud->y=666; + hud->x=-666; + hud->y=-666; } static bool IsHudDummy (HudCoordinates *hud) { - return (hud->x == 666 && hud->y == 666); + return (hud->x == -666 && hud->y == -666); +} + +static int ScreenWidth() +{ + return 256*osd->scale; +} + +static int ScreenHeight() +{ + return 192*osd->scale; } template @@ -64,21 +74,47 @@ static T calcY(T y) // alters a GUI element y coordinate as necessary to obey sw { if(osd->singleScreen) { - if(y >= 192) - y -= 192; + if(y >= ScreenHeight()) + y -= ScreenHeight(); if(osd->swapScreens) - y += 192; + y += ScreenHeight(); } else if(osd->swapScreens) { - if(y >= 192) - y -= 192; + if(y >= ScreenHeight()) + y -= ScreenHeight(); else - y += 192; + y += ScreenHeight(); } return y; } +static void RenderTextAutoVector(double x, double y, const std::string& str, bool shadow = true, double shadowOffset = 1.0) +{ +#ifdef AGG2D_USE_VECTORFONTS + bool render_vect = false; + if(osd) + if(osd->useVectorFonts) + render_vect = true; + if(render_vect) + { + if(shadow) + aggDraw.hud->renderVectorFontTextDropshadowed(x, y, str, shadowOffset); + else + aggDraw.hud->renderVectorFontText(x, y, str); + } + else + { +#endif + if(shadow) + aggDraw.hud->renderTextDropshadowed(x, y, str); + else + aggDraw.hud->renderText(x, y, str); +#ifdef AGG2D_USE_VECTORFONTS + } +#endif +} + void EditHud(s32 x, s32 y, HudStruct *hudstruct) { u32 i = 0; @@ -108,8 +144,10 @@ void EditHud(s32 x, s32 y, HudStruct *hudstruct) { //sanity checks if(hud.x < 0) hud.x = 0; if(hud.y < 0) hud.y = 0; - if(hud.x > 245)hud.x = 245; //margins - if(hud.y > 384-16)hud.y = 384-16; + if(hud.x > ScreenWidth()-11*osd->scale) + hud.x = ScreenWidth()-11*osd->scale; //margins + if(hud.y > ScreenHeight()*2-16*osd->scale) + hud.y = ScreenHeight()*2-16*osd->scale; if(hud.clicked) { @@ -136,45 +174,47 @@ void HudClickRelease(HudStruct *hudstruct) { void HudStruct::reset() { + double sc=(osd ? osd->scale : 1.0); + FpsDisplay.x=0; - FpsDisplay.y=5; - FpsDisplay.xsize=166; - FpsDisplay.ysize=10; + FpsDisplay.y=5*sc; + FpsDisplay.xsize=166*sc; + FpsDisplay.ysize=10*sc; FrameCounter.x=0; - FrameCounter.y=25; - FrameCounter.xsize=60; - FrameCounter.ysize=10; + FrameCounter.y=25*sc; + FrameCounter.xsize=60*sc; + FrameCounter.ysize=10*sc; InputDisplay.x=0; - InputDisplay.y=45; - InputDisplay.xsize=220; - InputDisplay.ysize=10; + InputDisplay.y=45*sc; + InputDisplay.xsize=220*sc; + InputDisplay.ysize=10*sc; - GraphicalInputDisplay.x=8; - GraphicalInputDisplay.y=328; - GraphicalInputDisplay.xsize=102; - GraphicalInputDisplay.ysize=50; + GraphicalInputDisplay.x=8*sc; + GraphicalInputDisplay.y=328*sc; + GraphicalInputDisplay.xsize=102*sc; + GraphicalInputDisplay.ysize=50*sc; LagFrameCounter.x=0; - LagFrameCounter.y=65; - LagFrameCounter.xsize=30; - LagFrameCounter.ysize=10; + LagFrameCounter.y=65*sc; + LagFrameCounter.xsize=30*sc; + LagFrameCounter.ysize=10*sc; Microphone.x=0; - Microphone.y=85; - Microphone.xsize=20; - Microphone.ysize=10; + Microphone.y=85*sc; + Microphone.xsize=20*sc; + Microphone.ysize=10*sc; RTCDisplay.x=0; - RTCDisplay.y=105; - RTCDisplay.xsize=220; - RTCDisplay.ysize=10; + RTCDisplay.y=105*sc; + RTCDisplay.xsize=220*sc; + RTCDisplay.ysize=10*sc; - SavestateSlots.x = 8; - SavestateSlots.y = 160; - SavestateSlots.xsize = 240; - SavestateSlots.ysize = 24; + SavestateSlots.x = 8*sc; + SavestateSlots.y = 160*sc; + SavestateSlots.xsize = 240*sc; + SavestateSlots.ysize = 24*sc; #ifdef _MSC_VER #define AGG_OSD_SETTING(which,comp) which.comp = GetPrivateProfileInt("HudEdit", #which "." #comp, which.comp, IniName); @@ -186,6 +226,51 @@ void HudStruct::reset() clicked = false; } +void HudStruct::rescale(double oldScale, double newScale) +{ + double sc=newScale/oldScale; + + FpsDisplay.x*=sc; + FpsDisplay.y*=sc; + FpsDisplay.xsize*=sc; + FpsDisplay.ysize*=sc; + + FrameCounter.x*=sc; + FrameCounter.y*=sc; + FrameCounter.xsize*=sc; + FrameCounter.ysize*=sc; + + InputDisplay.x*=sc; + InputDisplay.y*=sc; + InputDisplay.xsize*=sc; + InputDisplay.ysize*=sc; + + GraphicalInputDisplay.x*=sc; + GraphicalInputDisplay.y*=sc; + GraphicalInputDisplay.xsize*=sc; + GraphicalInputDisplay.ysize*=sc; + + LagFrameCounter.x*=sc; + LagFrameCounter.y*=sc; + LagFrameCounter.xsize*=sc; + LagFrameCounter.ysize*=sc; + + Microphone.x*=sc; + Microphone.y*=sc; + Microphone.xsize*=sc; + Microphone.ysize*=sc; + + RTCDisplay.x*=sc; + RTCDisplay.y*=sc; + RTCDisplay.xsize*=sc; + RTCDisplay.ysize*=sc; + + SavestateSlots.x*=sc; + SavestateSlots.y*=sc; + SavestateSlots.xsize*=sc; + SavestateSlots.ysize*=sc; +} + static void joyFill(int n) { bool pressedForGame = NDS_getFinalUserInput().buttons.array[n]; @@ -235,8 +320,8 @@ static void drawPad(double x, double y, double ratio) { // aligning to odd half-pixel boundaries prevents agg2d from blurring thin straight lines x = floor(x) + 0.5; y = floor(calcY(y)) + 0.5; - double xc = 41 - 0.5; - double yc = 20 - 0.5; + double xc = 41*osd->scale - 0.5; + double yc = 20*osd->scale - 0.5; aggDraw.hud->lineColor(128,128,128,255); @@ -252,12 +337,12 @@ static void drawPad(double x, double y, double ratio) { aggDraw.hud->roundedRect (screenLeft, screenTop, screenRight, screenBottom, 1); - joyEllipse(.89,.45,xc,yc,x,y,ratio,1,6);//B - joyEllipse(.89,.22,xc,yc,x,y,ratio,1,3);//X - joyEllipse(.83,.34,xc,yc,x,y,ratio,1,4);//Y - joyEllipse(.95,.34,xc,yc,x,y,ratio,1,5);//A - joyEllipse(.82,.716,xc,yc,x,y,ratio,.5,7);//Start - joyEllipse(.82,.842,xc,yc,x,y,ratio,.5,8);//Select + joyEllipse(.89,.45,xc,yc,x,y,ratio,osd->scale,6);//B + joyEllipse(.89,.22,xc,yc,x,y,ratio,osd->scale,3);//X + joyEllipse(.83,.34,xc,yc,x,y,ratio,osd->scale,4);//Y + joyEllipse(.95,.34,xc,yc,x,y,ratio,osd->scale,5);//A + joyEllipse(.82,.716,xc,yc,x,y,ratio,osd->scale * .5,7);//Start + joyEllipse(.82,.842,xc,yc,x,y,ratio,osd->scale * .5,8);//Select double dpadPoints [][2] = { @@ -311,29 +396,29 @@ static void drawPad(double x, double y, double ratio) { // touch pad { BOOL gameTouchOn = nds.isTouch; - double gameTouchX = screenLeft+1 + (nds.scr_touchX * 0.0625) * (screenRight - screenLeft - 2) / 256.0; - double gameTouchY = screenTop+1 + (nds.scr_touchY * 0.0625) * (screenBottom - screenTop - 2) / 192.0; + double gameTouchX = screenLeft+1 + (nds.scr_touchX * osd->scale * 0.0625) * (screenRight - screenLeft - 2) / (double)ScreenWidth(); + double gameTouchY = screenTop+1 + (nds.scr_touchY * osd->scale * 0.0625) * (screenBottom - screenTop - 2) / (double)ScreenHeight(); bool physicalTouchOn = NDS_getRawUserInput().touch.isTouch; - double physicalTouchX = screenLeft+1 + (NDS_getRawUserInput().touch.touchX * 0.0625) * (screenRight - screenLeft - 2) / 256.0; - double physicalTouchY = screenTop+1 + (NDS_getRawUserInput().touch.touchY * 0.0625) * (screenBottom - screenTop - 2) / 192.0; + double physicalTouchX = screenLeft+1 + (NDS_getRawUserInput().touch.touchX * osd->scale * 0.0625) * (screenRight - screenLeft - 2) / (double)ScreenWidth(); + double physicalTouchY = screenTop+1 + (NDS_getRawUserInput().touch.touchY * osd->scale * 0.0625) * (screenBottom - screenTop - 2) / (double)ScreenHeight(); if(gameTouchOn && physicalTouchOn && gameTouchX == physicalTouchX && gameTouchY == physicalTouchY) { aggDraw.hud->fillColor(0,0,0,255); - aggDraw.hud->ellipse(gameTouchX, gameTouchY, ratio*0.37, ratio*0.37); + aggDraw.hud->ellipse(gameTouchX, gameTouchY, osd->scale*ratio*0.37, osd->scale*ratio*0.37); } else { if(physicalTouchOn) { aggDraw.hud->fillColor(0,0,0,128); - aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, ratio*0.5, ratio*0.5); + aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, osd->scale*ratio*0.5, osd->scale*ratio*0.5); aggDraw.hud->fillColor(0,255,0,255); - aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, ratio*0.37, ratio*0.37); + aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, osd->scale*ratio*0.37, osd->scale*ratio*0.37); } if(gameTouchOn) { aggDraw.hud->fillColor(255,0,0,255); - aggDraw.hud->ellipse(gameTouchX, gameTouchY, ratio*0.37, ratio*0.37); + aggDraw.hud->ellipse(gameTouchX, gameTouchY, osd->scale*ratio*0.37, osd->scale*ratio*0.37); } } } @@ -379,8 +464,8 @@ static void TextualInputDisplay() { // cast from char to std::string is a bit awkward std::string str(buttonChars+i, 2); str[1] = '\0'; - - aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y), str); + + RenderTextAutoVector(x, calcY(Hud.InputDisplay.y), str, true, osd ? osd->scale : 1); } // touch pad @@ -396,7 +481,7 @@ static void TextualInputDisplay() { { sprintf(str, "%d,%d", gameTouchX, gameTouchY); aggDraw.hud->lineColor(255,255,255,255); - aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y), str); + RenderTextAutoVector(x, calcY(Hud.InputDisplay.y), str, true, osd ? osd->scale : 1); } else { @@ -404,13 +489,13 @@ static void TextualInputDisplay() { { sprintf(str, "%d,%d", gameTouchX, gameTouchY); aggDraw.hud->lineColor(255,48,48,255); - aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y)-(physicalTouchOn?8:0), str); + RenderTextAutoVector(x, calcY(Hud.InputDisplay.y)-(physicalTouchOn?8:0), str, true, osd ? osd->scale : 1); } if(physicalTouchOn) { sprintf(str, "%d,%d", physicalTouchX, physicalTouchY); aggDraw.hud->lineColor(0,192,0,255); - aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y)+(gameTouchOn?8:0), str); + RenderTextAutoVector(x, calcY(Hud.InputDisplay.y)+(gameTouchOn?8:0), str, true, osd ? osd->scale : 1); } } } @@ -418,10 +503,10 @@ static void TextualInputDisplay() { static void OSD_HandleTouchDisplay() { // note: calcY should not be used in this function. - aggDraw.hud->lineWidth(1.0); + aggDraw.hud->lineWidth(osd->scale); - temptouch.X = NDS_getRawUserInput().touch.touchX >> 4; - temptouch.Y = NDS_getRawUserInput().touch.touchY >> 4; + temptouch.X = (NDS_getRawUserInput().touch.touchX >> 4) * osd->scale; + temptouch.Y = (NDS_getRawUserInput().touch.touchY >> 4) * osd->scale; if(touchshadow) { @@ -432,27 +517,27 @@ static void OSD_HandleTouchDisplay() { temptouch = touch[i]; if(temptouch.X != 0 || temptouch.Y != 0) { aggDraw.hud->lineColor(0, 255, 0, touchalpha[i]); - aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz - aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert + aggDraw.hud->line(temptouch.X - ScreenWidth(), temptouch.Y + ScreenHeight(), temptouch.X + ScreenWidth(), temptouch.Y + ScreenHeight()); //horiz + aggDraw.hud->line(temptouch.X, temptouch.Y - ScreenWidth(), temptouch.X, temptouch.Y + ScreenHeight()*2); //vert aggDraw.hud->fillColor(0, 0, 0, touchalpha[i]); - aggDraw.hud->rectangle(temptouch.X-1, temptouch.Y + 192-1, temptouch.X+1, temptouch.Y + 192+1); + aggDraw.hud->rectangle(temptouch.X-1, temptouch.Y + ScreenHeight()-1, temptouch.X+1, temptouch.Y + ScreenHeight()+1); } } } else if(NDS_getRawUserInput().touch.isTouch) { aggDraw.hud->lineColor(0, 255, 0, 128); - aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz - aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert + aggDraw.hud->line(temptouch.X - ScreenWidth(), temptouch.Y + ScreenHeight(), temptouch.X + ScreenWidth(), temptouch.Y + ScreenHeight()); //horiz + aggDraw.hud->line(temptouch.X, temptouch.Y - ScreenWidth(), temptouch.X, temptouch.Y + ScreenHeight()*2); //vert } if(nds.isTouch) { - temptouch.X = nds.scr_touchX / 16; - temptouch.Y = nds.scr_touchY / 16; + temptouch.X = nds.scr_touchX / 16 * osd->scale; + temptouch.Y = nds.scr_touchY / 16 * osd->scale; aggDraw.hud->lineColor(255, 0, 0, 128); - aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz - aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert + aggDraw.hud->line(temptouch.X - ScreenWidth(), temptouch.Y + ScreenHeight(), temptouch.X + ScreenWidth(), temptouch.Y + ScreenHeight()); //horiz + aggDraw.hud->line(temptouch.X, temptouch.Y - ScreenWidth(), temptouch.X, temptouch.Y + ScreenHeight()*2); //vert } } @@ -476,24 +561,24 @@ static void DrawStateSlots(){ if(alpha!=0) { - aggDraw.hud->lineWidth(1.0); + aggDraw.hud->lineWidth(osd->scale); aggDraw.hud->lineColor(0, 0, 0, alpha); aggDraw.hud->fillColor(255, 255, 255, alpha); - for ( int i = 0, xpos=0; i < 10; xpos=xpos+24) { + for ( int i = 0, xpos=0; i < 10; xpos=xpos+24*osd->scale) { int yheight=0; - aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, xloc + 22 + xpos, yloc + 20 + yheight+20, agg::rgba8(100,200,255,alpha), agg::rgba8(255,255,255,0)); + aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, xloc + 22*osd->scale + xpos, yloc + 20*osd->scale + yheight+20*osd->scale, agg::rgba8(100,200,255,alpha), agg::rgba8(255,255,255,0)); if(lastSaveState == i) { - yheight = 5; - aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, 22 + xloc + xpos, yloc + 20 + yheight+20, agg::rgba8(100,255,255,alpha), agg::rgba8(255,255,255,0)); + yheight = 5*osd->scale; + aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, 22*osd->scale + xloc + xpos, yloc + 20*osd->scale + yheight+20*osd->scale, agg::rgba8(100,255,255,alpha), agg::rgba8(255,255,255,0)); } - aggDraw.hud->rectangle(xloc + xpos , yloc - yheight, xloc + 22 + xpos , yloc + 20 + yheight); + aggDraw.hud->rectangle(xloc + xpos , yloc - yheight, xloc + 22*osd->scale + xpos , yloc + 20*osd->scale + yheight); snprintf(number, 10, "%d", i); - aggDraw.hud->renderText(xloc + 1 + xpos + 4, yloc+4, std::string(number)); + RenderTextAutoVector(xloc + osd->scale + xpos + 4*osd->scale, yloc+4*osd->scale, std::string(number), true, osd->scale); i++; } } @@ -511,10 +596,10 @@ static void DrawEditableElementIndicators() HudCoordinates &hud = Hud.hud(i); aggDraw.hud->fillColor(0,0,0,0); aggDraw.hud->lineColor(0,0,0,64); - aggDraw.hud->lineWidth(2.0); + aggDraw.hud->lineWidth(2.0*osd->scale); aggDraw.hud->rectangle(hud.x,calcY(hud.y),hud.x+hud.xsize+1.0,calcY(hud.y)+hud.ysize+1.0); aggDraw.hud->lineColor(255,hud.clicked?127:255,0,255); - aggDraw.hud->lineWidth(1.0); + aggDraw.hud->lineWidth(osd->scale); aggDraw.hud->rectangle(hud.x-0.5,calcY(hud.y)-0.5,hud.x+hud.xsize+0.5,calcY(hud.y)+hud.ysize+0.5); i++; } @@ -624,9 +709,11 @@ OSDCLASS::OSDCLASS(u8 core) singleScreen = false; swapScreens = false; - + scale = 1.0; needUpdate = false; - +#ifdef AGG2D_USE_VECTORFONTS + useVectorFonts = false; +#endif if (core==0) strcpy(name,"Core A"); else @@ -707,7 +794,7 @@ void OSDCLASS::update() for (int i=0; i < lastLineText; i++) { aggDraw.hud->lineColor(lineColor[i]); - aggDraw.hud->renderTextDropshadowed(lineText_x,lineText_y+(i*16),lineText[i]); + RenderTextAutoVector(lineText_x, lineText_y+(i*16), lineText[i], true, osd->scale); } } else @@ -789,7 +876,7 @@ void OSDCLASS::addFixed(u16 x, u16 y, const char *fmt, ...) va_end(list); aggDraw.hud->lineColor(255,255,255); - aggDraw.hud->renderTextDropshadowed(x,calcY(y),msg); + RenderTextAutoVector(x, calcY(y), msg, true, osd->scale); needUpdate = true; } diff --git a/desmume/src/frontend/modules/osd/agg/agg_osd.h b/desmume/src/frontend/modules/osd/agg/agg_osd.h index e62fcbd95..4077a1eb2 100644 --- a/desmume/src/frontend/modules/osd/agg/agg_osd.h +++ b/desmume/src/frontend/modules/osd/agg/agg_osd.h @@ -73,6 +73,7 @@ public: HudCoordinates &hud(int i) { return ((HudCoordinates*)this)[i]; } void reset(); + void rescale(double oldScale, double newScale); int fps, fps3d, cpuload[2], cpuloopIterationCount; char rtcString[25]; @@ -92,7 +93,7 @@ class OSDCLASS private: u64 offset; u8 mode; - + u16 rotAngle; u16 lineText_x; @@ -111,6 +112,10 @@ public: char name[7]; // for debuging bool singleScreen; bool swapScreens; + double scale; +#ifdef AGG2D_USE_VECTORFONTS + bool useVectorFonts; +#endif OSDCLASS(u8 core); ~OSDCLASS(); @@ -125,7 +130,7 @@ public: void addLine(const char* fmt, va_list args); void addFixed(u16 x, u16 y, const char *fmt, ...); void border(bool enabled); - + void SaveHudEditor(); }; diff --git a/desmume/src/frontend/modules/osd/agg/aggdraw.cpp b/desmume/src/frontend/modules/osd/agg/aggdraw.cpp index 4ec5e0403..50758c8f1 100644 --- a/desmume/src/frontend/modules/osd/agg/aggdraw.cpp +++ b/desmume/src/frontend/modules/osd/agg/aggdraw.cpp @@ -118,20 +118,17 @@ static void Agg_init_fonts() AggDraw_Desmume aggDraw; -#if defined(WIN32) || defined(HOST_LINUX) -T_AGG_RGBA agg_targetScreen(0, 256, 384, 1024); -#else -T_AGG_RGB555 agg_targetScreen(0, 256, 384, 1512); -#endif +T_AGG_RGBA agg_targetScreen_32bit(0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4); +T_AGG_RGB555 agg_targetScreen_16bit(0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*2); -static u32 luaBuffer[256*192*2]; -T_AGG_RGBA agg_targetLua((u8*)luaBuffer, 256, 384, 1024); +static std::vector luaBuffer(GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT*2); +T_AGG_RGBA agg_targetLua((u8*)luaBuffer.data(), GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4); -static u32 hudBuffer[256*192*2]; -T_AGG_RGBA agg_targetHud((u8*)hudBuffer, 256, 384, 1024); +static std::vector hudBuffer(GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT*2); +T_AGG_RGBA agg_targetHud((u8*)hudBuffer.data(), GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4); static AggDrawTarget* targets[] = { - &agg_targetScreen, + &agg_targetScreen_32bit, &agg_targetHud, &agg_targetLua, }; @@ -139,6 +136,16 @@ static AggDrawTarget* targets[] = { void Agg_init() { Agg_init_fonts(); + switch(aggDraw.screenBytesPerPixel) + { + case 2: + targets[0]=&agg_targetScreen_16bit; + break; + case 4: + targets[0]=&agg_targetScreen_32bit; + break; + } + aggDraw.screen = targets[0]; aggDraw.hud = targets[1]; aggDraw.lua = targets[2]; @@ -149,19 +156,35 @@ void Agg_init() //and the more clever compositing isnt supported in non-windows #ifdef WIN32 if(CommonSettings.single_core()) - aggDraw.hud = &agg_targetScreen; + aggDraw.hud = aggDraw.screen; #else - aggDraw.hud = &agg_targetScreen; + aggDraw.hud = aggDraw.screen; #endif aggDraw.hud->setFont("verdana18_bold"); } +AggDraw_Desmume::AggDraw_Desmume() +{ + screenBytesPerPixel = 4; +} + void AggDraw_Desmume::setTarget(AggTarget newTarget) { target = targets[newTarget]; } +void Agg_setCustomSize(int w, int h) +{ + hudBuffer.resize(w*h); + luaBuffer.resize(w*h); + if(aggDraw.screen) + aggDraw.screen->setDrawTargetDims(0, w, h, w*aggDraw.screenBytesPerPixel); + if(aggDraw.hud) + aggDraw.hud->setDrawTargetDims((u8*)hudBuffer.data(), w, h, w*4); + if(aggDraw.lua) + aggDraw.lua->setDrawTargetDims((u8*)luaBuffer.data(), w, h, w*4); +} ////temporary, just for testing the lib diff --git a/desmume/src/frontend/modules/osd/agg/aggdraw.h b/desmume/src/frontend/modules/osd/agg/aggdraw.h index 2cc385622..692334fcf 100644 --- a/desmume/src/frontend/modules/osd/agg/aggdraw.h +++ b/desmume/src/frontend/modules/osd/agg/aggdraw.h @@ -19,7 +19,7 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE. */ @@ -43,18 +43,18 @@ THE SOFTWARE. #include "agg_pixfmt_rgb.h" #include "agg_pixfmt_rgba.h" -#include "agg_pixfmt_rgb_packed.h" +#include "agg_pixfmt_rgb_packed.h" #include "agg2d.h" typedef agg::rgba8 AggColor; -namespace agg -{ - //NOTE - these blenders are necessary to change the rgb order from the defaults, which are incorrect for us - - //this custom blender does more correct blending math than the default - //which is necessary or else drawing transparent pixels on (31,31,31) will yield (30,30,30) +namespace agg +{ + //NOTE - these blenders are necessary to change the rgb order from the defaults, which are incorrect for us + + //this custom blender does more correct blending math than the default + //which is necessary or else drawing transparent pixels on (31,31,31) will yield (30,30,30) struct my_blender_rgb555_pre { typedef rgba8 color_type; @@ -242,6 +242,8 @@ public: bool empty; virtual void clear() = 0; + + virtual void setDrawTargetDims(agg::int8u* buf, int width, int height, int stride) = 0; virtual agg::rendering_buffer & buf() = 0; @@ -408,6 +410,9 @@ public: virtual Agg2DBase::ImageResample imageResample() = 0; static const agg::int8u* lookupFont(const std::string& name); virtual void setFont(const std::string& name) = 0; +#ifdef AGG2D_USE_VECTORFONTS + virtual void setVectorFont(const std::string& fileName, int size, bool bold) = 0; +#endif virtual void renderText(double dstX, double dstY, const std::string& str) = 0; virtual void renderTextDropshadowed(double dstX, double dstY, const std::string& str) { @@ -427,6 +432,30 @@ public: lineColor(lineColorOld); renderText(dstX,dstY,str); } +#ifdef AGG2D_USE_VECTORFONTS + virtual void renderVectorFontText(double dstX, double dstY, const std::string& str) = 0; + virtual void renderVectorFontTextDropshadowed(double dstX, double dstY, const std::string& str, double shadowOffset = 1.0) + { + shadowOffset*=0.5; + AggColor lineColorOld = lineColor(); + if(lineColorOld.r+lineColorOld.g+lineColorOld.b<192) + lineColor(255-lineColorOld.r,255-lineColorOld.g,255-lineColorOld.b); + else + lineColor(0,0,0); + fillColor(lineColor()); + renderVectorFontText(dstX-shadowOffset,dstY-shadowOffset,str); + renderVectorFontText(dstX,dstY-shadowOffset,str); + renderVectorFontText(dstX+shadowOffset,dstY-shadowOffset,str); + renderVectorFontText(dstX-shadowOffset,dstY,str); + renderVectorFontText(dstX+shadowOffset,dstY,str); + renderVectorFontText(dstX-shadowOffset,dstY+shadowOffset,str); + renderVectorFontText(dstX,dstY+shadowOffset,str); + renderVectorFontText(dstX+shadowOffset,dstY+shadowOffset,str); + lineColor(lineColorOld); + fillColor(lineColor()); + renderVectorFontText(dstX,dstY,str); + } +#endif // Auxiliary @@ -458,6 +487,13 @@ public: undirty(); } } + + virtual void setDrawTargetDims(agg::int8u* buf, int width, int height, int stride) + { + BASE::attach(buf,width,height,stride); + + BASE::viewport(0, 0, width-1, height-1, 0, 0, width-1, height-1, TAGG2D::Anisotropic); + } virtual agg::rendering_buffer & buf() { dirty(); return BASE::buf(); } // buf() might not always require calling dirty() typename BASE::MyImage image() { return BASE::MyImage(buf()); } @@ -578,6 +614,9 @@ public: virtual void polyline(double* xy, int numPoints) {dirty(); BASE::polyline(xy, numPoints);}; virtual void setFont(const std::string& name) { BASE::font(lookupFont(name)); } +#ifdef AGG2D_USE_VECTORFONTS + virtual void setVectorFont(const std::string& fileName, int size, bool bold) {BASE::font(fileName.c_str(), size, bold); } +#endif virtual void renderText(double dstX, double dstY, const std::string& str) { dirty(); int height = BASE::font()[0]; @@ -585,6 +624,13 @@ public: int offset = height-base*2; BASE::renderText(dstX, dstY + offset, str); } +#ifdef AGG2D_USE_VECTORFONTS + virtual void renderVectorFontText(double dstX, double dstY, const std::string& str) { + dirty(); + BASE::flipText(true); + BASE::text(dstX, dstY + BASE::fontHeight(), str.c_str()); + } +#endif // Path commands virtual void resetPath() {BASE::resetPath();}; @@ -659,15 +705,18 @@ enum AggTarget class AggDraw_Desmume : public AggDraw { public: + AggDraw_Desmume(); void setTarget(AggTarget newTarget); //void composite(void* dest); AggDrawTarget *screen, *hud, *lua; + int screenBytesPerPixel; }; extern AggDraw_Desmume aggDraw; void Agg_init(); +void Agg_setCustomSize(int w, int h); struct font_type { diff --git a/desmume/src/frontend/posix/gtk/config.cpp b/desmume/src/frontend/posix/gtk/config.cpp index a0e593a5b..17a897563 100644 --- a/desmume/src/frontend/posix/gtk/config.cpp +++ b/desmume/src/frontend/posix/gtk/config.cpp @@ -97,6 +97,25 @@ void value::save() { g_key_file_set_string(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.c_str()); } +/* class value > */ + +template<> +void value >::load() { + gsize l; + int* val = g_key_file_get_integer_list(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), &l, NULL); + if(val) + { + this->mData.resize(l); + std::copy(val, val+l, this->mData.begin()); + g_free(val); + } +} + +template<> +void value >::save() { + g_key_file_set_integer_list(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.data(), this->mData.size()); +} + /* class Config */ Config::Config() diff --git a/desmume/src/frontend/posix/gtk/config_opts.h b/desmume/src/frontend/posix/gtk/config_opts.h index 7481ab634..72f0f5249 100644 --- a/desmume/src/frontend/posix/gtk/config_opts.h +++ b/desmume/src/frontend/posix/gtk/config_opts.h @@ -49,6 +49,7 @@ OPT(hud_input, bool, false, HudDisplay, Input) OPT(hud_graphicalInput, bool, false, HudDisplay, GraphicalInput) OPT(hud_rtc, bool, false, HudDisplay, RTC) OPT(hud_mic, bool, false, HudDisplay, Mic) +OPT(hud_layout, std::vector, std::vector(), HudDisplay, Layout) /* Config */ OPT(fpslimiter, bool, true, Config, FpsLimiter) diff --git a/desmume/src/frontend/posix/gtk/main.cpp b/desmume/src/frontend/posix/gtk/main.cpp index 1bf5bd492..f3e4c96d6 100644 --- a/desmume/src/frontend/posix/gtk/main.cpp +++ b/desmume/src/frontend/posix/gtk/main.cpp @@ -31,6 +31,9 @@ #include #include #include +#ifdef AGG2D_USE_VECTORFONTS +#include +#endif #include "types.h" #include "firmware.h" @@ -127,6 +130,15 @@ enum { SUB_OBJ }; +#ifdef AGG2D_USE_VECTORFONTS +#define VECTOR_FONT_BASE_SIZE 16 + +static FcConfig* fontConfig; +static std::string vectorFontFile; + +static std::string FindFontFile(const char* fontName, bool bold); +#endif + gboolean EmuLoop(gpointer data); static AVOutX264 avout_x264; @@ -190,6 +202,9 @@ static void HudLagCounter(GSimpleAction *action, GVariant *parameter, gpointer u static void HudRtc(GSimpleAction *action, GVariant *parameter, gpointer user_data); static void HudMic(GSimpleAction *action, GVariant *parameter, gpointer user_data); static void HudEditor(GSimpleAction *action, GVariant *parameter, gpointer user_data); +static void HudResetLayout(GSimpleAction *action, GVariant *parameter, gpointer user_data); +static void HudSaveLayout(); +static void HudLoadLayout(); #endif #ifdef DESMUME_GTK_FIRMWARE_BROKEN static void SelectFirmwareFile(GSimpleAction *action, GVariant *parameter, gpointer user_data); @@ -247,6 +262,7 @@ static const GActionEntry app_entries[] = { { "hud_rtc", HudRtc, NULL, "false" }, { "hud_mic", HudMic, NULL, "false" }, { "hud_editor", HudEditor, NULL, "false" }, + { "hud_reset_layout", HudResetLayout}, #endif // Config @@ -1449,7 +1465,7 @@ static void RedrawScreen() { GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16, (uint32_t *)video->GetSrcBufferPtr(), real_framebuffer_width * real_framebuffer_height * 2); #ifdef HAVE_LIBAGG - aggDraw.hud->attach((u8*)video->GetSrcBufferPtr(), real_framebuffer_width, real_framebuffer_height * 2, 1024 * gpu_scale_factor); + aggDraw.hud->setDrawTargetDims((u8*)video->GetSrcBufferPtr(), real_framebuffer_width, real_framebuffer_height * 2, real_framebuffer_width * 4); osd->update(); DrawHUD(); osd->clear(); @@ -1471,33 +1487,33 @@ static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.topscreen_matrix, &devX, &devY); - topX = devX; - topY = devY; + topX = devX * gpu_scale_factor; + topY = devY * gpu_scale_factor; } if (nds_screen.orientation != ORIENT_SINGLE || nds_screen.swap) { devX = x; devY = y; cairo_matrix_transform_point(&nds_screen.touch_matrix, &devX, &devY); - botX = devX; - botY = devY; + botX = devX * gpu_scale_factor; + botY = devY * gpu_scale_factor; } - if (topX >= 0 && topY >= 0 && topX < 256 && topY < 192) { + if (topX >= 0 && topY >= 0 && topX < real_framebuffer_width && topY < real_framebuffer_height) { X = topX; - Y = topY + (nds_screen.swap ? 192 : 0); + Y = topY + (nds_screen.swap ? real_framebuffer_height : 0); startScreen = 0; - } else if (botX >= 0 && botY >= 0 && botX < 256 && botY < 192) { + } else if (botX >= 0 && botY >= 0 && botX < real_framebuffer_width && botY < real_framebuffer_height) { X = botX; - Y = botY + (nds_screen.swap ? 0 : 192); + Y = botY + (nds_screen.swap ? 0 : real_framebuffer_height); startScreen = 1; } else if (!start) { if (startScreen == 0) { - X = CLAMP(topX, 0, 255); - Y = CLAMP(topY, 0, 191) + (nds_screen.swap ? 192 : 0); + X = CLAMP(topX, 0, real_framebuffer_width-1); + Y = CLAMP(topY, 0, real_framebuffer_height-1) + (nds_screen.swap ? real_framebuffer_height : 0); } else { - X = CLAMP(botX, 0, 255); - Y = CLAMP(botY, 0, 191) + (nds_screen.swap ? 0 : 192); + X = CLAMP(botX, 0, real_framebuffer_width-1); + Y = CLAMP(botY, 0, real_framebuffer_height-1) + (nds_screen.swap ? 0 : real_framebuffer_height); } } else { LOG("TopX=%d, TopY=%d, BotX=%d, BotY=%d\n", topX, topY, botX, botY); @@ -2098,6 +2114,7 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g default: break; } + double old_scale_factor = gpu_scale_factor; gpu_scale_factor = gtk_spin_button_get_value(wGPUScale); if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN) gpu_scale_factor = GPU_SCALE_FACTOR_MIN; @@ -2109,6 +2126,21 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor; GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); video->SetSourceSize(real_framebuffer_width, real_framebuffer_height * 2); +#ifdef HAVE_LIBAGG +#ifdef AGG2D_USE_VECTORFONTS + if(vectorFontFile.size() > 0) + { + aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * gpu_scale_factor, true); + osd->useVectorFonts=(gpu_scale_factor >= 1.1); + } + else + osd->useVectorFonts=false; +#endif + Agg_setCustomSize(real_framebuffer_width, real_framebuffer_height*2); + osd->scale=gpu_scale_factor; + Hud.rescale(old_scale_factor, gpu_scale_factor); + HudSaveLayout(); +#endif CommonSettings.GFX3D_Renderer_TextureDeposterize = config.textureDeposterize = gtk_toggle_button_get_active(wPosterize); CommonSettings.GFX3D_Renderer_TextureSmoothing = config.textureSmoothing = gtk_toggle_button_get_active(wSmoothing); CommonSettings.GFX3D_Renderer_TextureScalingFactor = config.textureUpscale = scale; @@ -2773,6 +2805,8 @@ static void ToggleHudDisplay(hud_display_enum hudId, gboolean active) break; case HUD_DISPLAY_EDITOR: HudEditorMode = active; + if(!active) + HudSaveLayout(); break; default: g_printerr("Unknown HUD toggle %u!", hudId); @@ -2799,6 +2833,60 @@ HudMacro(HudRtc, HUD_DISPLAY_RTC) HudMacro(HudMic, HUD_DISPLAY_MIC) HudMacro(HudEditor, HUD_DISPLAY_EDITOR) +static void HudResetLayout(GSimpleAction *action, GVariant *parameter, gpointer user_data) +{ + Hud.reset(); + HudSaveLayout(); +} + +static void HudSaveCoordsToVector(HudCoordinates* pCoords, int* pDest) +{ + pDest[0]=pCoords->x; + pDest[1]=pCoords->y; + pDest[2]=pCoords->xsize; + pDest[3]=pCoords->ysize; +} + +static void HudLoadCoordsFromVector(HudCoordinates* pCoords, int* pSrc) +{ + pCoords->x=pSrc[0]; + pCoords->y=pSrc[1]; + pCoords->xsize=pSrc[2]; + pCoords->ysize=pSrc[3]; +} + +static void HudSaveLayout() +{ + std::vector vec(8*4); //8 HudCoordinates + HudSaveCoordsToVector(&Hud.SavestateSlots, vec.data()); + HudSaveCoordsToVector(&Hud.FpsDisplay, vec.data()+4); + HudSaveCoordsToVector(&Hud.FrameCounter, vec.data()+8); + HudSaveCoordsToVector(&Hud.InputDisplay, vec.data()+12); + HudSaveCoordsToVector(&Hud.GraphicalInputDisplay, vec.data()+16); + HudSaveCoordsToVector(&Hud.LagFrameCounter, vec.data()+20); + HudSaveCoordsToVector(&Hud.Microphone, vec.data()+24); + HudSaveCoordsToVector(&Hud.RTCDisplay, vec.data()+28); + config.hud_layout=vec; +} + +static void HudLoadLayout() +{ + std::vector vec=config.hud_layout; + if(vec.size()==8*4) + { + HudLoadCoordsFromVector(&Hud.SavestateSlots, vec.data()); + HudLoadCoordsFromVector(&Hud.FpsDisplay, vec.data()+4); + HudLoadCoordsFromVector(&Hud.FrameCounter, vec.data()+8); + HudLoadCoordsFromVector(&Hud.InputDisplay, vec.data()+12); + HudLoadCoordsFromVector(&Hud.GraphicalInputDisplay, vec.data()+16); + HudLoadCoordsFromVector(&Hud.LagFrameCounter, vec.data()+20); + HudLoadCoordsFromVector(&Hud.Microphone, vec.data()+24); + HudLoadCoordsFromVector(&Hud.RTCDisplay, vec.data()+28); + } + else + Hud.reset(); +} + static void desmume_gtk_menu_view_hud(GtkApplication *app) { const struct { @@ -2998,6 +3086,10 @@ common_gtk_main(GApplication *app, gpointer user_data) /* Init the hud / osd stuff */ #ifdef HAVE_LIBAGG + SDL_DisplayMode cur_mode; + if(!SDL_GetCurrentDisplayMode(0, &cur_mode)) + aggDraw.screenBytesPerPixel = SDL_BYTESPERPIXEL(cur_mode.format); + Desmume_InitOnce(); Hud.reset(); osd = new OSDCLASS(-1); @@ -3067,6 +3159,20 @@ common_gtk_main(GApplication *app, gpointer user_data) g_printerr("Using %d threads for video filter.\n", CommonSettings.num_cores); GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height); video = new VideoFilter(real_framebuffer_width, real_framebuffer_height * 2, VideoFilterTypeID_None, CommonSettings.num_cores); +#ifdef HAVE_LIBAGG +#ifdef AGG2D_USE_VECTORFONTS + if(vectorFontFile.size() > 0) + { + aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * gpu_scale_factor, true); + osd->useVectorFonts=(gpu_scale_factor >= 1.1); + } + else + osd->useVectorFonts=false; +#endif + Agg_setCustomSize(real_framebuffer_width, real_framebuffer_height*2); + osd->scale=gpu_scale_factor; + HudLoadLayout(); +#endif /* Fetch the main elements from the window */ GtkBuilder *builder = gtk_builder_new_from_resource("/org/desmume/DeSmuME/main.ui"); @@ -3601,7 +3707,9 @@ common_gtk_main(GApplication *app, gpointer user_data) static void Teardown() { delete video; - +#ifdef HAVE_LIBAGG + HudSaveLayout(); +#endif config.save(); avout_x264.end(); avout_flac.end(); @@ -3644,10 +3752,46 @@ handle_open(GApplication *application, common_gtk_main(application, user_data); } +#ifdef AGG2D_USE_VECTORFONTS + +static std::string FindFontFile(const char* fontName, bool bold) +{ + std::string fontFile; + FcPattern* pat = FcNameParse((const FcChar8*)fontName); + if(bold) + FcPatternAddInteger(pat, FC_WEIGHT, FC_WEIGHT_BOLD); + FcConfigSubstitute(fontConfig, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + + // find the font + FcResult res; + FcPattern* font = FcFontMatch(fontConfig, pat, &res); + if (font) + { + FcChar8* file = NULL; + if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) + { + // save the file to another std::string + fontFile = (char*)file; + } + FcPatternDestroy(font); + } + FcPatternDestroy(pat); + return fontFile; +} + +#endif + int main (int argc, char *argv[]) { configured_features my_config; +#ifdef AGG2D_USE_VECTORFONTS + fontConfig = FcInitLoadConfigAndFonts(); + vectorFontFile = FindFontFile("mono", true); + if(!vectorFontFile.size()) + vectorFontFile = FindFontFile("sans", true); +#endif // The global menu screws up the window size... unsetenv("UBUNTU_MENUPROXY"); diff --git a/desmume/src/frontend/posix/gtk/menu.ui b/desmume/src/frontend/posix/gtk/menu.ui index db28d2ae7..807efa898 100644 --- a/desmume/src/frontend/posix/gtk/menu.ui +++ b/desmume/src/frontend/posix/gtk/menu.ui @@ -834,6 +834,10 @@ _Editor mode app.hud_editor + + Reset layout + app.hud_reset_layout + diff --git a/desmume/src/frontend/posix/meson.build b/desmume/src/frontend/posix/meson.build index 89e0e4bef..13bf45a25 100644 --- a/desmume/src/frontend/posix/meson.build +++ b/desmume/src/frontend/posix/meson.build @@ -20,6 +20,7 @@ dep_openal = dependency('openal', required: get_option('openal')) dep_alsa = dependency('alsa', required: false) dep_soundtouch = dependency('soundtouch', required: false) dep_agg = dependency('libagg', required: false) +dep_fontconfig = dependency('fontconfig', required: false) # XXX: something wrong with this one. #dep_lua = dependency('lua-5.1', required: false) @@ -203,6 +204,11 @@ endif if dep_agg.found() dependencies += dep_agg add_global_arguments('-DHAVE_LIBAGG', language: ['c', 'cpp']) + if dep_fontconfig.found() + dependencies += dep_fontconfig + add_global_arguments('-DAGG2D_USE_VECTORFONTS', language: ['c', 'cpp']) + add_global_link_arguments('-laggfontfreetype', language: ['c', 'cpp']) + endif libdesmume_src += [ '../modules/osd/agg/aggdraw.cpp', '../modules/osd/agg/agg_osd.cpp', From 0a6eca6dce2e16817da45827aa38acd4e57b1a32 Mon Sep 17 00:00:00 2001 From: Max Fedotov Date: Mon, 26 Feb 2024 22:12:50 +0300 Subject: [PATCH 24/49] GTK: hybrid layout support (#773) * GTK: hybrid layout support * Fix HUD with new layouts * Simplify rotoscaled_hudedit logic a bit --- desmume/src/frontend/posix/gtk/main.cpp | 290 ++++++++++++++++++++---- desmume/src/frontend/posix/gtk/menu.ui | 12 + 2 files changed, 261 insertions(+), 41 deletions(-) diff --git a/desmume/src/frontend/posix/gtk/main.cpp b/desmume/src/frontend/posix/gtk/main.cpp index f3e4c96d6..06861431e 100644 --- a/desmume/src/frontend/posix/gtk/main.cpp +++ b/desmume/src/frontend/posix/gtk/main.cpp @@ -313,6 +313,8 @@ enum orientation_enum { ORIENT_VERTICAL = 0, ORIENT_HORIZONTAL = 1, ORIENT_SINGLE = 2, + ORIENT_HYBRID_EQUAL = 3, + ORIENT_HYBRID_VERTICAL = 4, ORIENT_N }; @@ -322,9 +324,11 @@ struct screen_size_t { }; const struct screen_size_t screen_size[ORIENT_N] = { - {256, 384}, - {512, 192}, - {256, 192} + {GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2}, + {GPU_FRAMEBUFFER_NATIVE_WIDTH*2, GPU_FRAMEBUFFER_NATIVE_HEIGHT}, + {GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT}, + {GPU_FRAMEBUFFER_NATIVE_WIDTH*3, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2}, + {GPU_FRAMEBUFFER_NATIVE_WIDTH*3, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2} }; enum spumode_enum { @@ -539,7 +543,9 @@ struct nds_screen_t { gint rotation_angle; orientation_enum orientation; cairo_matrix_t touch_matrix; + cairo_matrix_t touch_matrix_hybrid; cairo_matrix_t topscreen_matrix; + cairo_matrix_t topscreen_matrix_hybrid; gboolean swap; }; @@ -1213,6 +1219,33 @@ static void Reset(GSimpleAction *action, GVariant *parameter, gpointer user_data /////////////////////////////// DRAWING SCREEN ////////////////////////////////// + +struct DrawParams { + bool valid; + + //Drawing area size + gint daW; + gint daH; + + //Image size + gint imgW; + gint imgH; + + //Buffer size + gint dstW; + gint dstH; + gint dstScale; + + gint gap; + gint gapOffset; + + gfloat ratio; + + gdouble hybridBigScreenScale; +}; + +static DrawParams draw_params = {false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0.0}; + static void UpdateDrawingAreaAspect() { gint H, W; @@ -1226,11 +1259,16 @@ static void UpdateDrawingAreaAspect() } if (nds_screen.orientation != ORIENT_SINGLE) { - if (nds_screen.orientation == ORIENT_VERTICAL) { + if ((nds_screen.orientation == ORIENT_VERTICAL) || (nds_screen.orientation == ORIENT_HYBRID_EQUAL) || + (nds_screen.orientation == ORIENT_HYBRID_VERTICAL)) { if ((nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180)) { - H += nds_screen.gap_size; + if((nds_screen.orientation == ORIENT_HYBRID_EQUAL) || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL)) + W = (W * 2.0/3.0) * (double)(H + nds_screen.gap_size) / (double)H + W / 3.0; + H += nds_screen.gap_size; } else { - W += nds_screen.gap_size; + if((nds_screen.orientation == ORIENT_HYBRID_EQUAL) || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL)) + H = (H * 2.0/3.0) * (double)(W + nds_screen.gap_size) / (double)W + H / 3.0; + W += nds_screen.gap_size; } } } @@ -1243,6 +1281,8 @@ static void UpdateDrawingAreaAspect() gtk_window_set_resizable(GTK_WINDOW(pWindow), FALSE); gtk_widget_set_size_request(GTK_WIDGET(pDrawingArea), W * winsize_current / 2, H * winsize_current / 2); } + + draw_params.valid = false; } static void ToggleGap(GSimpleAction *action, GVariant *parameter, gpointer user_data) @@ -1306,9 +1346,15 @@ static void SetOrientation(GSimpleAction *action, GVariant *parameter, gpointer orient = ORIENT_HORIZONTAL; else if(strcmp(string, "single") == 0) orient = ORIENT_SINGLE; + else if(strcmp(string, "hybrid_equal") == 0) + orient = ORIENT_HYBRID_EQUAL; + else if(strcmp(string, "hybrid_vertical") == 0) + orient = ORIENT_HYBRID_VERTICAL; nds_screen.orientation = orient; #ifdef HAVE_LIBAGG osd->singleScreen = nds_screen.orientation == ORIENT_SINGLE; + bool hybrid = (nds_screen.orientation == ORIENT_HYBRID_EQUAL) || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL); + osd->swapScreens = nds_screen.swap && !hybrid; #endif config.view_orient = nds_screen.orientation; UpdateDrawingAreaAspect(); @@ -1320,7 +1366,8 @@ static void ToggleSwapScreens(GSimpleAction *action, GVariant *parameter, gpoint gboolean value = !g_variant_get_boolean(variant); nds_screen.swap = value; #ifdef HAVE_LIBAGG - osd->swapScreens = nds_screen.swap; + bool hybrid = (nds_screen.orientation == ORIENT_HYBRID_EQUAL) || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL); + osd->swapScreens = nds_screen.swap && !hybrid; #endif config.view_swap = nds_screen.swap; RedrawScreen(); @@ -1364,6 +1411,17 @@ static inline void drawTopScreen(cairo_t* cr, u32* buf, gint w, gint h, gint gap cairo_translate(cr, w, 0); } break; + case ORIENT_HYBRID_EQUAL: + case ORIENT_HYBRID_VERTICAL: + if (!swap && (draw_params.hybridBigScreenScale > 0.0)) { + cairo_save(cr); + cairo_scale(cr, draw_params.hybridBigScreenScale, draw_params.hybridBigScreenScale); + cairo_get_matrix(cr, &nds_screen.topscreen_matrix_hybrid); + drawScreen(cr, buf, w, h); + cairo_restore(cr); + } + cairo_translate(cr, w * draw_params.hybridBigScreenScale, 0); + break; } // Used for HUD editor mode cairo_get_matrix(cr, &nds_screen.topscreen_matrix); @@ -1387,6 +1445,19 @@ static inline void drawBottomScreen(cairo_t* cr, u32* buf, gint w, gint h, gint cairo_translate(cr, w, 0); } break; + case ORIENT_HYBRID_EQUAL: + case ORIENT_HYBRID_VERTICAL: + if (swap && (draw_params.hybridBigScreenScale > 0.0)) { + cairo_save(cr); + if(orientation == ORIENT_HYBRID_VERTICAL) + cairo_translate(cr, 0, h * (2.0 - draw_params.hybridBigScreenScale) + gap); + cairo_scale(cr, draw_params.hybridBigScreenScale, draw_params.hybridBigScreenScale); + cairo_get_matrix(cr, &nds_screen.touch_matrix_hybrid); + drawScreen(cr, buf, w, h); + cairo_restore(cr); + } + cairo_translate(cr, w * draw_params.hybridBigScreenScale, h + gap); + break; } // Store the matrix for converting touchscreen coordinates cairo_get_matrix(cr, &nds_screen.touch_matrix); @@ -1394,6 +1465,21 @@ static inline void drawBottomScreen(cairo_t* cr, u32* buf, gint w, gint h, gint cairo_restore(cr); } +static void calc_hybrid_vertical_params(gint daW, gint daH, gint gap, gint dstScale, gint & imgW, gint & imgH) +{ + gdouble hyb_hratio1, hyb_hratio2, hyb_vratio1, hyb_vratio2, hyb_ratio1, hyb_ratio2; + hyb_hratio1 = (gdouble)daW / (gdouble)(GPU_FRAMEBUFFER_NATIVE_WIDTH * dstScale / 2); + hyb_vratio1 = (gdouble)daH / (gdouble)(GPU_FRAMEBUFFER_NATIVE_HEIGHT * dstScale + gap); + hyb_ratio1 = MIN(hyb_hratio1, hyb_vratio1); + gint w_rem = daW - GPU_FRAMEBUFFER_NATIVE_WIDTH * dstScale / 2.0 * hyb_ratio1; + hyb_hratio2 = (gdouble)w_rem / (gdouble)(GPU_FRAMEBUFFER_NATIVE_WIDTH * dstScale / 2); + hyb_vratio2 = (gdouble)daH / (gdouble)(GPU_FRAMEBUFFER_NATIVE_HEIGHT * dstScale / 2); + hyb_ratio2 = MIN(hyb_hratio2, hyb_vratio2); + imgW = GPU_FRAMEBUFFER_NATIVE_WIDTH * dstScale / 2 * (1.0 + hyb_ratio2 / hyb_ratio1); + imgH = GPU_FRAMEBUFFER_NATIVE_HEIGHT * dstScale + gap; + draw_params.hybridBigScreenScale = hyb_ratio2 / hyb_ratio1; +} + /* Drawing callback */ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpointer data) { @@ -1408,51 +1494,96 @@ static gboolean ExposeDrawingArea (GtkWidget *widget, GdkEventExpose *event, gpo u32* fbuf = video->GetDstBufferPtr(); gint dstW = video->GetDstWidth(); gint dstH = video->GetDstHeight(); - - gint dstScale = dstW * 2 / GPU_FRAMEBUFFER_NATIVE_WIDTH; // Actual scale * 2 to handle 1.5x filters - gint gap = nds_screen.orientation == ORIENT_VERTICAL ? nds_screen.gap_size * dstScale / 2 : 0; - gint imgW, imgH; - if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) { - imgW = screen_size[nds_screen.orientation].width * dstScale / 2; - imgH = screen_size[nds_screen.orientation].height * dstScale / 2 + gap; - } else { - imgH = screen_size[nds_screen.orientation].width * dstScale / 2; - imgW = screen_size[nds_screen.orientation].height * dstScale / 2 + gap; + if(draw_params.valid) + if(draw_params.daW != daW || draw_params.daH != daH || draw_params.dstW != dstW || draw_params.dstH != dstH) + draw_params.valid = false; + + if(!draw_params.valid) { + draw_params.daW = daW; + draw_params.daH = daH; + draw_params.dstW = dstW; + draw_params.dstH = dstH; + + draw_params.dstScale = dstW * 2 / GPU_FRAMEBUFFER_NATIVE_WIDTH; // Actual scale * 2 to handle 1.5x filters + + draw_params.gap = ((nds_screen.orientation == ORIENT_VERTICAL) || (nds_screen.orientation == ORIENT_HYBRID_EQUAL) + || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL)) ? nds_screen.gap_size * draw_params.dstScale / 2 : 0; + if(nds_screen.orientation == ORIENT_HYBRID_VERTICAL) { + if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) + calc_hybrid_vertical_params(daW, daH, draw_params.gap, draw_params.dstScale, draw_params.imgW, draw_params.imgH); + else + calc_hybrid_vertical_params(daH, daW, draw_params.gap, draw_params.dstScale, draw_params.imgH, draw_params.imgW); + } + else { + if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) { + draw_params.imgW = screen_size[nds_screen.orientation].width * draw_params.dstScale / 2; + draw_params.imgH = screen_size[nds_screen.orientation].height * draw_params.dstScale / 2 + draw_params.gap; + if(nds_screen.orientation == ORIENT_HYBRID_EQUAL) + draw_params.imgW = (draw_params.imgW * 2.0/3.0) * (double)draw_params.imgH / + (double)(draw_params.imgH - draw_params.gap) + draw_params.imgW / 3.0; + } else { + draw_params.imgH = screen_size[nds_screen.orientation].width * draw_params.dstScale / 2; + draw_params.imgW = screen_size[nds_screen.orientation].height * draw_params.dstScale / 2 + draw_params.gap; + if(nds_screen.orientation == ORIENT_HYBRID_EQUAL) + draw_params.imgH = (draw_params.imgH * 2.0/3.0) * (double)draw_params.imgW / + (double)(draw_params.imgW - draw_params.gap) + draw_params.imgH / 3.0; + } + if(nds_screen.orientation == ORIENT_HYBRID_EQUAL) + draw_params.hybridBigScreenScale = (double)(dstH + draw_params.gap) / (double)(dstH / 2); + } + + // Calculate scale to fit display area to window + gfloat hratio = (gfloat)daW / (gfloat)draw_params.imgW; + gfloat vratio = (gfloat)daH / (gfloat)draw_params.imgH; + draw_params.ratio = MIN(hratio, vratio); + + draw_params.gapOffset = 0; + switch(nds_screen.orientation) { + case ORIENT_HYBRID_EQUAL: + draw_params.gapOffset = dstW * ((gdouble)(dstH + draw_params.gap) / (dstH / 2.0)); + break; + case ORIENT_HYBRID_VERTICAL: + draw_params.gapOffset = dstW * draw_params.hybridBigScreenScale; + break; + } + + draw_params.valid = true; } - // Calculate scale to fit display area to window - gfloat hratio = (gfloat)daW / (gfloat)imgW; - gfloat vratio = (gfloat)daH / (gfloat)imgH; - hratio = MIN(hratio, vratio); - vratio = hratio; - GdkDrawingContext *context = gdk_window_begin_draw_frame(window, gdk_window_get_clip_region(window)); cairo_t* cr = gdk_drawing_context_get_cairo_context(context); // Scale to window size at center of area cairo_translate(cr, daW / 2, daH / 2); - cairo_scale(cr, hratio, vratio); + cairo_scale(cr, draw_params.ratio, draw_params.ratio); // Rotate area cairo_rotate(cr, M_PI / 180 * nds_screen.rotation_angle); // Translate area to top-left corner if (nds_screen.rotation_angle == 0 || nds_screen.rotation_angle == 180) { - cairo_translate(cr, -imgW / 2, -imgH / 2); + cairo_translate(cr, -draw_params.imgW / 2, -draw_params.imgH / 2); } else { - cairo_translate(cr, -imgH / 2, -imgW / 2); + cairo_translate(cr, -draw_params.imgH / 2, -draw_params.imgW / 2); } // Draw both screens - drawTopScreen(cr, fbuf, dstW, dstH / 2, gap, nds_screen.rotation_angle, nds_screen.swap, nds_screen.orientation); - drawBottomScreen(cr, fbuf + dstW * dstH / 2, dstW, dstH / 2, gap, nds_screen.rotation_angle, nds_screen.swap, nds_screen.orientation); + drawTopScreen(cr, fbuf, dstW, dstH / 2, draw_params.gap, nds_screen.rotation_angle, nds_screen.swap, nds_screen.orientation); + drawBottomScreen(cr, fbuf + dstW * dstH / 2, dstW, dstH / 2, draw_params.gap, nds_screen.rotation_angle, nds_screen.swap, nds_screen.orientation); // Draw gap + cairo_set_source_rgb(cr, 0.3, 0.3, 0.3); - cairo_rectangle(cr, 0, dstH / 2, dstW, gap); + cairo_rectangle(cr, draw_params.gapOffset, dstH / 2, dstW, draw_params.gap); cairo_fill(cr); // Complete the touch transformation matrix - cairo_matrix_scale(&nds_screen.topscreen_matrix, (double)dstScale / 2, (double)dstScale / 2); + cairo_matrix_scale(&nds_screen.topscreen_matrix, (double)draw_params.dstScale / 2, (double)draw_params.dstScale / 2); cairo_matrix_invert(&nds_screen.topscreen_matrix); - cairo_matrix_scale(&nds_screen.touch_matrix, (double)dstScale / 2, (double)dstScale / 2); + cairo_matrix_scale(&nds_screen.touch_matrix, (double)draw_params.dstScale / 2, (double)draw_params.dstScale / 2); cairo_matrix_invert(&nds_screen.touch_matrix); + if((nds_screen.orientation == ORIENT_HYBRID_EQUAL) || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL)) { + cairo_matrix_scale(&nds_screen.topscreen_matrix_hybrid, (double)draw_params.dstScale / 2, (double)draw_params.dstScale / 2); + cairo_matrix_invert(&nds_screen.topscreen_matrix_hybrid); + cairo_matrix_scale(&nds_screen.touch_matrix_hybrid, (double)draw_params.dstScale / 2, (double)draw_params.dstScale / 2); + cairo_matrix_invert(&nds_screen.touch_matrix_hybrid); + } gdk_window_end_draw_frame(window, context); draw_count++; @@ -1476,12 +1607,17 @@ static void RedrawScreen() { /////////////////////////////// KEYS AND STYLUS UPDATE /////////////////////////////////////// +static bool move_started_in_big_screen = false; +static bool hud_move_started_in_big_screen = false; + #ifdef HAVE_LIBAGG static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) { double devX, devY; - gint X, Y, topX = -1, topY = -1, botX = -1, botY = -1; + gint X, Y, topX = -1, topY = -1, botX = -1, botY = -1, hybTopX = -1, hybTopY = -1, hybBotX = -1, hybBotY = -1; static gint startScreen = 0; + bool hybrid = ((nds_screen.orientation == ORIENT_HYBRID_EQUAL) || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL)) && + (draw_params.hybridBigScreenScale > 0.0); if (nds_screen.orientation != ORIENT_SINGLE || !nds_screen.swap) { devX = x; @@ -1489,6 +1625,14 @@ static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) cairo_matrix_transform_point(&nds_screen.topscreen_matrix, &devX, &devY); topX = devX * gpu_scale_factor; topY = devY * gpu_scale_factor; + + if(hybrid && !nds_screen.swap) { + devX = x; + devY = y; + cairo_matrix_transform_point(&nds_screen.topscreen_matrix_hybrid, &devX, &devY); + hybTopX = devX * gpu_scale_factor; + hybTopY = devY * gpu_scale_factor; + } } if (nds_screen.orientation != ORIENT_SINGLE || nds_screen.swap) { @@ -1497,23 +1641,57 @@ static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start) cairo_matrix_transform_point(&nds_screen.touch_matrix, &devX, &devY); botX = devX * gpu_scale_factor; botY = devY * gpu_scale_factor; + + if(hybrid && nds_screen.swap) { + devX = x; + devY = y; + cairo_matrix_transform_point(&nds_screen.touch_matrix_hybrid, &devX, &devY); + hybBotX = devX * gpu_scale_factor; + hybBotY = devY * gpu_scale_factor; + } } if (topX >= 0 && topY >= 0 && topX < real_framebuffer_width && topY < real_framebuffer_height) { X = topX; - Y = topY + (nds_screen.swap ? real_framebuffer_height : 0); + Y = topY + (osd->swapScreens ? real_framebuffer_height : 0); startScreen = 0; + if(start) + hud_move_started_in_big_screen = false; + } else if (hybTopX >= 0 && hybTopY >= 0 && hybTopX < real_framebuffer_width && hybTopY < real_framebuffer_height) { + X = hybTopX; + Y = hybTopY; + startScreen = 0; + if(start) + hud_move_started_in_big_screen = true; } else if (botX >= 0 && botY >= 0 && botX < real_framebuffer_width && botY < real_framebuffer_height) { X = botX; - Y = botY + (nds_screen.swap ? 0 : real_framebuffer_height); + Y = botY + (osd->swapScreens ? 0 : real_framebuffer_height); startScreen = 1; + if(start) + hud_move_started_in_big_screen = false; + } else if (hybBotX >= 0 && hybBotY >= 0 && hybBotX < real_framebuffer_width && hybBotY < real_framebuffer_height) { + X = hybBotX; + Y = hybBotY + real_framebuffer_height; + startScreen = 1; + if(start) + hud_move_started_in_big_screen = true; } else if (!start) { if (startScreen == 0) { - X = CLAMP(topX, 0, real_framebuffer_width-1); - Y = CLAMP(topY, 0, real_framebuffer_height-1) + (nds_screen.swap ? real_framebuffer_height : 0); + if(!hud_move_started_in_big_screen || !hybrid) { + X = CLAMP(topX, 0, real_framebuffer_width-1); + Y = CLAMP(topY, 0, real_framebuffer_height-1) + (osd->swapScreens ? real_framebuffer_height : 0); + } else { + X = CLAMP(hybTopX, 0, real_framebuffer_width-1); + Y = CLAMP(hybTopY, 0, real_framebuffer_height-1); + } } else { - X = CLAMP(botX, 0, real_framebuffer_width-1); - Y = CLAMP(botY, 0, real_framebuffer_height-1) + (nds_screen.swap ? 0 : real_framebuffer_height); + if(!hud_move_started_in_big_screen || !hybrid) { + X = CLAMP(botX, 0, real_framebuffer_width-1); + Y = CLAMP(botY, 0, real_framebuffer_height-1) + (osd->swapScreens ? 0 : real_framebuffer_height); + } else { + X = CLAMP(hybBotX, 0, real_framebuffer_width-1); + Y = CLAMP(hybBotY, 0, real_framebuffer_height-1) + real_framebuffer_height; + } } } else { LOG("TopX=%d, TopY=%d, BotX=%d, BotY=%d\n", topX, topY, botX, botY); @@ -1545,13 +1723,33 @@ static gboolean rotoscaled_touchpos(gint x, gint y, gboolean start) LOG("X=%d, Y=%d\n", X, Y); - if (!start || (X >= 0 && Y >= 0 && X < 256 && Y < 192)) { + if ((!start && !move_started_in_big_screen) || (X >= 0 && Y >= 0 && X < 256 && Y < 192)) { + if(start) + move_started_in_big_screen = false; EmuX = CLAMP(X, 0, 255); EmuY = CLAMP(Y, 0, 191); NDS_setTouchPos(EmuX, EmuY); return TRUE; } - + + if((((nds_screen.orientation == ORIENT_HYBRID_EQUAL) || + (nds_screen.orientation == ORIENT_HYBRID_VERTICAL)) && (draw_params.hybridBigScreenScale > 0.0)) && (nds_screen.swap)) { + devX = x; + devY = y; + cairo_matrix_transform_point(&nds_screen.touch_matrix_hybrid, &devX, &devY); + X = devX; + Y = devY; + + if ((!start && move_started_in_big_screen) || (X >= 0 && Y >= 0 && X < 256 && Y < 192)) { + if(start) + move_started_in_big_screen = true; + EmuX = CLAMP(X, 0, 255); + EmuY = CLAMP(Y, 0, 191); + NDS_setTouchPos(EmuX, EmuY); + return TRUE; + } + } + return FALSE; } @@ -3450,7 +3648,7 @@ common_gtk_main(GApplication *app, gpointer user_data) } g_simple_action_set_state(G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "winsize")), g_variant_new_string(string.c_str())); - if (config.view_orient < ORIENT_VERTICAL || config.view_orient > ORIENT_SINGLE) { + if (config.view_orient < ORIENT_VERTICAL || config.view_orient > ORIENT_HYBRID_VERTICAL) { config.view_orient = ORIENT_VERTICAL; } nds_screen.orientation = (orientation_enum)config.view_orient.get(); @@ -3464,6 +3662,12 @@ common_gtk_main(GApplication *app, gpointer user_data) case ORIENT_SINGLE: string = "single"; break; + case ORIENT_HYBRID_EQUAL: + string = "hybrid_equal"; + break; + case ORIENT_HYBRID_VERTICAL: + string = "hybrid_vertical"; + break; } g_simple_action_set_state(G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "orient")), g_variant_new_string(string.c_str())); @@ -3484,6 +3688,10 @@ common_gtk_main(GApplication *app, gpointer user_data) nds_screen.gap_size = config.view_gap ? GAP_SIZE : 0; nds_screen.swap = config.view_swap; + #ifdef HAVE_LIBAGG + bool hybrid = (nds_screen.orientation == ORIENT_HYBRID_EQUAL) || (nds_screen.orientation == ORIENT_HYBRID_VERTICAL); + osd->swapScreens = nds_screen.swap && !hybrid; + #endif g_simple_action_set_state(G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(app), "swapscreens")), g_variant_new_boolean(config.view_swap)); builder = gtk_builder_new_from_resource("/org/desmume/DeSmuME/menu.ui"); diff --git a/desmume/src/frontend/posix/gtk/menu.ui b/desmume/src/frontend/posix/gtk/menu.ui index 807efa898..c9369d697 100644 --- a/desmume/src/frontend/posix/gtk/menu.ui +++ b/desmume/src/frontend/posix/gtk/menu.ui @@ -254,6 +254,18 @@ app.orient single <Control>0 + + + Hybrid (_equal height) + app.orient + hybrid_equal + <Control>3 + + + Hybrid (e_mphasize vertical) + app.orient + hybrid_vertical + <Control>4
From bae67e2d0ca9ea49b61392b47ca1e732b9b68946 Mon Sep 17 00:00:00 2001 From: rogerman Date: Sat, 2 Mar 2024 15:18:51 -0800 Subject: [PATCH 25/49] GPU: Implement the DISPCNT register's ForceBlank bit by clearing the line to white if the ForceBlank bit is set. (Fixes #775.) --- desmume/src/GPU.cpp | 104 +++++++++++++++++++++++++++----------------- desmume/src/GPU.h | 7 ++- 2 files changed, 70 insertions(+), 41 deletions(-) diff --git a/desmume/src/GPU.cpp b/desmume/src/GPU.cpp index 66696443d..8081ad2b0 100644 --- a/desmume/src/GPU.cpp +++ b/desmume/src/GPU.cpp @@ -924,6 +924,11 @@ const GPU_IOREG& GPUEngineBase::GetIORegisterMap() const return *this->_IORegisterMap; } +bool GPUEngineBase::IsForceBlankSet() const +{ + return (this->_IORegisterMap->DISPCNT.ForceBlank != 0); +} + bool GPUEngineBase::IsMasterBrightMaxOrMin() const { return this->_currentRenderState.masterBrightnessIsMaxOrMin; @@ -2940,11 +2945,18 @@ void GPUEngineBase::RenderLayerBG(const GPULayerID layerID, u16 *dstColorBuffer) } } +void GPUEngineBase::_RenderLineBlank(const size_t l) +{ + // Native rendering only. + // Just clear the line using white pixels. + memset_u16_fast(this->_targetDisplay->GetNativeBuffer16() + (l * GPU_FRAMEBUFFER_NATIVE_WIDTH), 0xFFFF); +} + void GPUEngineBase::_HandleDisplayModeOff(const size_t l) { // Native rendering only. - // In this display mode, the display is cleared to white. - memset_u16_fast(this->_targetDisplay->GetNativeBuffer16() + (l * GPU_FRAMEBUFFER_NATIVE_WIDTH), 0xFFFF); + // In this display mode, the line is cleared to white. + this->_RenderLineBlank(l); } void GPUEngineBase::_HandleDisplayModeNormal(const size_t l) @@ -3536,23 +3548,30 @@ void GPUEngineA::RenderLine(const size_t l) } // Fill the display output - switch (compInfo.renderState.displayOutputMode) + if ( this->IsForceBlankSet() ) { - case GPUDisplayMode_Off: // Display Off (Display white) - this->_HandleDisplayModeOff(l); - break; - - case GPUDisplayMode_Normal: // Display BG and OBJ layers - this->_HandleDisplayModeNormal(l); - break; - - case GPUDisplayMode_VRAM: // Display VRAM framebuffer - this->_HandleDisplayModeVRAM(compInfo.line); - break; - - case GPUDisplayMode_MainMemory: // Display Memory FIFO - this->_HandleDisplayModeMainMemory(compInfo.line); - break; + this->_RenderLineBlank(l); + } + else + { + switch (compInfo.renderState.displayOutputMode) + { + case GPUDisplayMode_Off: // Display Off (clear line to white) + this->_HandleDisplayModeOff(l); + break; + + case GPUDisplayMode_Normal: // Display BG and OBJ layers + this->_HandleDisplayModeNormal(l); + break; + + case GPUDisplayMode_VRAM: // Display VRAM framebuffer + this->_HandleDisplayModeVRAM(compInfo.line); + break; + + case GPUDisplayMode_MainMemory: // Display Memory FIFO + this->_HandleDisplayModeMainMemory(compInfo.line); + break; + } } //capture after displaying so that we can safely display vram before overwriting it here @@ -4533,29 +4552,36 @@ void GPUEngineB::RenderLine(const size_t l) { GPUEngineCompositorInfo &compInfo = this->_currentCompositorInfo[l]; - switch (compInfo.renderState.displayOutputMode) + if ( this->IsForceBlankSet() ) { - case GPUDisplayMode_Off: // Display Off(Display white) - this->_HandleDisplayModeOff(l); - break; - - case GPUDisplayMode_Normal: // Display BG and OBJ layers + this->_RenderLineBlank(l); + } + else + { + switch (compInfo.renderState.displayOutputMode) { - if (compInfo.renderState.isAnyWindowEnabled) - { - this->_RenderLine_Layers(compInfo); - } - else - { - this->_RenderLine_Layers(compInfo); - } + case GPUDisplayMode_Off: // Display Off (clear line to white) + this->_HandleDisplayModeOff(l); + break; - this->_HandleDisplayModeNormal(l); - break; + case GPUDisplayMode_Normal: // Display BG and OBJ layers + { + if (compInfo.renderState.isAnyWindowEnabled) + { + this->_RenderLine_Layers(compInfo); + } + else + { + this->_RenderLine_Layers(compInfo); + } + + this->_HandleDisplayModeNormal(l); + break; + } + + default: + break; } - - default: - break; } if (compInfo.line.indexNative >= 191) @@ -5454,7 +5480,7 @@ void GPUSubsystem::RenderLine(const size_t l) this->_engineSub->UpdateRenderStates(l); } - if ( (isFramebufferRenderNeeded[GPUEngineID_Main] || isDisplayCaptureNeeded) && !this->_willFrameSkip ) + if ( (isFramebufferRenderNeeded[GPUEngineID_Main] || this->_engineMain->IsForceBlankSet() || isDisplayCaptureNeeded) && !this->_willFrameSkip ) { // GPUEngineA:WillRender3DLayer() and GPUEngineA:WillCapture3DLayerDirect() both rely on register // states that might change on a per-line basis. Therefore, we need to check these states on a @@ -5502,7 +5528,7 @@ void GPUSubsystem::RenderLine(const size_t l) this->_engineMain->UpdatePropertiesWithoutRender(l); } - if (isFramebufferRenderNeeded[GPUEngineID_Sub] && !this->_willFrameSkip) + if ( (isFramebufferRenderNeeded[GPUEngineID_Sub] || this->_engineSub->IsForceBlankSet()) && !this->_willFrameSkip) { switch (this->_engineSub->GetTargetDisplay()->GetColorFormat()) { diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index 5808fa304..43ff7d44a 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -117,7 +117,7 @@ typedef union u8 OBJ_Tile_mapping:1; // 4: A+B; 0=2D (32KB), 1=1D (32..256KB) u8 OBJ_BMP_2D_dim:1; // 5: A+B; 0=128x512, 1=256x256 pixels u8 OBJ_BMP_mapping:1; // 6: A+B; 0=2D (128KB), 1=1D (128..256KB) - u8 ForceBlank:1; // 7: A+B; + u8 ForceBlank:1; // 7: A+B; 0=Disable, 1=Enable (causes the line to render all white) u8 BG0_Enable:1; // 8: A+B; 0=Disable, 1=Enable u8 BG1_Enable:1; // 9: A+B; 0=Disable, 1=Enable @@ -143,7 +143,7 @@ typedef union u8 ExBGxPalette_Enable:1; // 30: A+B; 0=Disable, 1=Enable BG extended Palette u8 ExOBJPalette_Enable:1; // 31: A+B; 0=Disable, 1=Enable OBJ extended Palette #else - u8 ForceBlank:1; // 7: A+B; + u8 ForceBlank:1; // 7: A+B; 0=Disable, 1=Enable (causes the line to render all white) u8 OBJ_BMP_mapping:1; // 6: A+B; 0=2D (128KB), 1=1D (128..256KB) u8 OBJ_BMP_2D_dim:1; // 5: A+B; 0=128x512, 1=256x256 pixels u8 OBJ_Tile_mapping:1; // 4: A+B; 0=2D (32KB), 1=1D (32..256KB) @@ -1543,6 +1543,8 @@ protected: void _RenderLine_SetupSprites(GPUEngineCompositorInfo &compInfo); template void _RenderLine_Layers(GPUEngineCompositorInfo &compInfo); + void _RenderLineBlank(const size_t l); + void _HandleDisplayModeOff(const size_t l); void _HandleDisplayModeNormal(const size_t l); @@ -1609,6 +1611,7 @@ public: const GPU_IOREG& GetIORegisterMap() const; + bool IsForceBlankSet() const; bool IsMasterBrightMaxOrMin() const; bool GetEnableState(); From 9515af82b2cbe10cbc50c6762635080134345946 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Fri, 12 Apr 2024 21:39:12 +0200 Subject: [PATCH 26/49] add an issue template for github (#784) --- .../new-issue--bug-report--question.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/new-issue--bug-report--question.md diff --git a/.github/ISSUE_TEMPLATE/new-issue--bug-report--question.md b/.github/ISSUE_TEMPLATE/new-issue--bug-report--question.md new file mode 100644 index 000000000..8b28b2a17 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-issue--bug-report--question.md @@ -0,0 +1,19 @@ +--- +name: New Issue, Bug report, Question +about: New Issue, Bug report, Question +title: '' +labels: '' +assignees: '' + +--- + +## State your operating system: +Windows/Mac/Linux. in case of linux, whether you use CLI, gtk2, or gtk3 version. + +## DesMuME version +e.g. 0.9.13 or git master + +## Isse +type here what's bothering you, in a detailed manner. + + From 4a53a30b91933cc0e34cfb76e8c7d5bd814e9f56 Mon Sep 17 00:00:00 2001 From: zeromus Date: Sun, 12 May 2024 21:33:33 -0400 Subject: [PATCH 27/49] =?UTF-8?q?winport=20-=20fix=20bug=20where=20desmume?= =?UTF-8?q?=20would=20create=20working=20directory=20using=20some=20wrong?= =?UTF-8?q?=20locale=20encoding=20and=20produce=20a=20Pok=E9=AD=AFn=20dire?= =?UTF-8?q?ctory=20instead=20of=20using=20the=20Pok=C3=A9mon=20that=20was?= =?UTF-8?q?=20already=20there=20(fixes=20#791)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- desmume/src/frontend/windows/winutil.cpp | 2 +- desmume/src/path.cpp | 2 +- desmume/src/utils/xstring.cpp | 13 +++++++++++++ desmume/src/utils/xstring.h | 2 ++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/desmume/src/frontend/windows/winutil.cpp b/desmume/src/frontend/windows/winutil.cpp index 1bab5f8d4..07e8b4bad 100644 --- a/desmume/src/frontend/windows/winutil.cpp +++ b/desmume/src/frontend/windows/winutil.cpp @@ -87,7 +87,7 @@ void GetINIPath() } FCEUD_MakePathDirs(IniName); - wcscpy(IniNameW,mbstowcs(IniName).c_str()); //careful to use locale C-style mbstowcs to get IniName (which is with locale encoding) to unicode + wcscpy(IniNameW,mbstowcs_locale(IniName).c_str()); //write BOM to get unicode FILE* test = fopen(IniName,"rb"); diff --git a/desmume/src/path.cpp b/desmume/src/path.cpp index c2c2b883d..d71b07ecf 100644 --- a/desmume/src/path.cpp +++ b/desmume/src/path.cpp @@ -170,7 +170,7 @@ void createDirectoryRecursively(std::wstring path) void FCEUD_MakePathDirs(const char *fname) { - createDirectoryRecursively(mbstowcs(fname)); + createDirectoryRecursively(mbstowcs_locale(fname)); } #endif //------------------------------ diff --git a/desmume/src/utils/xstring.cpp b/desmume/src/utils/xstring.cpp index d491b180b..6b92f5f30 100644 --- a/desmume/src/utils/xstring.cpp +++ b/desmume/src/utils/xstring.cpp @@ -284,6 +284,19 @@ std::string mass_replace(const std::string &source, const std::string &victim, c return answer; } +std::wstring mbstowcs_locale(std::string str) +{ + #ifdef HOST_WINDOWS + int plenty = str.size()*4+1; + wchar_t *wgarbage = new wchar_t[plenty]; + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.data(), -1, wgarbage, plenty); + std::wstring ret = wgarbage; + delete[] wgarbage; + return ret; + #endif + return mbstowcs(str); +} + //convert a std::string to std::wstring std::wstring mbstowcs(std::string str) { diff --git a/desmume/src/utils/xstring.h b/desmume/src/utils/xstring.h index 92a881ceb..5741d998f 100644 --- a/desmume/src/utils/xstring.h +++ b/desmume/src/utils/xstring.h @@ -107,5 +107,7 @@ std::string mass_replace(const std::string &source, const std::string &victim, c std::wstring mbstowcs(std::string str); std::string wcstombs(std::wstring str); +std::wstring mbstowcs_locale(std::string str); + #endif From 738298a9e887bf7220fed026cb872a544fd60431 Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Mon, 13 May 2024 12:47:10 +0100 Subject: [PATCH 28/49] libretro-common: fix implicit declarations strdup and realpath are only declared by glibc's headers if _XOPEN_SOURCE >= 500. --- desmume/src/libretro-common/file/file_path.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desmume/src/libretro-common/file/file_path.c b/desmume/src/libretro-common/file/file_path.c index f5814d307..f6d043d05 100644 --- a/desmume/src/libretro-common/file/file_path.c +++ b/desmume/src/libretro-common/file/file_path.c @@ -20,6 +20,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#define _XOPEN_SOURCE 500 /* For strdup, realpath */ + #include #include #include From ff6c33a8d62067c975a38608d106babac065c98d Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 7 Jun 2024 00:18:02 -0400 Subject: [PATCH 29/49] winport - reduce joystick digitalization threshold from 60% to a more normal 50%. With a too-high threshold, it's impossible to specify diagonals. This is preferable for games without diagonals (else you accidentally crouch when you just meant to walk to the side) instead of 8-way games, so we have to be pretty aggressive about the threshold. But 50 is the more normal choice. --- desmume/src/frontend/windows/inputdx.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/desmume/src/frontend/windows/inputdx.cpp b/desmume/src/frontend/windows/inputdx.cpp index c6a6b40a9..feb00300c 100644 --- a/desmume/src/frontend/windows/inputdx.cpp +++ b/desmume/src/frontend/windows/inputdx.cpp @@ -670,8 +670,12 @@ int FunkyNormalize(int cur, int min, int max) } - -#define S9X_JOY_NEUTRAL 60 +//60 is a poor choice for a threshold; the theoretical maximum you can get even at an exact 45 degree angle is 70 +//Sloshy sticks or slightly-off angles make it impossible to reach 60, as it's far too close to 70. +//Too-small values feel bad, too +//50 is a more normal choice +//#define S9X_JOY_NEUTRAL 60 +#define S9X_JOY_NEUTRAL 50 void CheckAxis (short joy, short control, int val, int min, int max, From ffb8666a8fd8e94a3dbe0d5248c5b758ca2dad97 Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 7 Jun 2024 00:24:55 -0400 Subject: [PATCH 30/49] winport - plumb S9X_JOY_NEUTRAL through inifile: [Controls] DigitalizationThreshold=50 --- desmume/src/frontend/windows/inputdx.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/desmume/src/frontend/windows/inputdx.cpp b/desmume/src/frontend/windows/inputdx.cpp index feb00300c..b3db20f51 100644 --- a/desmume/src/frontend/windows/inputdx.cpp +++ b/desmume/src/frontend/windows/inputdx.cpp @@ -51,6 +51,13 @@ #include "main.h" #include "winutil.h" + //60 is a poor choice for a threshold; the theoretical maximum you can get even at an exact 45 degree angle is 70 + //Sloshy sticks or slightly-off angles make it impossible to reach 60, as it's far too close to 70. + //Too-small values feel bad, too + //50 is a more normal choice + //#define S9X_JOY_NEUTRAL 60 +int S9X_JOY_NEUTRAL = 50; + // Gamepad Dialog Strings // Support Unicode display //#define INPUTCONFIG_TITLE "Input Configuration" @@ -520,6 +527,9 @@ BOOL di_init() { HWND hParentWnd = MainWindow->getHWnd(); + S9X_JOY_NEUTRAL = GetPrivateProfileInt("Controls", "DigitalizationThreshold", S9X_JOY_NEUTRAL, IniName); + + pDI = NULL; memset(cDIBuf, 0, sizeof(cDIBuf)); @@ -669,14 +679,6 @@ int FunkyNormalize(int cur, int min, int max) return Result; } - -//60 is a poor choice for a threshold; the theoretical maximum you can get even at an exact 45 degree angle is 70 -//Sloshy sticks or slightly-off angles make it impossible to reach 60, as it's far too close to 70. -//Too-small values feel bad, too -//50 is a more normal choice -//#define S9X_JOY_NEUTRAL 60 -#define S9X_JOY_NEUTRAL 50 - void CheckAxis (short joy, short control, int val, int min, int max, bool &first, bool &second) From 779606ec2fbaf87de65922286efb91e5b2e16f74 Mon Sep 17 00:00:00 2001 From: rogerman Date: Fri, 7 Jun 2024 16:33:13 -0700 Subject: [PATCH 31/49] libretro: Fix building on Mach-based operating systems, otherwise known as Mac OS X and modern macOS (regression from commit 90d0abd). Based on PR #793. --- desmume/src/libretro-common/file/file_path.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/desmume/src/libretro-common/file/file_path.c b/desmume/src/libretro-common/file/file_path.c index f6d043d05..8836538b7 100644 --- a/desmume/src/libretro-common/file/file_path.c +++ b/desmume/src/libretro-common/file/file_path.c @@ -20,8 +20,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#define _XOPEN_SOURCE 500 /* For strdup, realpath */ - #include #include #include @@ -33,6 +31,7 @@ #include #ifndef __MACH__ +#define _XOPEN_SOURCE 500 /* For strdup, realpath */ #include #include #endif From 6309a9c6a755a59be5d243971bcbd4539e4dd12a Mon Sep 17 00:00:00 2001 From: rogerman Date: Fri, 7 Jun 2024 17:16:53 -0700 Subject: [PATCH 32/49] libretro: So apparently, _XOPEN_SOURCE has to be at the top of the file. Hopefully this makes both GCC14 users and Mac users happy. (Related to commit 779606e. Based on PR #793.) --- desmume/src/libretro-common/file/file_path.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/desmume/src/libretro-common/file/file_path.c b/desmume/src/libretro-common/file/file_path.c index 8836538b7..21e7f1e51 100644 --- a/desmume/src/libretro-common/file/file_path.c +++ b/desmume/src/libretro-common/file/file_path.c @@ -20,6 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifdef __MACH__ +#define _DARWIN_C_SOURCE /* As below, plus strl* functions */ +#else +#define _XOPEN_SOURCE 500 /* For strdup, realpath */ +#endif + #include #include #include @@ -31,7 +37,6 @@ #include #ifndef __MACH__ -#define _XOPEN_SOURCE 500 /* For strdup, realpath */ #include #include #endif From 76bd1a5e353d7e36a662fc37a0c13d010b5962ab Mon Sep 17 00:00:00 2001 From: rogerman Date: Sat, 29 Jun 2024 14:50:47 -0700 Subject: [PATCH 33/49] Change line-ending style in OGLRender.h from Windows-style CRLF to Unix-style LF. --- desmume/src/OGLRender.h | 1870 +++++++++++++++++++-------------------- 1 file changed, 935 insertions(+), 935 deletions(-) diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index ada53834b..93f54b5e1 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -1,935 +1,935 @@ -/* - Copyright (C) 2006 yopyop - Copyright (C) 2006-2007 shash - Copyright (C) 2008-2023 DeSmuME team - - This file 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 file 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 the this software. If not, see . -*/ - -#ifndef OGLRENDER_H -#define OGLRENDER_H - -#include -#include -#include -#include -#include "render3D.h" -#include "types.h" - -#ifndef OGLRENDER_3_2_H - -#if defined(_WIN32) - #define WIN32_LEAN_AND_MEAN - #include - #include - #include - - #define OGLEXT(procPtr, func) procPtr func = NULL; - #define INITOGLEXT(procPtr, func) func = (procPtr)wglGetProcAddress(#func); - #define EXTERNOGLEXT(procPtr, func) extern procPtr func; -#elif defined(__APPLE__) - #include - #include - - // Ignore dynamic linking on Apple OS - #define OGLEXT(procPtr, func) - #define INITOGLEXT(procPtr, func) - #define EXTERNOGLEXT(procPtr, func) - - // We're not exactly committing to OpenGL 3.2 Core Profile just yet, so redefine APPLE - // extensions as a temporary measure. - #if defined(GL_APPLE_vertex_array_object) && !defined(GL_ARB_vertex_array_object) - #define glGenVertexArrays(n, ids) glGenVertexArraysAPPLE(n, ids) - #define glBindVertexArray(id) glBindVertexArrayAPPLE(id) - #define glDeleteVertexArrays(n, ids) glDeleteVertexArraysAPPLE(n, ids) - #endif -#else - #include - #include - #include - - /* This is a workaround needed to compile against nvidia GL headers */ - #ifndef GL_ALPHA_BLEND_EQUATION_ATI - #undef GL_VERSION_1_3 - #endif - - #define OGLEXT(procPtr, func) procPtr func = NULL; - #define INITOGLEXT(procPtr, func) func = (procPtr)glXGetProcAddress((const GLubyte *) #func); - #define EXTERNOGLEXT(procPtr, func) extern procPtr func; -#endif - -// Check minimum OpenGL header version -#if !defined(GL_VERSION_2_1) - #if defined(GL_VERSION_2_0) - #warning Using OpenGL v2.0 headers with v2.1 overrides. Some features will be disabled. - - #if !defined(GL_ARB_framebuffer_object) - // Overrides for GL_EXT_framebuffer_blit - #if !defined(GL_EXT_framebuffer_blit) - #define GL_READ_FRAMEBUFFER_EXT GL_FRAMEBUFFER_EXT - #define GL_DRAW_FRAMEBUFFER_EXT GL_FRAMEBUFFER_EXT - #define glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) - #endif - - // Overrides for GL_EXT_framebuffer_multisample - #if !defined(GL_EXT_framebuffer_multisample) - #define GL_MAX_SAMPLES_EXT 0 - #define glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height) - #endif - - // Overrides for GL_ARB_pixel_buffer_object - #if !defined(GL_PIXEL_PACK_BUFFER) && defined(GL_PIXEL_PACK_BUFFER_ARB) - #define GL_PIXEL_PACK_BUFFER GL_PIXEL_PACK_BUFFER_ARB - #endif - #endif - #else - #error OpenGL requires v2.1 headers or later. - #endif -#endif - -// Textures -#if !defined(GLX_H) -EXTERNOGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 -EXTERNOGLEXT(PFNGLACTIVETEXTUREARBPROC, glActiveTextureARB) -#endif - -// Blending -#if !defined(GLX_H) -EXTERNOGLEXT(PFNGLBLENDEQUATIONPROC, glBlendEquation) // Core in v1.2 -#endif -EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 -EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 - -EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEEXTPROC, glBlendFuncSeparateEXT) -EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEEXTPROC, glBlendEquationSeparateEXT) - -// Shaders -EXTERNOGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 -EXTERNOGLEXT(PFNGLCOMPILESHADERPROC, glCompileShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLCREATEPROGRAMPROC, glCreateProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLATTACHSHADERPROC, glAttachShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLDETACHSHADERPROC, glDetachShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLLINKPROGRAMPROC, glLinkProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLUSEPROGRAMPROC, glUseProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETSHADERIVPROC, glGetShaderiv) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) // Core in v2.0 -EXTERNOGLEXT(PFNGLDELETESHADERPROC, glDeleteShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLDELETEPROGRAMPROC, glDeleteProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETPROGRAMIVPROC, glGetProgramiv) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) // Core in v2.0 -EXTERNOGLEXT(PFNGLVALIDATEPROGRAMPROC, glValidateProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1IPROC, glUniform1i) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1IVPROC, glUniform1iv) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1FPROC, glUniform1f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1FVPROC, glUniform1fv) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM2FPROC, glUniform2f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM4FPROC, glUniform4f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM4FVPROC, glUniform4fv) // Core in v2.0 -EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 - -// Generic vertex attributes -EXTERNOGLEXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) // Core in v2.0 -EXTERNOGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Core in v2.0 -EXTERNOGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 -EXTERNOGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 - -// VAO -EXTERNOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) -EXTERNOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) -EXTERNOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) - -// VBO and PBO -EXTERNOGLEXT(PFNGLGENBUFFERSARBPROC, glGenBuffersARB) -EXTERNOGLEXT(PFNGLDELETEBUFFERSARBPROC, glDeleteBuffersARB) -EXTERNOGLEXT(PFNGLBINDBUFFERARBPROC, glBindBufferARB) -EXTERNOGLEXT(PFNGLBUFFERDATAARBPROC, glBufferDataARB) -EXTERNOGLEXT(PFNGLBUFFERSUBDATAARBPROC, glBufferSubDataARB) -EXTERNOGLEXT(PFNGLMAPBUFFERARBPROC, glMapBufferARB) -EXTERNOGLEXT(PFNGLUNMAPBUFFERARBPROC, glUnmapBufferARB) - -EXTERNOGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 -EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 -EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 -EXTERNOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 -EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 -EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 -EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 - -// FBO -EXTERNOGLEXT(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT) -EXTERNOGLEXT(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT) -EXTERNOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC, glFramebufferRenderbufferEXT) -EXTERNOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DEXTPROC, glFramebufferTexture2DEXT) -EXTERNOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT) -EXTERNOGLEXT(PFNGLDELETEFRAMEBUFFERSEXTPROC, glDeleteFramebuffersEXT) -EXTERNOGLEXT(PFNGLBLITFRAMEBUFFEREXTPROC, glBlitFramebufferEXT) - -// Multisampled FBO -EXTERNOGLEXT(PFNGLGENRENDERBUFFERSEXTPROC, glGenRenderbuffersEXT) -EXTERNOGLEXT(PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) -EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) -EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) -EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) - -#else // OGLRENDER_3_2_H - -// Basic Functions -EXTERNOGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0 -EXTERNOGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 -EXTERNOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 - -// Textures -#if !defined(GLX_H) -EXTERNOGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 -#endif - -// Blending -#if !defined(GLX_H) -EXTERNOGLEXT(PFNGLBLENDEQUATIONPROC, glBlendEquation) // Core in v1.2 -#endif -EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 -EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 - -// Shaders -EXTERNOGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 -EXTERNOGLEXT(PFNGLCOMPILESHADERPROC, glCompileShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLCREATEPROGRAMPROC, glCreateProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLATTACHSHADERPROC, glAttachShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLDETACHSHADERPROC, glDetachShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLLINKPROGRAMPROC, glLinkProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLUSEPROGRAMPROC, glUseProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETSHADERIVPROC, glGetShaderiv) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) // Core in v2.0 -EXTERNOGLEXT(PFNGLDELETESHADERPROC, glDeleteShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLDELETEPROGRAMPROC, glDeleteProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETPROGRAMIVPROC, glGetProgramiv) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) // Core in v2.0 -EXTERNOGLEXT(PFNGLVALIDATEPROGRAMPROC, glValidateProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1IPROC, glUniform1i) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1IVPROC, glUniform1iv) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1FPROC, glUniform1f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1FVPROC, glUniform1fv) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM2FPROC, glUniform2f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM4FPROC, glUniform4f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM4FVPROC, glUniform4fv) // Core in v2.0 -EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 - -// Generic vertex attributes -EXTERNOGLEXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) // Core in v2.0 -EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3 -EXTERNOGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Core in v2.0 -EXTERNOGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 -EXTERNOGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 - -// VAO -EXTERNOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) // Core in v3.0 -EXTERNOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) // Core in v3.0 - -// VBO and PBO -EXTERNOGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 -EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 -EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 -EXTERNOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 -EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 -EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 -EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 - -// Buffer Objects -EXTERNOGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 - -// FBO -EXTERNOGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0 -EXTERNOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0 -EXTERNOGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 - -// Multisampled FBO -EXTERNOGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 -EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 -EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2 - -// UBO -EXTERNOGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 -EXTERNOGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Core in v3.1 -EXTERNOGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 -EXTERNOGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 - -// TBO -EXTERNOGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 - -// Sync Objects -EXTERNOGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 -EXTERNOGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 -EXTERNOGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 - -#endif // OGLRENDER_3_2_H - -// Define the minimum required OpenGL version for the driver to support -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 1 -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR 2 -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION 0 - -#define OGLRENDER_VERT_INDEX_BUFFER_COUNT (CLIPPED_POLYLIST_SIZE * 6) - -// Assign the FBO attachments for the main geometry render -#ifdef OGLRENDER_3_2_H - #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0 - #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3 - #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1 - #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2 -#else - #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0_EXT - #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3_EXT - #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1_EXT - #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2_EXT -#endif - -enum OGLVertexAttributeID -{ - OGLVertexAttributeID_Position = 0, - OGLVertexAttributeID_TexCoord0 = 8, - OGLVertexAttributeID_Color = 3 -}; - -enum OGLTextureUnitID -{ - // Main textures will always be on texture unit 0. - OGLTextureUnitID_FinalColor = 1, - OGLTextureUnitID_GColor, - OGLTextureUnitID_DepthStencil, - OGLTextureUnitID_GPolyID, - OGLTextureUnitID_FogAttr, - OGLTextureUnitID_PolyStates, - OGLTextureUnitID_LookupTable, -}; - -enum OGLBindingPointID -{ - OGLBindingPointID_RenderStates = 0, - OGLBindingPointID_PolyStates = 1 -}; - -enum OGLErrorCode -{ - OGLERROR_NOERR = RENDER3DERROR_NOERR, - - OGLERROR_DRIVER_VERSION_TOO_OLD, - - OGLERROR_BEGINGL_FAILED, - OGLERROR_CLIENT_RESIZE_ERROR, - - OGLERROR_FEATURE_UNSUPPORTED, - OGLERROR_VBO_UNSUPPORTED, - OGLERROR_PBO_UNSUPPORTED, - OGLERROR_SHADER_UNSUPPORTED, - OGLERROR_VAO_UNSUPPORTED, - OGLERROR_FBO_UNSUPPORTED, - OGLERROR_MULTISAMPLED_FBO_UNSUPPORTED, - - OGLERROR_VERTEX_SHADER_PROGRAM_LOAD_ERROR, - OGLERROR_FRAGMENT_SHADER_PROGRAM_LOAD_ERROR, - OGLERROR_SHADER_CREATE_ERROR, - - OGLERROR_FBO_CREATE_ERROR -}; - -enum OGLPolyDrawMode -{ - OGLPolyDrawMode_DrawOpaquePolys = 0, - OGLPolyDrawMode_DrawTranslucentPolys = 1, - OGLPolyDrawMode_ZeroAlphaPass = 2 -}; - -union GLvec2 -{ - GLfloat vec[2]; - struct { GLfloat x, y; }; -}; -typedef union GLvec2 GLvec2; - -union GLvec3 -{ - GLfloat vec[3]; - struct { GLfloat r, g, b; }; - struct { GLfloat x, y, z; }; -}; -typedef union GLvec3 GLvec3; - -union GLvec4 -{ - GLfloat vec[4]; - struct { GLfloat r, g, b, a; }; - struct { GLfloat x, y, z, w; }; -}; -typedef union GLvec4 GLvec4; - -struct OGLVertex -{ - GLvec4 position; - GLvec2 texCoord; - GLvec3 color; -}; -typedef struct OGLVertex OGLVertex; - -struct OGLRenderStates -{ - GLuint enableAntialiasing; - GLuint enableFogAlphaOnly; - GLuint clearPolyID; - GLfloat clearDepth; - GLfloat alphaTestRef; - GLfloat fogOffset; // Currently unused, kept to preserve alignment - GLfloat fogStep; // Currently unused, kept to preserve alignment - GLfloat pad_0; // This needs to be here to preserve alignment - GLvec4 fogColor; - GLvec4 edgeColor[8]; - GLvec4 toonColor[32]; -}; -typedef struct OGLRenderStates OGLRenderStates; - -union OGLPolyStates -{ - u32 packedState; - - struct - { - u8 PolygonID:6; - u8 PolygonMode:2; - - u8 PolygonAlpha:5; - u8 IsWireframe:1; - u8 EnableFog:1; - u8 SetNewDepthForTranslucent:1; - - u8 EnableTexture:1; - u8 TexSingleBitAlpha:1; - u8 TexSizeShiftS:3; - u8 TexSizeShiftT:3; - - u8 IsBackFacing:1; - u8 :7; - }; -}; -typedef union OGLPolyStates OGLPolyStates; - -union OGLGeometryFlags -{ - u8 value; - -#ifndef MSB_FIRST - struct - { - u8 EnableFog:1; - u8 EnableEdgeMark:1; - u8 OpaqueDrawMode:1; - u8 EnableWDepth:1; - u8 EnableAlphaTest:1; - u8 EnableTextureSampling:1; - u8 ToonShadingMode:1; - u8 unused:1; - }; - - struct - { - u8 DrawBuffersMode:3; - u8 :5; - }; -#else - struct - { - u8 unused:1; - u8 ToonShadingMode:1; - u8 EnableTextureSampling:1; - u8 EnableAlphaTest:1; - u8 EnableWDepth:1; - u8 OpaqueDrawMode:1; - u8 EnableEdgeMark:1; - u8 EnableFog:1; - }; - - struct - { - u8 :5; - u8 DrawBuffersMode:3; - }; -#endif -}; -typedef OGLGeometryFlags OGLGeometryFlags; - -union OGLFogProgramKey -{ - u32 key; - - struct - { - u16 offset; - u8 shift; - u8 :8; - }; -}; -typedef OGLFogProgramKey OGLFogProgramKey; - -struct OGLFogShaderID -{ - GLuint program; - GLuint fragShader; -}; -typedef OGLFogShaderID OGLFogShaderID; - -struct OGLRenderRef -{ - // OpenGL Feature Support - GLint stateTexMirroredRepeat; - - // VBO - GLuint vboGeometryVtxID; - GLuint iboGeometryIndexID; - GLuint vboPostprocessVtxID; - - // PBO - GLuint pboRenderDataID; - - // UBO / TBO - GLuint uboRenderStatesID; - GLuint uboPolyStatesID; - GLuint tboPolyStatesID; - GLuint texPolyStatesID; - - // FBO - GLuint texCIColorID; - GLuint texCIFogAttrID; - GLuint texCIDepthStencilID; - - GLuint texGColorID; - GLuint texGFogAttrID; - GLuint texGPolyID; - GLuint texGDepthStencilID; - GLuint texFinalColorID; - GLuint texFogDensityTableID; - GLuint texToonTableID; - GLuint texEdgeColorTableID; - GLuint texMSGColorID; - GLuint texMSGWorkingID; - - GLuint rboMSGColorID; - GLuint rboMSGWorkingID; - GLuint rboMSGPolyID; - GLuint rboMSGFogAttrID; - GLuint rboMSGDepthStencilID; - - GLuint fboClearImageID; - GLuint fboRenderID; - GLuint fboFramebufferFlipID; - GLuint fboMSIntermediateRenderID; - GLuint selectedRenderingFBO; - - // Shader states - GLuint vertexGeometryShaderID; - GLuint fragmentGeometryShaderID[128]; - GLuint programGeometryID[128]; - - GLuint vtxShaderGeometryZeroDstAlphaID; - GLuint fragShaderGeometryZeroDstAlphaID; - GLuint programGeometryZeroDstAlphaID; - - GLuint vtxShaderMSGeometryZeroDstAlphaID; - GLuint fragShaderMSGeometryZeroDstAlphaID; - GLuint programMSGeometryZeroDstAlphaID; - - GLuint vertexEdgeMarkShaderID; - GLuint vertexFogShaderID; - GLuint vertexFramebufferOutput6665ShaderID; - GLuint vertexFramebufferOutput8888ShaderID; - GLuint fragmentEdgeMarkShaderID; - GLuint fragmentFramebufferRGBA6665OutputShaderID; - GLuint fragmentFramebufferRGBA8888OutputShaderID; - GLuint programEdgeMarkID; - GLuint programFramebufferRGBA6665OutputID[2]; - GLuint programFramebufferRGBA8888OutputID[2]; - - GLint uniformStateEnableFogAlphaOnly; - GLint uniformStateClearPolyID; - GLint uniformStateClearDepth; - GLint uniformStateFogColor; - - GLint uniformStateAlphaTestRef[256]; - GLint uniformPolyTexScale[256]; - GLint uniformPolyMode[256]; - GLint uniformPolyIsWireframe[256]; - GLint uniformPolySetNewDepthForTranslucent[256]; - GLint uniformPolyAlpha[256]; - GLint uniformPolyID[256]; - - GLint uniformPolyEnableTexture[256]; - GLint uniformPolyEnableFog[256]; - GLint uniformTexSingleBitAlpha[256]; - GLint uniformTexDrawOpaque[256]; - GLint uniformDrawModeDepthEqualsTest[256]; - GLint uniformPolyIsBackFacing[256]; - - GLint uniformPolyStateIndex[256]; - GLfloat uniformPolyDepthOffset[256]; - GLint uniformPolyDrawShadow[256]; - - // VAO - GLuint vaoGeometryStatesID; - GLuint vaoPostprocessStatesID; - - // Client-side Buffers - GLfloat *position4fBuffer; - GLfloat *texCoord2fBuffer; - GLfloat *color4fBuffer; - CACHE_ALIGN GLushort vertIndexBuffer[OGLRENDER_VERT_INDEX_BUFFER_COUNT]; - CACHE_ALIGN GLushort workingCIColorBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; - CACHE_ALIGN GLuint workingCIDepthStencilBuffer[2][GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; - CACHE_ALIGN GLuint workingCIFogAttributesBuffer[2][GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; -}; -typedef struct OGLRenderRef OGLRenderRef; - -struct GFX3D_State; -struct POLY; -class OpenGLRenderer; - -extern GPU3DInterface gpu3Dgl; -extern GPU3DInterface gpu3DglOld; -extern GPU3DInterface gpu3Dgl_3_2; - -extern const GLenum GeometryDrawBuffersEnum[8][4]; -extern const GLint GeometryAttachmentWorkingBuffer[8]; -extern const GLint GeometryAttachmentPolyID[8]; -extern const GLint GeometryAttachmentFogAttributes[8]; - -extern CACHE_ALIGN const GLfloat divide5bitBy31_LUT[32]; -extern CACHE_ALIGN const GLfloat divide6bitBy63_LUT[64]; -extern const GLfloat PostprocessVtxBuffer[16]; -extern const GLubyte PostprocessElementBuffer[6]; - -//This is called by OGLRender whenever it initializes. -//Platforms, please be sure to set this up. -//return true if you successfully init. -extern bool (*oglrender_init)(); - -//This is called by OGLRender before it uses opengl. -//return true if youre OK with using opengl -extern bool (*oglrender_beginOpenGL)(); - -//This is called by OGLRender after it is done using opengl. -extern void (*oglrender_endOpenGL)(); - -//This is called by OGLRender whenever the framebuffer is resized. -extern bool (*oglrender_framebufferDidResizeCallback)(const bool isFBOSupported, size_t w, size_t h); - -// Helper functions for calling the above function pointers at the -// beginning and ending of OpenGL commands. -bool BEGINGL(); -void ENDGL(); - -// These functions need to be assigned by ports that support using an -// OpenGL 3.2 Core Profile context. The OGLRender_3_2.cpp file includes -// the corresponding functions to assign to each function pointer. -// -// If any of these functions are unassigned, then one of the legacy OpenGL -// renderers will be used instead. -extern void (*OGLLoadEntryPoints_3_2_Func)(); -extern void (*OGLCreateRenderer_3_2_Func)(OpenGLRenderer **rendererPtr); - -bool IsOpenGLDriverVersionSupported(unsigned int checkVersionMajor, unsigned int checkVersionMinor, unsigned int checkVersionRevision); - -class OpenGLTexture : public Render3DTexture -{ -protected: - GLuint _texID; - GLfloat _invSizeS; - GLfloat _invSizeT; - bool _isTexInited; - - u32 *_upscaleBuffer; - -public: - OpenGLTexture(TEXIMAGE_PARAM texAttributes, u32 palAttributes); - virtual ~OpenGLTexture(); - - virtual void Load(bool forceTextureInit); - - GLuint GetID() const; - GLfloat GetInvWidth() const; - GLfloat GetInvHeight() const; - - void SetUnpackBuffer(void *unpackBuffer); - void SetDeposterizeBuffer(void *dstBuffer, void *workingBuffer); - void SetUpscalingBuffer(void *upscaleBuffer); -}; - -#if defined(ENABLE_AVX2) -class OpenGLRenderer : public Render3D_AVX2 -#elif defined(ENABLE_SSE2) -class OpenGLRenderer : public Render3D_SSE2 -#elif defined(ENABLE_NEON_A64) -class OpenGLRenderer : public Render3D_NEON -#elif defined(ENABLE_ALTIVEC) -class OpenGLRenderer : public Render3D_AltiVec -#else -class OpenGLRenderer : public Render3D -#endif -{ -private: - // Driver's OpenGL Version - unsigned int versionMajor; - unsigned int versionMinor; - unsigned int versionRevision; - -private: - Render3DError _FlushFramebufferFlipAndConvertOnCPU(const Color4u8 *__restrict srcFramebuffer, - Color4u8 *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16, - bool doFramebufferFlip, bool doFramebufferConvert); - -protected: - // OpenGL-specific References - OGLRenderRef *ref; - - // OpenGL Feature Support - bool isVBOSupported; - bool isPBOSupported; - bool isFBOSupported; - bool isMultisampledFBOSupported; - bool isShaderSupported; - bool isVAOSupported; - bool willFlipOnlyFramebufferOnGPU; - bool willFlipAndConvertFramebufferOnGPU; - bool willUsePerSampleZeroDstPass; - - bool _emulateShadowPolygon; - bool _emulateSpecialZeroAlphaBlending; - bool _emulateNDSDepthCalculation; - bool _emulateDepthLEqualPolygonFacing; - bool _isDepthLEqualPolygonFacingSupported; - - Color4u8 *_mappedFramebuffer; - Color4u8 *_workingTextureUnpackBuffer; - bool _pixelReadNeedsFinish; - bool _needsZeroDstAlphaPass; - size_t _currentPolyIndex; - bool _enableAlphaBlending; - OGLTextureUnitID _lastTextureDrawTarget; - OGLGeometryFlags _geometryProgramFlags; - OGLFogProgramKey _fogProgramKey; - std::map _fogProgramMap; - - CACHE_ALIGN OGLRenderStates _pendingRenderStates; - - bool _enableMultisampledRendering; - int _selectedMultisampleSize; - size_t _clearImageIndex; - - Render3DError FlushFramebuffer(const Color4u8 *__restrict srcFramebuffer, Color4u8 *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16); - OpenGLTexture* GetLoadedTextureFromPolygon(const POLY &thePoly, bool enableTexturing); - - template size_t DrawPolygonsForIndexRange(const POLY *rawPolyList, const CPoly *clippedPolyList, const size_t clippedPolyCount, size_t firstIndex, size_t lastIndex, size_t &indexOffset, POLYGON_ATTR &lastPolyAttr); - template Render3DError DrawAlphaTexturePolygon(const GLenum polyPrimitive, - const GLsizei vertIndexCount, - const GLushort *indexBufferPtr, - const bool performDepthEqualTest, - const bool enableAlphaDepthWrite, - const bool canHaveOpaqueFragments, - const u8 opaquePolyID, - const bool isPolyFrontFacing); - template Render3DError DrawOtherPolygon(const GLenum polyPrimitive, - const GLsizei vertIndexCount, - const GLushort *indexBufferPtr, - const bool performDepthEqualTest, - const bool enableAlphaDepthWrite, - const u8 opaquePolyID, - const bool isPolyFrontFacing); - - // OpenGL-specific methods - virtual Render3DError CreateVBOs() = 0; - virtual void DestroyVBOs() = 0; - virtual Render3DError CreatePBOs() = 0; - virtual void DestroyPBOs() = 0; - virtual Render3DError CreateFBOs() = 0; - virtual void DestroyFBOs() = 0; - virtual Render3DError CreateMultisampledFBO(GLsizei numSamples) = 0; - virtual void DestroyMultisampledFBO() = 0; - virtual void ResizeMultisampledFBOs(GLsizei numSamples) = 0; - virtual Render3DError CreateVAOs() = 0; - virtual void DestroyVAOs() = 0; - - virtual Render3DError CreateGeometryPrograms() = 0; - virtual void DestroyGeometryPrograms() = 0; - virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString) = 0; - virtual void DestroyGeometryZeroDstAlphaProgram() = 0; - virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString) = 0; - virtual void DestroyEdgeMarkProgram() = 0; - virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString) = 0; - virtual void DestroyFogProgram(const OGLFogProgramKey fogProgramKey) = 0; - virtual void DestroyFogPrograms() = 0; - virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString) = 0; - virtual void DestroyFramebufferOutput6665Programs() = 0; - virtual Render3DError CreateFramebufferOutput8888Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString) = 0; - virtual void DestroyFramebufferOutput8888Programs() = 0; - - virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet) = 0; - virtual Render3DError InitPostprocessingPrograms(const char *edgeMarkVtxShader, - const char *edgeMarkFragShader, - const char *framebufferOutputVtxShader, - const char *framebufferOutputRGBA6665FragShader, - const char *framebufferOutputRGBA8888FragShader) = 0; - - virtual Render3DError UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 opaquePolyID) = 0; - - virtual void GetExtensionSet(std::set *oglExtensionSet) = 0; - virtual void _SetupGeometryShaders(const OGLGeometryFlags flags) = 0; - virtual Render3DError EnableVertexAttributes() = 0; - virtual Render3DError DisableVertexAttributes() = 0; - virtual void _ResolveWorkingBackFacing() = 0; - virtual void _ResolveGeometry() = 0; - virtual Render3DError ReadBackPixels() = 0; - - virtual Render3DError DrawShadowPolygon(const GLenum polyPrimitive, const GLsizei vertIndexCount, const GLushort *indexBufferPtr, const bool performDepthEqualTest, const bool enableAlphaDepthWrite, const bool isTranslucent, const u8 opaquePolyID) = 0; - virtual void SetPolygonIndex(const size_t index) = 0; - virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing) = 0; - -public: - OpenGLRenderer(); - virtual ~OpenGLRenderer(); - - virtual Render3DError InitExtensions() = 0; - - bool IsExtensionPresent(const std::set *oglExtensionSet, const std::string extensionName) const; - Render3DError ShaderProgramCreate(GLuint &vtxShaderID, - GLuint &fragShaderID, - GLuint &programID, - const char *vtxShaderCString, - const char *fragShaderCString); - bool ValidateShaderCompile(GLenum shaderType, GLuint theShader) const; - bool ValidateShaderProgramLink(GLuint theProgram) const; - void GetVersion(unsigned int *major, unsigned int *minor, unsigned int *revision) const; - void SetVersion(unsigned int major, unsigned int minor, unsigned int revision); - bool IsVersionSupported(unsigned int checkVersionMajor, unsigned int checkVersionMinor, unsigned int checkVersionRevision) const; - - virtual Color4u8* GetFramebuffer(); - virtual GLsizei GetLimitedMultisampleSize() const; - - Render3DError ApplyRenderingSettings(const GFX3D_State &renderState); -}; - -class OpenGLRenderer_1_2 : public OpenGLRenderer -{ -protected: - // OpenGL-specific methods - virtual Render3DError CreateVBOs(); - virtual void DestroyVBOs(); - virtual Render3DError CreatePBOs(); - virtual void DestroyPBOs(); - virtual Render3DError CreateFBOs(); - virtual void DestroyFBOs(); - virtual Render3DError CreateMultisampledFBO(GLsizei numSamples); - virtual void DestroyMultisampledFBO(); - virtual void ResizeMultisampledFBOs(GLsizei numSamples); - virtual Render3DError CreateVAOs(); - virtual void DestroyVAOs(); - - virtual Render3DError CreateGeometryPrograms(); - virtual void DestroyGeometryPrograms(); - virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString); - virtual void DestroyGeometryZeroDstAlphaProgram(); - virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString); - virtual void DestroyEdgeMarkProgram(); - virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString); - virtual void DestroyFogProgram(const OGLFogProgramKey fogProgramKey); - virtual void DestroyFogPrograms(); - virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); - virtual void DestroyFramebufferOutput6665Programs(); - virtual Render3DError CreateFramebufferOutput8888Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); - virtual void DestroyFramebufferOutput8888Programs(); - - virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); - virtual Render3DError InitPostprocessingPrograms(const char *edgeMarkVtxShader, - const char *edgeMarkFragShader, - const char *framebufferOutputVtxShader, - const char *framebufferOutputRGBA6665FragShader, - const char *framebufferOutputRGBA8888FragShader); - - virtual Render3DError UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 opaquePolyID); - - virtual void GetExtensionSet(std::set *oglExtensionSet); - virtual void _SetupGeometryShaders(const OGLGeometryFlags flags); - virtual Render3DError EnableVertexAttributes(); - virtual Render3DError DisableVertexAttributes(); - virtual Render3DError ZeroDstAlphaPass(const POLY *rawPolyList, const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); - virtual void _ResolveWorkingBackFacing(); - virtual void _ResolveGeometry(); - virtual Render3DError ReadBackPixels(); - - // Base rendering methods - virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); - virtual Render3DError RenderGeometry(); - virtual Render3DError PostprocessFramebuffer(); - virtual Render3DError EndRender(); - - virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 opaquePolyID); - virtual Render3DError ClearUsingValues(const Color4u8 &clearColor6665, const FragmentAttributes &clearAttributes); - - virtual void SetPolygonIndex(const size_t index); - virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing); - virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); - virtual Render3DError SetupViewport(const GFX3D_Viewport viewport); - - virtual Render3DError DrawShadowPolygon(const GLenum polyPrimitive, const GLsizei vertIndexCount, const GLushort *indexBufferPtr, const bool performDepthEqualTest, const bool enableAlphaDepthWrite, const bool isTranslucent, const u8 opaquePolyID); - -public: - ~OpenGLRenderer_1_2(); - - virtual Render3DError InitExtensions(); - virtual Render3DError Reset(); - virtual Render3DError RenderPowerOff(); - virtual Render3DError RenderFinish(); - virtual Render3DError RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16); - virtual Render3DError SetFramebufferSize(size_t w, size_t h); -}; - -class OpenGLRenderer_2_0 : public OpenGLRenderer_1_2 -{ -protected: - virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); - - virtual Render3DError EnableVertexAttributes(); - virtual Render3DError DisableVertexAttributes(); - - virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); - - virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); -}; - -class OpenGLRenderer_2_1 : public OpenGLRenderer_2_0 -{ -public: - virtual Render3DError RenderFinish(); - virtual Render3DError RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16); -}; - -#endif +/* + Copyright (C) 2006 yopyop + Copyright (C) 2006-2007 shash + Copyright (C) 2008-2023 DeSmuME team + + This file 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 file 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 the this software. If not, see . +*/ + +#ifndef OGLRENDER_H +#define OGLRENDER_H + +#include +#include +#include +#include +#include "render3D.h" +#include "types.h" + +#ifndef OGLRENDER_3_2_H + +#if defined(_WIN32) + #define WIN32_LEAN_AND_MEAN + #include + #include + #include + + #define OGLEXT(procPtr, func) procPtr func = NULL; + #define INITOGLEXT(procPtr, func) func = (procPtr)wglGetProcAddress(#func); + #define EXTERNOGLEXT(procPtr, func) extern procPtr func; +#elif defined(__APPLE__) + #include + #include + + // Ignore dynamic linking on Apple OS + #define OGLEXT(procPtr, func) + #define INITOGLEXT(procPtr, func) + #define EXTERNOGLEXT(procPtr, func) + + // We're not exactly committing to OpenGL 3.2 Core Profile just yet, so redefine APPLE + // extensions as a temporary measure. + #if defined(GL_APPLE_vertex_array_object) && !defined(GL_ARB_vertex_array_object) + #define glGenVertexArrays(n, ids) glGenVertexArraysAPPLE(n, ids) + #define glBindVertexArray(id) glBindVertexArrayAPPLE(id) + #define glDeleteVertexArrays(n, ids) glDeleteVertexArraysAPPLE(n, ids) + #endif +#else + #include + #include + #include + + /* This is a workaround needed to compile against nvidia GL headers */ + #ifndef GL_ALPHA_BLEND_EQUATION_ATI + #undef GL_VERSION_1_3 + #endif + + #define OGLEXT(procPtr, func) procPtr func = NULL; + #define INITOGLEXT(procPtr, func) func = (procPtr)glXGetProcAddress((const GLubyte *) #func); + #define EXTERNOGLEXT(procPtr, func) extern procPtr func; +#endif + +// Check minimum OpenGL header version +#if !defined(GL_VERSION_2_1) + #if defined(GL_VERSION_2_0) + #warning Using OpenGL v2.0 headers with v2.1 overrides. Some features will be disabled. + + #if !defined(GL_ARB_framebuffer_object) + // Overrides for GL_EXT_framebuffer_blit + #if !defined(GL_EXT_framebuffer_blit) + #define GL_READ_FRAMEBUFFER_EXT GL_FRAMEBUFFER_EXT + #define GL_DRAW_FRAMEBUFFER_EXT GL_FRAMEBUFFER_EXT + #define glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) + #endif + + // Overrides for GL_EXT_framebuffer_multisample + #if !defined(GL_EXT_framebuffer_multisample) + #define GL_MAX_SAMPLES_EXT 0 + #define glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height) + #endif + + // Overrides for GL_ARB_pixel_buffer_object + #if !defined(GL_PIXEL_PACK_BUFFER) && defined(GL_PIXEL_PACK_BUFFER_ARB) + #define GL_PIXEL_PACK_BUFFER GL_PIXEL_PACK_BUFFER_ARB + #endif + #endif + #else + #error OpenGL requires v2.1 headers or later. + #endif +#endif + +// Textures +#if !defined(GLX_H) +EXTERNOGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 +EXTERNOGLEXT(PFNGLACTIVETEXTUREARBPROC, glActiveTextureARB) +#endif + +// Blending +#if !defined(GLX_H) +EXTERNOGLEXT(PFNGLBLENDEQUATIONPROC, glBlendEquation) // Core in v1.2 +#endif +EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 +EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 + +EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEEXTPROC, glBlendFuncSeparateEXT) +EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEEXTPROC, glBlendEquationSeparateEXT) + +// Shaders +EXTERNOGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 +EXTERNOGLEXT(PFNGLCOMPILESHADERPROC, glCompileShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLCREATEPROGRAMPROC, glCreateProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLATTACHSHADERPROC, glAttachShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLDETACHSHADERPROC, glDetachShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLLINKPROGRAMPROC, glLinkProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLUSEPROGRAMPROC, glUseProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETSHADERIVPROC, glGetShaderiv) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) // Core in v2.0 +EXTERNOGLEXT(PFNGLDELETESHADERPROC, glDeleteShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLDELETEPROGRAMPROC, glDeleteProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETPROGRAMIVPROC, glGetProgramiv) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) // Core in v2.0 +EXTERNOGLEXT(PFNGLVALIDATEPROGRAMPROC, glValidateProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1IPROC, glUniform1i) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1IVPROC, glUniform1iv) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1FPROC, glUniform1f) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1FVPROC, glUniform1fv) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM2FPROC, glUniform2f) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM4FPROC, glUniform4f) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM4FVPROC, glUniform4fv) // Core in v2.0 +EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 + +// Generic vertex attributes +EXTERNOGLEXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) // Core in v2.0 +EXTERNOGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Core in v2.0 +EXTERNOGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 +EXTERNOGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 + +// VAO +EXTERNOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) +EXTERNOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) +EXTERNOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) + +// VBO and PBO +EXTERNOGLEXT(PFNGLGENBUFFERSARBPROC, glGenBuffersARB) +EXTERNOGLEXT(PFNGLDELETEBUFFERSARBPROC, glDeleteBuffersARB) +EXTERNOGLEXT(PFNGLBINDBUFFERARBPROC, glBindBufferARB) +EXTERNOGLEXT(PFNGLBUFFERDATAARBPROC, glBufferDataARB) +EXTERNOGLEXT(PFNGLBUFFERSUBDATAARBPROC, glBufferSubDataARB) +EXTERNOGLEXT(PFNGLMAPBUFFERARBPROC, glMapBufferARB) +EXTERNOGLEXT(PFNGLUNMAPBUFFERARBPROC, glUnmapBufferARB) + +EXTERNOGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 +EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 +EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 +EXTERNOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 +EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 +EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 +EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 + +// FBO +EXTERNOGLEXT(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT) +EXTERNOGLEXT(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT) +EXTERNOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC, glFramebufferRenderbufferEXT) +EXTERNOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DEXTPROC, glFramebufferTexture2DEXT) +EXTERNOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT) +EXTERNOGLEXT(PFNGLDELETEFRAMEBUFFERSEXTPROC, glDeleteFramebuffersEXT) +EXTERNOGLEXT(PFNGLBLITFRAMEBUFFEREXTPROC, glBlitFramebufferEXT) + +// Multisampled FBO +EXTERNOGLEXT(PFNGLGENRENDERBUFFERSEXTPROC, glGenRenderbuffersEXT) +EXTERNOGLEXT(PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) +EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) +EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) +EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) + +#else // OGLRENDER_3_2_H + +// Basic Functions +EXTERNOGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0 +EXTERNOGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 +EXTERNOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 + +// Textures +#if !defined(GLX_H) +EXTERNOGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 +#endif + +// Blending +#if !defined(GLX_H) +EXTERNOGLEXT(PFNGLBLENDEQUATIONPROC, glBlendEquation) // Core in v1.2 +#endif +EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 +EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 + +// Shaders +EXTERNOGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 +EXTERNOGLEXT(PFNGLCOMPILESHADERPROC, glCompileShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLCREATEPROGRAMPROC, glCreateProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLATTACHSHADERPROC, glAttachShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLDETACHSHADERPROC, glDetachShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLLINKPROGRAMPROC, glLinkProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLUSEPROGRAMPROC, glUseProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETSHADERIVPROC, glGetShaderiv) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) // Core in v2.0 +EXTERNOGLEXT(PFNGLDELETESHADERPROC, glDeleteShader) // Core in v2.0 +EXTERNOGLEXT(PFNGLDELETEPROGRAMPROC, glDeleteProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETPROGRAMIVPROC, glGetProgramiv) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) // Core in v2.0 +EXTERNOGLEXT(PFNGLVALIDATEPROGRAMPROC, glValidateProgram) // Core in v2.0 +EXTERNOGLEXT(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1IPROC, glUniform1i) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1IVPROC, glUniform1iv) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1FPROC, glUniform1f) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM1FVPROC, glUniform1fv) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM2FPROC, glUniform2f) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM4FPROC, glUniform4f) // Core in v2.0 +EXTERNOGLEXT(PFNGLUNIFORM4FVPROC, glUniform4fv) // Core in v2.0 +EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 + +// Generic vertex attributes +EXTERNOGLEXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) // Core in v2.0 +EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0 +EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3 +EXTERNOGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Core in v2.0 +EXTERNOGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 +EXTERNOGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 + +// VAO +EXTERNOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) // Core in v3.0 +EXTERNOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) // Core in v3.0 +EXTERNOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) // Core in v3.0 + +// VBO and PBO +EXTERNOGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 +EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 +EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 +EXTERNOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 +EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 +EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 +EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 + +// Buffer Objects +EXTERNOGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 + +// FBO +EXTERNOGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0 +EXTERNOGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0 +EXTERNOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0 +EXTERNOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0 +EXTERNOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0 +EXTERNOGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0 +EXTERNOGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0 +EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 + +// Multisampled FBO +EXTERNOGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0 +EXTERNOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 +EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 +EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 +EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 +EXTERNOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2 + +// UBO +EXTERNOGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 +EXTERNOGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Core in v3.1 +EXTERNOGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 +EXTERNOGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 + +// TBO +EXTERNOGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 + +// Sync Objects +EXTERNOGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 +EXTERNOGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 +EXTERNOGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 + +#endif // OGLRENDER_3_2_H + +// Define the minimum required OpenGL version for the driver to support +#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 1 +#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR 2 +#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION 0 + +#define OGLRENDER_VERT_INDEX_BUFFER_COUNT (CLIPPED_POLYLIST_SIZE * 6) + +// Assign the FBO attachments for the main geometry render +#ifdef OGLRENDER_3_2_H + #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0 + #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3 + #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1 + #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2 +#else + #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0_EXT + #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3_EXT + #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1_EXT + #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2_EXT +#endif + +enum OGLVertexAttributeID +{ + OGLVertexAttributeID_Position = 0, + OGLVertexAttributeID_TexCoord0 = 8, + OGLVertexAttributeID_Color = 3 +}; + +enum OGLTextureUnitID +{ + // Main textures will always be on texture unit 0. + OGLTextureUnitID_FinalColor = 1, + OGLTextureUnitID_GColor, + OGLTextureUnitID_DepthStencil, + OGLTextureUnitID_GPolyID, + OGLTextureUnitID_FogAttr, + OGLTextureUnitID_PolyStates, + OGLTextureUnitID_LookupTable, +}; + +enum OGLBindingPointID +{ + OGLBindingPointID_RenderStates = 0, + OGLBindingPointID_PolyStates = 1 +}; + +enum OGLErrorCode +{ + OGLERROR_NOERR = RENDER3DERROR_NOERR, + + OGLERROR_DRIVER_VERSION_TOO_OLD, + + OGLERROR_BEGINGL_FAILED, + OGLERROR_CLIENT_RESIZE_ERROR, + + OGLERROR_FEATURE_UNSUPPORTED, + OGLERROR_VBO_UNSUPPORTED, + OGLERROR_PBO_UNSUPPORTED, + OGLERROR_SHADER_UNSUPPORTED, + OGLERROR_VAO_UNSUPPORTED, + OGLERROR_FBO_UNSUPPORTED, + OGLERROR_MULTISAMPLED_FBO_UNSUPPORTED, + + OGLERROR_VERTEX_SHADER_PROGRAM_LOAD_ERROR, + OGLERROR_FRAGMENT_SHADER_PROGRAM_LOAD_ERROR, + OGLERROR_SHADER_CREATE_ERROR, + + OGLERROR_FBO_CREATE_ERROR +}; + +enum OGLPolyDrawMode +{ + OGLPolyDrawMode_DrawOpaquePolys = 0, + OGLPolyDrawMode_DrawTranslucentPolys = 1, + OGLPolyDrawMode_ZeroAlphaPass = 2 +}; + +union GLvec2 +{ + GLfloat vec[2]; + struct { GLfloat x, y; }; +}; +typedef union GLvec2 GLvec2; + +union GLvec3 +{ + GLfloat vec[3]; + struct { GLfloat r, g, b; }; + struct { GLfloat x, y, z; }; +}; +typedef union GLvec3 GLvec3; + +union GLvec4 +{ + GLfloat vec[4]; + struct { GLfloat r, g, b, a; }; + struct { GLfloat x, y, z, w; }; +}; +typedef union GLvec4 GLvec4; + +struct OGLVertex +{ + GLvec4 position; + GLvec2 texCoord; + GLvec3 color; +}; +typedef struct OGLVertex OGLVertex; + +struct OGLRenderStates +{ + GLuint enableAntialiasing; + GLuint enableFogAlphaOnly; + GLuint clearPolyID; + GLfloat clearDepth; + GLfloat alphaTestRef; + GLfloat fogOffset; // Currently unused, kept to preserve alignment + GLfloat fogStep; // Currently unused, kept to preserve alignment + GLfloat pad_0; // This needs to be here to preserve alignment + GLvec4 fogColor; + GLvec4 edgeColor[8]; + GLvec4 toonColor[32]; +}; +typedef struct OGLRenderStates OGLRenderStates; + +union OGLPolyStates +{ + u32 packedState; + + struct + { + u8 PolygonID:6; + u8 PolygonMode:2; + + u8 PolygonAlpha:5; + u8 IsWireframe:1; + u8 EnableFog:1; + u8 SetNewDepthForTranslucent:1; + + u8 EnableTexture:1; + u8 TexSingleBitAlpha:1; + u8 TexSizeShiftS:3; + u8 TexSizeShiftT:3; + + u8 IsBackFacing:1; + u8 :7; + }; +}; +typedef union OGLPolyStates OGLPolyStates; + +union OGLGeometryFlags +{ + u8 value; + +#ifndef MSB_FIRST + struct + { + u8 EnableFog:1; + u8 EnableEdgeMark:1; + u8 OpaqueDrawMode:1; + u8 EnableWDepth:1; + u8 EnableAlphaTest:1; + u8 EnableTextureSampling:1; + u8 ToonShadingMode:1; + u8 unused:1; + }; + + struct + { + u8 DrawBuffersMode:3; + u8 :5; + }; +#else + struct + { + u8 unused:1; + u8 ToonShadingMode:1; + u8 EnableTextureSampling:1; + u8 EnableAlphaTest:1; + u8 EnableWDepth:1; + u8 OpaqueDrawMode:1; + u8 EnableEdgeMark:1; + u8 EnableFog:1; + }; + + struct + { + u8 :5; + u8 DrawBuffersMode:3; + }; +#endif +}; +typedef OGLGeometryFlags OGLGeometryFlags; + +union OGLFogProgramKey +{ + u32 key; + + struct + { + u16 offset; + u8 shift; + u8 :8; + }; +}; +typedef OGLFogProgramKey OGLFogProgramKey; + +struct OGLFogShaderID +{ + GLuint program; + GLuint fragShader; +}; +typedef OGLFogShaderID OGLFogShaderID; + +struct OGLRenderRef +{ + // OpenGL Feature Support + GLint stateTexMirroredRepeat; + + // VBO + GLuint vboGeometryVtxID; + GLuint iboGeometryIndexID; + GLuint vboPostprocessVtxID; + + // PBO + GLuint pboRenderDataID; + + // UBO / TBO + GLuint uboRenderStatesID; + GLuint uboPolyStatesID; + GLuint tboPolyStatesID; + GLuint texPolyStatesID; + + // FBO + GLuint texCIColorID; + GLuint texCIFogAttrID; + GLuint texCIDepthStencilID; + + GLuint texGColorID; + GLuint texGFogAttrID; + GLuint texGPolyID; + GLuint texGDepthStencilID; + GLuint texFinalColorID; + GLuint texFogDensityTableID; + GLuint texToonTableID; + GLuint texEdgeColorTableID; + GLuint texMSGColorID; + GLuint texMSGWorkingID; + + GLuint rboMSGColorID; + GLuint rboMSGWorkingID; + GLuint rboMSGPolyID; + GLuint rboMSGFogAttrID; + GLuint rboMSGDepthStencilID; + + GLuint fboClearImageID; + GLuint fboRenderID; + GLuint fboFramebufferFlipID; + GLuint fboMSIntermediateRenderID; + GLuint selectedRenderingFBO; + + // Shader states + GLuint vertexGeometryShaderID; + GLuint fragmentGeometryShaderID[128]; + GLuint programGeometryID[128]; + + GLuint vtxShaderGeometryZeroDstAlphaID; + GLuint fragShaderGeometryZeroDstAlphaID; + GLuint programGeometryZeroDstAlphaID; + + GLuint vtxShaderMSGeometryZeroDstAlphaID; + GLuint fragShaderMSGeometryZeroDstAlphaID; + GLuint programMSGeometryZeroDstAlphaID; + + GLuint vertexEdgeMarkShaderID; + GLuint vertexFogShaderID; + GLuint vertexFramebufferOutput6665ShaderID; + GLuint vertexFramebufferOutput8888ShaderID; + GLuint fragmentEdgeMarkShaderID; + GLuint fragmentFramebufferRGBA6665OutputShaderID; + GLuint fragmentFramebufferRGBA8888OutputShaderID; + GLuint programEdgeMarkID; + GLuint programFramebufferRGBA6665OutputID[2]; + GLuint programFramebufferRGBA8888OutputID[2]; + + GLint uniformStateEnableFogAlphaOnly; + GLint uniformStateClearPolyID; + GLint uniformStateClearDepth; + GLint uniformStateFogColor; + + GLint uniformStateAlphaTestRef[256]; + GLint uniformPolyTexScale[256]; + GLint uniformPolyMode[256]; + GLint uniformPolyIsWireframe[256]; + GLint uniformPolySetNewDepthForTranslucent[256]; + GLint uniformPolyAlpha[256]; + GLint uniformPolyID[256]; + + GLint uniformPolyEnableTexture[256]; + GLint uniformPolyEnableFog[256]; + GLint uniformTexSingleBitAlpha[256]; + GLint uniformTexDrawOpaque[256]; + GLint uniformDrawModeDepthEqualsTest[256]; + GLint uniformPolyIsBackFacing[256]; + + GLint uniformPolyStateIndex[256]; + GLfloat uniformPolyDepthOffset[256]; + GLint uniformPolyDrawShadow[256]; + + // VAO + GLuint vaoGeometryStatesID; + GLuint vaoPostprocessStatesID; + + // Client-side Buffers + GLfloat *position4fBuffer; + GLfloat *texCoord2fBuffer; + GLfloat *color4fBuffer; + CACHE_ALIGN GLushort vertIndexBuffer[OGLRENDER_VERT_INDEX_BUFFER_COUNT]; + CACHE_ALIGN GLushort workingCIColorBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; + CACHE_ALIGN GLuint workingCIDepthStencilBuffer[2][GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; + CACHE_ALIGN GLuint workingCIFogAttributesBuffer[2][GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; +}; +typedef struct OGLRenderRef OGLRenderRef; + +struct GFX3D_State; +struct POLY; +class OpenGLRenderer; + +extern GPU3DInterface gpu3Dgl; +extern GPU3DInterface gpu3DglOld; +extern GPU3DInterface gpu3Dgl_3_2; + +extern const GLenum GeometryDrawBuffersEnum[8][4]; +extern const GLint GeometryAttachmentWorkingBuffer[8]; +extern const GLint GeometryAttachmentPolyID[8]; +extern const GLint GeometryAttachmentFogAttributes[8]; + +extern CACHE_ALIGN const GLfloat divide5bitBy31_LUT[32]; +extern CACHE_ALIGN const GLfloat divide6bitBy63_LUT[64]; +extern const GLfloat PostprocessVtxBuffer[16]; +extern const GLubyte PostprocessElementBuffer[6]; + +//This is called by OGLRender whenever it initializes. +//Platforms, please be sure to set this up. +//return true if you successfully init. +extern bool (*oglrender_init)(); + +//This is called by OGLRender before it uses opengl. +//return true if youre OK with using opengl +extern bool (*oglrender_beginOpenGL)(); + +//This is called by OGLRender after it is done using opengl. +extern void (*oglrender_endOpenGL)(); + +//This is called by OGLRender whenever the framebuffer is resized. +extern bool (*oglrender_framebufferDidResizeCallback)(const bool isFBOSupported, size_t w, size_t h); + +// Helper functions for calling the above function pointers at the +// beginning and ending of OpenGL commands. +bool BEGINGL(); +void ENDGL(); + +// These functions need to be assigned by ports that support using an +// OpenGL 3.2 Core Profile context. The OGLRender_3_2.cpp file includes +// the corresponding functions to assign to each function pointer. +// +// If any of these functions are unassigned, then one of the legacy OpenGL +// renderers will be used instead. +extern void (*OGLLoadEntryPoints_3_2_Func)(); +extern void (*OGLCreateRenderer_3_2_Func)(OpenGLRenderer **rendererPtr); + +bool IsOpenGLDriverVersionSupported(unsigned int checkVersionMajor, unsigned int checkVersionMinor, unsigned int checkVersionRevision); + +class OpenGLTexture : public Render3DTexture +{ +protected: + GLuint _texID; + GLfloat _invSizeS; + GLfloat _invSizeT; + bool _isTexInited; + + u32 *_upscaleBuffer; + +public: + OpenGLTexture(TEXIMAGE_PARAM texAttributes, u32 palAttributes); + virtual ~OpenGLTexture(); + + virtual void Load(bool forceTextureInit); + + GLuint GetID() const; + GLfloat GetInvWidth() const; + GLfloat GetInvHeight() const; + + void SetUnpackBuffer(void *unpackBuffer); + void SetDeposterizeBuffer(void *dstBuffer, void *workingBuffer); + void SetUpscalingBuffer(void *upscaleBuffer); +}; + +#if defined(ENABLE_AVX2) +class OpenGLRenderer : public Render3D_AVX2 +#elif defined(ENABLE_SSE2) +class OpenGLRenderer : public Render3D_SSE2 +#elif defined(ENABLE_NEON_A64) +class OpenGLRenderer : public Render3D_NEON +#elif defined(ENABLE_ALTIVEC) +class OpenGLRenderer : public Render3D_AltiVec +#else +class OpenGLRenderer : public Render3D +#endif +{ +private: + // Driver's OpenGL Version + unsigned int versionMajor; + unsigned int versionMinor; + unsigned int versionRevision; + +private: + Render3DError _FlushFramebufferFlipAndConvertOnCPU(const Color4u8 *__restrict srcFramebuffer, + Color4u8 *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16, + bool doFramebufferFlip, bool doFramebufferConvert); + +protected: + // OpenGL-specific References + OGLRenderRef *ref; + + // OpenGL Feature Support + bool isVBOSupported; + bool isPBOSupported; + bool isFBOSupported; + bool isMultisampledFBOSupported; + bool isShaderSupported; + bool isVAOSupported; + bool willFlipOnlyFramebufferOnGPU; + bool willFlipAndConvertFramebufferOnGPU; + bool willUsePerSampleZeroDstPass; + + bool _emulateShadowPolygon; + bool _emulateSpecialZeroAlphaBlending; + bool _emulateNDSDepthCalculation; + bool _emulateDepthLEqualPolygonFacing; + bool _isDepthLEqualPolygonFacingSupported; + + Color4u8 *_mappedFramebuffer; + Color4u8 *_workingTextureUnpackBuffer; + bool _pixelReadNeedsFinish; + bool _needsZeroDstAlphaPass; + size_t _currentPolyIndex; + bool _enableAlphaBlending; + OGLTextureUnitID _lastTextureDrawTarget; + OGLGeometryFlags _geometryProgramFlags; + OGLFogProgramKey _fogProgramKey; + std::map _fogProgramMap; + + CACHE_ALIGN OGLRenderStates _pendingRenderStates; + + bool _enableMultisampledRendering; + int _selectedMultisampleSize; + size_t _clearImageIndex; + + Render3DError FlushFramebuffer(const Color4u8 *__restrict srcFramebuffer, Color4u8 *__restrict dstFramebufferMain, u16 *__restrict dstFramebuffer16); + OpenGLTexture* GetLoadedTextureFromPolygon(const POLY &thePoly, bool enableTexturing); + + template size_t DrawPolygonsForIndexRange(const POLY *rawPolyList, const CPoly *clippedPolyList, const size_t clippedPolyCount, size_t firstIndex, size_t lastIndex, size_t &indexOffset, POLYGON_ATTR &lastPolyAttr); + template Render3DError DrawAlphaTexturePolygon(const GLenum polyPrimitive, + const GLsizei vertIndexCount, + const GLushort *indexBufferPtr, + const bool performDepthEqualTest, + const bool enableAlphaDepthWrite, + const bool canHaveOpaqueFragments, + const u8 opaquePolyID, + const bool isPolyFrontFacing); + template Render3DError DrawOtherPolygon(const GLenum polyPrimitive, + const GLsizei vertIndexCount, + const GLushort *indexBufferPtr, + const bool performDepthEqualTest, + const bool enableAlphaDepthWrite, + const u8 opaquePolyID, + const bool isPolyFrontFacing); + + // OpenGL-specific methods + virtual Render3DError CreateVBOs() = 0; + virtual void DestroyVBOs() = 0; + virtual Render3DError CreatePBOs() = 0; + virtual void DestroyPBOs() = 0; + virtual Render3DError CreateFBOs() = 0; + virtual void DestroyFBOs() = 0; + virtual Render3DError CreateMultisampledFBO(GLsizei numSamples) = 0; + virtual void DestroyMultisampledFBO() = 0; + virtual void ResizeMultisampledFBOs(GLsizei numSamples) = 0; + virtual Render3DError CreateVAOs() = 0; + virtual void DestroyVAOs() = 0; + + virtual Render3DError CreateGeometryPrograms() = 0; + virtual void DestroyGeometryPrograms() = 0; + virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString) = 0; + virtual void DestroyGeometryZeroDstAlphaProgram() = 0; + virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString) = 0; + virtual void DestroyEdgeMarkProgram() = 0; + virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString) = 0; + virtual void DestroyFogProgram(const OGLFogProgramKey fogProgramKey) = 0; + virtual void DestroyFogPrograms() = 0; + virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString) = 0; + virtual void DestroyFramebufferOutput6665Programs() = 0; + virtual Render3DError CreateFramebufferOutput8888Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString) = 0; + virtual void DestroyFramebufferOutput8888Programs() = 0; + + virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet) = 0; + virtual Render3DError InitPostprocessingPrograms(const char *edgeMarkVtxShader, + const char *edgeMarkFragShader, + const char *framebufferOutputVtxShader, + const char *framebufferOutputRGBA6665FragShader, + const char *framebufferOutputRGBA8888FragShader) = 0; + + virtual Render3DError UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 opaquePolyID) = 0; + + virtual void GetExtensionSet(std::set *oglExtensionSet) = 0; + virtual void _SetupGeometryShaders(const OGLGeometryFlags flags) = 0; + virtual Render3DError EnableVertexAttributes() = 0; + virtual Render3DError DisableVertexAttributes() = 0; + virtual void _ResolveWorkingBackFacing() = 0; + virtual void _ResolveGeometry() = 0; + virtual Render3DError ReadBackPixels() = 0; + + virtual Render3DError DrawShadowPolygon(const GLenum polyPrimitive, const GLsizei vertIndexCount, const GLushort *indexBufferPtr, const bool performDepthEqualTest, const bool enableAlphaDepthWrite, const bool isTranslucent, const u8 opaquePolyID) = 0; + virtual void SetPolygonIndex(const size_t index) = 0; + virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing) = 0; + +public: + OpenGLRenderer(); + virtual ~OpenGLRenderer(); + + virtual Render3DError InitExtensions() = 0; + + bool IsExtensionPresent(const std::set *oglExtensionSet, const std::string extensionName) const; + Render3DError ShaderProgramCreate(GLuint &vtxShaderID, + GLuint &fragShaderID, + GLuint &programID, + const char *vtxShaderCString, + const char *fragShaderCString); + bool ValidateShaderCompile(GLenum shaderType, GLuint theShader) const; + bool ValidateShaderProgramLink(GLuint theProgram) const; + void GetVersion(unsigned int *major, unsigned int *minor, unsigned int *revision) const; + void SetVersion(unsigned int major, unsigned int minor, unsigned int revision); + bool IsVersionSupported(unsigned int checkVersionMajor, unsigned int checkVersionMinor, unsigned int checkVersionRevision) const; + + virtual Color4u8* GetFramebuffer(); + virtual GLsizei GetLimitedMultisampleSize() const; + + Render3DError ApplyRenderingSettings(const GFX3D_State &renderState); +}; + +class OpenGLRenderer_1_2 : public OpenGLRenderer +{ +protected: + // OpenGL-specific methods + virtual Render3DError CreateVBOs(); + virtual void DestroyVBOs(); + virtual Render3DError CreatePBOs(); + virtual void DestroyPBOs(); + virtual Render3DError CreateFBOs(); + virtual void DestroyFBOs(); + virtual Render3DError CreateMultisampledFBO(GLsizei numSamples); + virtual void DestroyMultisampledFBO(); + virtual void ResizeMultisampledFBOs(GLsizei numSamples); + virtual Render3DError CreateVAOs(); + virtual void DestroyVAOs(); + + virtual Render3DError CreateGeometryPrograms(); + virtual void DestroyGeometryPrograms(); + virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString); + virtual void DestroyGeometryZeroDstAlphaProgram(); + virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString); + virtual void DestroyEdgeMarkProgram(); + virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString); + virtual void DestroyFogProgram(const OGLFogProgramKey fogProgramKey); + virtual void DestroyFogPrograms(); + virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); + virtual void DestroyFramebufferOutput6665Programs(); + virtual Render3DError CreateFramebufferOutput8888Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); + virtual void DestroyFramebufferOutput8888Programs(); + + virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); + virtual Render3DError InitPostprocessingPrograms(const char *edgeMarkVtxShader, + const char *edgeMarkFragShader, + const char *framebufferOutputVtxShader, + const char *framebufferOutputRGBA6665FragShader, + const char *framebufferOutputRGBA8888FragShader); + + virtual Render3DError UploadClearImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 opaquePolyID); + + virtual void GetExtensionSet(std::set *oglExtensionSet); + virtual void _SetupGeometryShaders(const OGLGeometryFlags flags); + virtual Render3DError EnableVertexAttributes(); + virtual Render3DError DisableVertexAttributes(); + virtual Render3DError ZeroDstAlphaPass(const POLY *rawPolyList, const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); + virtual void _ResolveWorkingBackFacing(); + virtual void _ResolveGeometry(); + virtual Render3DError ReadBackPixels(); + + // Base rendering methods + virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); + virtual Render3DError RenderGeometry(); + virtual Render3DError PostprocessFramebuffer(); + virtual Render3DError EndRender(); + + virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const u8 *__restrict fogBuffer, const u8 opaquePolyID); + virtual Render3DError ClearUsingValues(const Color4u8 &clearColor6665, const FragmentAttributes &clearAttributes); + + virtual void SetPolygonIndex(const size_t index); + virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing); + virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); + virtual Render3DError SetupViewport(const GFX3D_Viewport viewport); + + virtual Render3DError DrawShadowPolygon(const GLenum polyPrimitive, const GLsizei vertIndexCount, const GLushort *indexBufferPtr, const bool performDepthEqualTest, const bool enableAlphaDepthWrite, const bool isTranslucent, const u8 opaquePolyID); + +public: + ~OpenGLRenderer_1_2(); + + virtual Render3DError InitExtensions(); + virtual Render3DError Reset(); + virtual Render3DError RenderPowerOff(); + virtual Render3DError RenderFinish(); + virtual Render3DError RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16); + virtual Render3DError SetFramebufferSize(size_t w, size_t h); +}; + +class OpenGLRenderer_2_0 : public OpenGLRenderer_1_2 +{ +protected: + virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); + + virtual Render3DError EnableVertexAttributes(); + virtual Render3DError DisableVertexAttributes(); + + virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); + + virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); +}; + +class OpenGLRenderer_2_1 : public OpenGLRenderer_2_0 +{ +public: + virtual Render3DError RenderFinish(); + virtual Render3DError RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16); +}; + +#endif From 086980deaf88dbe57780003c8d4ff0b383fe62fb Mon Sep 17 00:00:00 2001 From: rogerman Date: Mon, 1 Jul 2024 16:19:05 -0700 Subject: [PATCH 34/49] OpenGL: Start reorganizing stuff in preparation for adding new OpenGL variants, such as OpenGL ES. - All platform-specific header includes are now centralized in OGLRender.h. - Remove all ARB and EXT versions of legacy functions (everything pre 3.0). Legacy functions now only reference their core versions. - Do a some minor code cleanup. --- desmume/src/OGLRender.cpp | 206 ++++----- desmume/src/OGLRender.h | 401 ++++++++++-------- desmume/src/OGLRender_3_2.cpp | 113 ++--- desmume/src/OGLRender_3_2.h | 36 +- desmume/src/frontend/posix/gtk/main.cpp | 3 +- .../src/frontend/posix/gtk/osmesa_3Demu.cpp | 3 +- desmume/src/frontend/posix/gtk2/main.cpp | 3 +- .../src/frontend/posix/gtk2/osmesa_3Demu.cpp | 3 +- desmume/src/frontend/windows/main.cpp | 5 +- 9 files changed, 373 insertions(+), 400 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 9e8a430f0..63c6180f1 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2023 DeSmuME team + Copyright (C) 2008-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -130,14 +130,14 @@ const GLint GeometryAttachmentFogAttributes[8] = { bool BEGINGL() { - if(oglrender_beginOpenGL) + if (oglrender_beginOpenGL) return oglrender_beginOpenGL(); else return true; } void ENDGL() { - if(oglrender_endOpenGL) + if (oglrender_endOpenGL) oglrender_endOpenGL(); } @@ -154,7 +154,6 @@ void (*OGLCreateRenderer_3_2_Func)(OpenGLRenderer **rendererPtr) = NULL; // Textures #if !defined(GLX_H) OGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 -OGLEXT(PFNGLACTIVETEXTUREARBPROC, glActiveTextureARB) #endif // Blending @@ -164,9 +163,6 @@ OGLEXT(PFNGLBLENDEQUATIONPROC, glBlendEquation) // Core in v1.2 OGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 OGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 -OGLEXT(PFNGLBLENDFUNCSEPARATEEXTPROC, glBlendFuncSeparateEXT) -OGLEXT(PFNGLBLENDEQUATIONSEPARATEEXTPROC, glBlendEquationSeparateEXT) - // Shaders OGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 OGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 @@ -192,24 +188,17 @@ OGLEXT(PFNGLUNIFORM2FPROC, glUniform2f) // Core in v2.0 OGLEXT(PFNGLUNIFORM4FPROC, glUniform4f) // Core in v2.0 OGLEXT(PFNGLUNIFORM4FVPROC, glUniform4fv) // Core in v2.0 OGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 + +// Generic vertex attributes OGLEXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) // Core in v2.0 OGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Core in v2.0 OGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 OGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 -// VAO -OGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) -OGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) -OGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) - -// Buffer Objects -OGLEXT(PFNGLGENBUFFERSARBPROC, glGenBuffersARB) -OGLEXT(PFNGLDELETEBUFFERSARBPROC, glDeleteBuffersARB) -OGLEXT(PFNGLBINDBUFFERARBPROC, glBindBufferARB) -OGLEXT(PFNGLBUFFERDATAARBPROC, glBufferDataARB) -OGLEXT(PFNGLBUFFERSUBDATAARBPROC, glBufferSubDataARB) -OGLEXT(PFNGLMAPBUFFERARBPROC, glMapBufferARB) -OGLEXT(PFNGLUNMAPBUFFERARBPROC, glUnmapBufferARB) +// VAO (always available in Apple's implementation of OpenGL, including old versions) +OGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) // Core in v3.0 and ES v3.0 +OGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) // Core in v3.0 and ES v3.0 +OGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) // Core in v3.0 and ES v3.0 OGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 OGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 @@ -219,6 +208,7 @@ OGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 OGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 OGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 +#ifdef GL_EXT_framebuffer_object // FBO OGLEXT(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT) OGLEXT(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT) @@ -227,18 +217,20 @@ OGLEXT(PFNGLFRAMEBUFFERTEXTURE2DEXTPROC, glFramebufferTexture2DEXT) OGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT) OGLEXT(PFNGLDELETEFRAMEBUFFERSEXTPROC, glDeleteFramebuffersEXT) OGLEXT(PFNGLBLITFRAMEBUFFEREXTPROC, glBlitFramebufferEXT) + +// Multisampled FBO OGLEXT(PFNGLGENRENDERBUFFERSEXTPROC, glGenRenderbuffersEXT) OGLEXT(PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) OGLEXT(PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) OGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) OGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) +#endif // GL_EXT_framebuffer_object static void OGLLoadEntryPoints_Legacy() { // Textures #if !defined(GLX_H) INITOGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 - INITOGLEXT(PFNGLACTIVETEXTUREARBPROC, glActiveTextureARB) #endif // Blending @@ -248,9 +240,6 @@ static void OGLLoadEntryPoints_Legacy() INITOGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 INITOGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 - INITOGLEXT(PFNGLBLENDFUNCSEPARATEEXTPROC, glBlendFuncSeparateEXT) - INITOGLEXT(PFNGLBLENDEQUATIONSEPARATEEXTPROC, glBlendEquationSeparateEXT) - // Shaders INITOGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 INITOGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 @@ -276,25 +265,14 @@ static void OGLLoadEntryPoints_Legacy() INITOGLEXT(PFNGLUNIFORM4FPROC, glUniform4f) // Core in v2.0 INITOGLEXT(PFNGLUNIFORM4FVPROC, glUniform4fv) // Core in v2.0 INITOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 + + // Generic vertex attributes INITOGLEXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) // Core in v2.0 INITOGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Core in v2.0 INITOGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 INITOGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 - // VAO - INITOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) - INITOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) - INITOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) - // Buffer Objects - INITOGLEXT(PFNGLGENBUFFERSARBPROC, glGenBuffersARB) - INITOGLEXT(PFNGLDELETEBUFFERSARBPROC, glDeleteBuffersARB) - INITOGLEXT(PFNGLBINDBUFFERARBPROC, glBindBufferARB) - INITOGLEXT(PFNGLBUFFERDATAARBPROC, glBufferDataARB) - INITOGLEXT(PFNGLBUFFERSUBDATAARBPROC, glBufferSubDataARB) - INITOGLEXT(PFNGLMAPBUFFERARBPROC, glMapBufferARB) - INITOGLEXT(PFNGLUNMAPBUFFERARBPROC, glUnmapBufferARB) - INITOGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 INITOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 INITOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 @@ -302,7 +280,13 @@ static void OGLLoadEntryPoints_Legacy() INITOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 INITOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 INITOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 + + // VAO (always available in Apple's implementation of OpenGL, including old versions) + INITOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) // Core in v3.0 and ES v3.0 + INITOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) // Core in v3.0 and ES v3.0 + INITOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) // Core in v3.0 and ES v3.0 +#ifdef GL_EXT_framebuffer_object // FBO INITOGLEXT(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT) INITOGLEXT(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT) @@ -311,11 +295,14 @@ static void OGLLoadEntryPoints_Legacy() INITOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT) INITOGLEXT(PFNGLDELETEFRAMEBUFFERSEXTPROC, glDeleteFramebuffersEXT) INITOGLEXT(PFNGLBLITFRAMEBUFFEREXTPROC, glBlitFramebufferEXT) + + // Multisampled FBO INITOGLEXT(PFNGLGENRENDERBUFFERSEXTPROC, glGenRenderbuffersEXT) INITOGLEXT(PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) INITOGLEXT(PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) INITOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) INITOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) +#endif // GL_EXT_framebuffer_object } // Vertex Shader GLSL 1.00 @@ -958,10 +945,10 @@ static Render3D* OpenGLRendererCreate() const char *oglVendorString = (const char *)glGetString(GL_VENDOR); const char *oglRendererString = (const char *)glGetString(GL_RENDERER); - // Writing to gl_FragDepth causes the driver to fail miserably on systems equipped + // Writing to gl_FragDepth causes the driver to fail miserably on systems equipped // with a Intel G965 graphic card. Warn the user and fail gracefully. // http://forums.desmume.org/viewtopic.php?id=9286 - if(!strcmp(oglVendorString,"Intel") && strstr(oglRendererString,"965")) + if(!strcmp(oglVendorString,"Intel") && strstr(oglRendererString,"965")) { INFO("OpenGL: Incompatible graphic card detected. Disabling OpenGL support.\n"); @@ -1127,6 +1114,8 @@ GPU3DInterface gpu3Dgl_3_2 = { OpenGLRenderer::OpenGLRenderer() { + _variantID = OpenGLVariantID_Legacy; + _deviceInfo.renderID = RENDERID_OPENGL_AUTO; _deviceInfo.renderName = "OpenGL"; _deviceInfo.isTexturingSupported = true; @@ -1873,7 +1862,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const rawPoly.attribute.TranslucentDepthWrite_Enable, GFX3D_IsPolyWireframe(rawPoly) || GFX3D_IsPolyOpaque(rawPoly), rawPoly.attribute.PolygonID, - !clippedPoly.isPolyBackFacing); + !clippedPoly.isPolyBackFacing); } else { @@ -1883,7 +1872,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const rawPoly.attribute.DepthEqualTest_Enable, rawPoly.attribute.TranslucentDepthWrite_Enable, rawPoly.attribute.PolygonID, - !clippedPoly.isPolyBackFacing); + !clippedPoly.isPolyBackFacing); } indexBufferPtr += vertIndexCount; @@ -2372,7 +2361,6 @@ OpenGLRenderer_1_2::~OpenGLRenderer_1_2() this->DestroyFramebufferOutput8888Programs(); } - isShaderSupported = false; DestroyVAOs(); @@ -2423,27 +2411,24 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() // This texture is only required by shaders, and so if shader creation // fails, then we can immediately delete this texture if an error occurs. glGenTextures(1, &OGLRef.texFinalColorID); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FinalColor); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB); + glActiveTexture(GL_TEXTURE0); this->isVBOSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_buffer_object"); if (this->isVBOSupported) { this->CreateVBOs(); } - else + else if (this->IsVersionSupported(1, 5, 0)) { error = OGLERROR_VBO_UNSUPPORTED; - if (this->IsVersionSupported(1, 5, 0)) - { - return error; - } + return error; } this->isPBOSupported = this->isVBOSupported && @@ -2453,13 +2438,10 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() { this->CreatePBOs(); } - else + else if (this->IsVersionSupported(2, 1, 0)) { error = OGLERROR_PBO_UNSUPPORTED; - if (this->IsVersionSupported(2, 1, 0)) - { - return error; - } + return error; } // Don't use ARB versions since we're using the EXT versions for backwards compatibility. @@ -2550,8 +2532,8 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() GLint maxDrawBuffersOGL = 0; GLint maxShaderTexUnitsOGL = 0; glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachmentsOGL); - glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &maxDrawBuffersOGL); - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxShaderTexUnitsOGL); + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffersOGL); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxShaderTexUnitsOGL); if ( (maxColorAttachmentsOGL >= 4) && (maxDrawBuffersOGL >= 4) && (maxShaderTexUnitsOGL >= 8) ) { @@ -2639,20 +2621,20 @@ Render3DError OpenGLRenderer_1_2::CreateVBOs() { OGLRenderRef &OGLRef = *this->ref; - glGenBuffersARB(1, &OGLRef.vboGeometryVtxID); - glGenBuffersARB(1, &OGLRef.iboGeometryIndexID); - glGenBuffersARB(1, &OGLRef.vboPostprocessVtxID); + glGenBuffers(1, &OGLRef.vboGeometryVtxID); + glGenBuffers(1, &OGLRef.iboGeometryIndexID); + glGenBuffers(1, &OGLRef.vboPostprocessVtxID); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, VERTLIST_SIZE * sizeof(NDSVertex), NULL, GL_STREAM_DRAW_ARB); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(OGLRef.vertIndexBuffer), NULL, GL_STREAM_DRAW_ARB); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); + glBufferData(GL_ARRAY_BUFFER, VERTLIST_SIZE * sizeof(NDSVertex), NULL, GL_STREAM_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(OGLRef.vertIndexBuffer), NULL, GL_STREAM_DRAW); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW_ARB); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); + glBufferData(GL_ARRAY_BUFFER, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); return OGLERROR_NOERR; } @@ -2666,12 +2648,12 @@ void OpenGLRenderer_1_2::DestroyVBOs() OGLRenderRef &OGLRef = *this->ref; - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDeleteBuffersARB(1, &OGLRef.vboGeometryVtxID); - glDeleteBuffersARB(1, &OGLRef.iboGeometryIndexID); - glDeleteBuffersARB(1, &OGLRef.vboPostprocessVtxID); + glDeleteBuffers(1, &OGLRef.vboGeometryVtxID); + glDeleteBuffers(1, &OGLRef.iboGeometryIndexID); + glDeleteBuffers(1, &OGLRef.vboPostprocessVtxID); this->isVBOSupported = false; } @@ -2680,10 +2662,10 @@ Render3DError OpenGLRenderer_1_2::CreatePBOs() { OGLRenderRef &OGLRef = *this->ref; - glGenBuffersARB(1, &OGLRef.pboRenderDataID); - glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, OGLRef.pboRenderDataID); - glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ_ARB); - this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); + glGenBuffers(1, &OGLRef.pboRenderDataID); + glBindBuffer(GL_PIXEL_PACK_BUFFER, OGLRef.pboRenderDataID); + glBufferData(GL_PIXEL_PACK_BUFFER, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ); + this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); return OGLERROR_NOERR; } @@ -2697,12 +2679,12 @@ void OpenGLRenderer_1_2::DestroyPBOs() if (this->_mappedFramebuffer != NULL) { - glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); this->_mappedFramebuffer = NULL; } - glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); - glDeleteBuffersARB(1, &this->ref->pboRenderDataID); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glDeleteBuffers(1, &this->ref->pboRenderDataID); this->isPBOSupported = false; } @@ -2715,11 +2697,11 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID); glBindVertexArray(OGLRef.vaoGeometryStatesID); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); if (this->isShaderSupported) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glEnableVertexAttribArray(OGLVertexAttributeID_Position); glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); @@ -2730,7 +2712,7 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() } else { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -2746,7 +2728,7 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() if (this->isShaderSupported) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); glEnableVertexAttribArray(OGLVertexAttributeID_Position); glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); @@ -2793,7 +2775,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glGenTextures(1, &OGLRef.texGPolyID); glGenTextures(1, &OGLRef.texGDepthStencilID); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_DepthStencil); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_DepthStencil); glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -2802,7 +2784,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GColor); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -2810,7 +2792,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GPolyID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); glBindTexture(GL_TEXTURE_2D, OGLRef.texGPolyID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -2818,7 +2800,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FogAttr); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -2826,7 +2808,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB); + glActiveTexture(GL_TEXTURE0); CACHE_ALIGN GLint tempClearImageBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT]; memset(tempClearImageBuffer, 0, sizeof(tempClearImageBuffer)); @@ -3693,12 +3675,12 @@ Render3DError OpenGLRenderer_1_2::InitFinalRenderStates(const std::set_clearImageIndex], OGLRef.workingCIDepthStencilBuffer[this->_clearImageIndex ^ 0x01], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(GLuint)) != 0); const bool didFogAttributesChange = this->_enableFog && this->_deviceInfo.isFogSupported && (memcmp(OGLRef.workingCIFogAttributesBuffer[this->_clearImageIndex], OGLRef.workingCIFogAttributesBuffer[this->_clearImageIndex ^ 0x01], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(GLuint)) != 0); - glActiveTextureARB(GL_TEXTURE0_ARB); + glActiveTexture(GL_TEXTURE0); if (didColorChange) { @@ -4124,9 +4106,9 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() const GLuint convertProgramID = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.programFramebufferRGBA6665OutputID[0] : OGLRef.programFramebufferRGBA8888OutputID[0]; glUseProgram(convertProgramID); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FinalColor); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); - glActiveTextureARB(GL_TEXTURE0_ARB); + glActiveTexture(GL_TEXTURE0); } glViewport(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); @@ -4182,7 +4164,7 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() // penalty if the readback is in any other format. if (this->_mappedFramebuffer != NULL) { - glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); this->_mappedFramebuffer = NULL; } @@ -4211,17 +4193,17 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co if (this->isVBOSupported) { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); if (this->isShaderSupported) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(NDSVertex) * renderGList.rawVertCount, renderGList.rawVtxList); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(NDSVertex) * renderGList.rawVertCount, renderGList.rawVtxList); } else { // If shaders aren't supported, we need to use the client-side buffers here. - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); } } @@ -4315,7 +4297,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co { // Replace the entire index buffer as a hint to the driver that we can orphan the index buffer and // avoid a synchronization cost. - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(OGLRef.vertIndexBuffer), OGLRef.vertIndexBuffer); } // Set up rendering states that will remain constant for the entire frame. @@ -4431,7 +4413,7 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry() glDisable(GL_BLEND); } - glActiveTextureARB(GL_TEXTURE0_ARB); + glActiveTexture(GL_TEXTURE0); this->EnableVertexAttributes(); @@ -5219,7 +5201,7 @@ Render3DError OpenGLRenderer_1_2::RenderPowerOff() { if (this->_mappedFramebuffer != NULL) { - glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); this->_mappedFramebuffer = NULL; } @@ -5250,7 +5232,7 @@ Render3DError OpenGLRenderer_1_2::RenderFinish() if (this->isPBOSupported) { - this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); + this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); } else { @@ -5311,41 +5293,41 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) { if (this->_mappedFramebuffer != NULL) { - glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glFinish(); } - glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, newFramebufferColorSizeBytes, NULL, GL_STREAM_READ_ARB); + glBufferData(GL_PIXEL_PACK_BUFFER, newFramebufferColorSizeBytes, NULL, GL_STREAM_READ); if (this->_mappedFramebuffer != NULL) { - this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); + this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); glFinish(); } } if (this->isShaderSupported || this->isFBOSupported) { - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FinalColor); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); } if (this->isFBOSupported) { - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_DepthStencil); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_DepthStencil); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, (GLsizei)w, (GLsizei)h, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GColor); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GPolyID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FogAttr); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); } - glActiveTextureARB(GL_TEXTURE0_ARB); + glActiveTexture(GL_TEXTURE0); this->_framebufferWidth = w; this->_framebufferHeight = h; diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index 93f54b5e1..e226dab3a 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2023 DeSmuME team + Copyright (C) 2008-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,81 +27,112 @@ #include "render3D.h" #include "types.h" -#ifndef OGLRENDER_3_2_H +// OPENGL PLATFORM-SPECIFIC INCLUDES +#if defined(__ANGLE__) || defined(__ANDROID__) + #define OPENGL_VARIANT_ES + #define _NO_SDL_TYPES + #include + #include + #include + //#include "opengl.h" -#if defined(_WIN32) - #define WIN32_LEAN_AND_MEAN - #include - #include - #include - - #define OGLEXT(procPtr, func) procPtr func = NULL; - #define INITOGLEXT(procPtr, func) func = (procPtr)wglGetProcAddress(#func); - #define EXTERNOGLEXT(procPtr, func) extern procPtr func; -#elif defined(__APPLE__) - #include - #include - - // Ignore dynamic linking on Apple OS + // Ignore dynamic linking #define OGLEXT(procPtr, func) #define INITOGLEXT(procPtr, func) #define EXTERNOGLEXT(procPtr, func) +#elif defined(__EMSCRIPTEN__) + #define OPENGL_VARIANT_ES + #include + #include - // We're not exactly committing to OpenGL 3.2 Core Profile just yet, so redefine APPLE - // extensions as a temporary measure. - #if defined(GL_APPLE_vertex_array_object) && !defined(GL_ARB_vertex_array_object) - #define glGenVertexArrays(n, ids) glGenVertexArraysAPPLE(n, ids) - #define glBindVertexArray(id) glBindVertexArrayAPPLE(id) - #define glDeleteVertexArrays(n, ids) glDeleteVertexArraysAPPLE(n, ids) + // Ignore dynamic linking + #define OGLEXT(procPtr, func) + #define INITOGLEXT(procPtr, func) + #define EXTERNOGLEXT(procPtr, func) +#elif defined(_WIN32) + #define OPENGL_VARIANT_STANDARD + #define WIN32_LEAN_AND_MEAN + #include + + #ifdef OGLRENDER_3_2_H + #include + #else + #include + #include #endif + + #define OGLEXT(procPtr, func) procPtr func = NULL; + #define INITOGLEXT(procPtr, func) func = (procPtr)wglGetProcAddress(#func); + #define EXTERNOGLEXT(procPtr, func) extern procPtr func; +#elif defined(__APPLE__) + #include + + #if TARGET_OS_IPHONE + #define OPENGL_VARIANT_ES + #include + #include + #else + #define OPENGL_VARIANT_STANDARD + + #ifdef OGLRENDER_3_2_H + #include + #include + #else + #include + #include + #endif + + // Use Apple's extension function if the core function is not available + #if defined(GL_APPLE_vertex_array_object) && !defined(GL_ARB_vertex_array_object) + #define glGenVertexArrays(n, ids) glGenVertexArraysAPPLE(n, ids) + #define glBindVertexArray(id) glBindVertexArrayAPPLE(id) + #define glDeleteVertexArrays(n, ids) glDeleteVertexArraysAPPLE(n, ids) + #endif + #endif + + // Ignore dynamic linking + #define OGLEXT(procPtr, func) + #define INITOGLEXT(procPtr, func) + #define EXTERNOGLEXT(procPtr, func) #else - #include - #include - #include + #define OPENGL_VARIANT_STANDARD - /* This is a workaround needed to compile against nvidia GL headers */ - #ifndef GL_ALPHA_BLEND_EQUATION_ATI - #undef GL_VERSION_1_3 + #ifdef OGLRENDER_3_2_H + #include "utils/glcorearb.h" + #else + #include + #include + #include + + /* This is a workaround needed to compile against nvidia GL headers */ + #ifndef GL_ALPHA_BLEND_EQUATION_ATI + #undef GL_VERSION_1_3 + #endif #endif - #define OGLEXT(procPtr, func) procPtr func = NULL; - #define INITOGLEXT(procPtr, func) func = (procPtr)glXGetProcAddress((const GLubyte *) #func); - #define EXTERNOGLEXT(procPtr, func) extern procPtr func; + #define OGLEXT(procPtr, func) procPtr func = NULL; + #define INITOGLEXT(procPtr, func) func = (procPtr)glXGetProcAddress((const GLubyte *) #func); + #define EXTERNOGLEXT(procPtr, func) extern procPtr func; #endif // Check minimum OpenGL header version -#if !defined(GL_VERSION_2_1) - #if defined(GL_VERSION_2_0) - #warning Using OpenGL v2.0 headers with v2.1 overrides. Some features will be disabled. - - #if !defined(GL_ARB_framebuffer_object) - // Overrides for GL_EXT_framebuffer_blit - #if !defined(GL_EXT_framebuffer_blit) - #define GL_READ_FRAMEBUFFER_EXT GL_FRAMEBUFFER_EXT - #define GL_DRAW_FRAMEBUFFER_EXT GL_FRAMEBUFFER_EXT - #define glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) - #endif - - // Overrides for GL_EXT_framebuffer_multisample - #if !defined(GL_EXT_framebuffer_multisample) - #define GL_MAX_SAMPLES_EXT 0 - #define glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height) - #endif - - // Overrides for GL_ARB_pixel_buffer_object - #if !defined(GL_PIXEL_PACK_BUFFER) && defined(GL_PIXEL_PACK_BUFFER_ARB) - #define GL_PIXEL_PACK_BUFFER GL_PIXEL_PACK_BUFFER_ARB - #endif - #endif - #else +#if defined(OPENGL_VARIANT_STANDARD) + #if !defined(GL_VERSION_2_1) #error OpenGL requires v2.1 headers or later. #endif +#elif defined(OPENGL_VARIANT_ES) + #if !defined(GL_ES_VERSION_3_0) + #error OpenGL ES requires v3.0 headers or later. + #endif +#else + #error Unknown OpenGL variant. #endif +// OPENGL LEGACY CORE FUNCTIONS + // Textures #if !defined(GLX_H) EXTERNOGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 -EXTERNOGLEXT(PFNGLACTIVETEXTUREARBPROC, glActiveTextureARB) #endif // Blending @@ -111,9 +142,6 @@ EXTERNOGLEXT(PFNGLBLENDEQUATIONPROC, glBlendEquation) // Core in v1.2 EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 -EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEEXTPROC, glBlendFuncSeparateEXT) -EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEEXTPROC, glBlendEquationSeparateEXT) - // Shaders EXTERNOGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 EXTERNOGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 @@ -146,20 +174,7 @@ EXTERNOGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Cor EXTERNOGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 EXTERNOGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 -// VAO -EXTERNOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) -EXTERNOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) -EXTERNOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) - -// VBO and PBO -EXTERNOGLEXT(PFNGLGENBUFFERSARBPROC, glGenBuffersARB) -EXTERNOGLEXT(PFNGLDELETEBUFFERSARBPROC, glDeleteBuffersARB) -EXTERNOGLEXT(PFNGLBINDBUFFERARBPROC, glBindBufferARB) -EXTERNOGLEXT(PFNGLBUFFERDATAARBPROC, glBufferDataARB) -EXTERNOGLEXT(PFNGLBUFFERSUBDATAARBPROC, glBufferSubDataARB) -EXTERNOGLEXT(PFNGLMAPBUFFERARBPROC, glMapBufferARB) -EXTERNOGLEXT(PFNGLUNMAPBUFFERARBPROC, glUnmapBufferARB) - +// Buffer Objects EXTERNOGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 @@ -168,6 +183,71 @@ EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 +// VAO (always available in Apple's implementation of OpenGL, including old versions) +#if defined(__APPLE__) || defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_3_0) +EXTERNOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) // Core in v3.0 and ES v3.0 +EXTERNOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) // Core in v3.0 and ES v3.0 +EXTERNOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) // Core in v3.0 and ES v3.0 +#endif + +// OPENGL CORE FUNCTIONS ADDED IN 3.2 CORE PROFILE AND VARIANTS +#if defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_3_0) + +// Basic Functions +EXTERNOGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0 and ES v3.0 +EXTERNOGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 and ES v3.0 +EXTERNOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 and ES v3.0 + +// Shaders +#if !defined(GL_ES_VERSION_3_0) +EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES +EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3, not available in ES +#endif + +// Buffer Objects +EXTERNOGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 and ES v3.0 + +// FBO +EXTERNOGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0 and ES v3.0 + +// Multisampled FBO +EXTERNOGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 and ES v2.0 +EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 and ES v3.0 +EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 and ES v2.0 +#if !defined(GL_ES_VERSION_3_0) +EXTERNOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2, not available in ES +#endif + +// UBO +EXTERNOGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 and ES v3.0 +EXTERNOGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Core in v3.1 and ES v3.0 +EXTERNOGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 and ES v3.0 +EXTERNOGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 and ES v3.0 + +// TBO +#if defined(GL_VERSION_3_1) || defined(GL_ES_VERSION_3_2) +EXTERNOGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 and ES v3.2 +#endif + +// Sync Objects +EXTERNOGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 and ES v3.0 +EXTERNOGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 and ES v3.0 +EXTERNOGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 and ES v3.0 + +#endif // GL_VERSION_3_0 || GL_ES_VERSION_3_0 + +// OPENGL FBO EXTENSIONS +// We need to include these explicitly for OpenGL legacy mode since the EXT versions of FBOs +// may work differently than their ARB counterparts when running on older drivers. +#if defined(GL_EXT_framebuffer_object) // FBO EXTERNOGLEXT(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT) EXTERNOGLEXT(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT) @@ -184,130 +264,74 @@ EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) -#else // OGLRENDER_3_2_H +#elif defined(GL_ARB_framebuffer_object) +// Most OpenGL variants don't have GL_EXT_framebuffer_object, so redeclare all the ARB versions +// to their EXT versions to avoid compile time errors in OGLRender.cpp. +// +// In practice, class objects for more modern variants like 3.2 Core Profile and ES 3.0 should +// override all the methods that would use FBOs so that only the ARB versions are actually used. -// Basic Functions -EXTERNOGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0 -EXTERNOGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 -EXTERNOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 +#define GL_MAX_COLOR_ATTACHMENTS_EXT GL_MAX_COLOR_ATTACHMENTS +#define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8 +#define GL_DEPTH_STENCIL_EXT GL_DEPTH_STENCIL +#define GL_UNSIGNED_INT_24_8_EXT GL_UNSIGNED_INT_24_8 +#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER +#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE +#define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT +#define GL_STENCIL_ATTACHMENT_EXT GL_STENCIL_ATTACHMENT +#define GL_RENDERBUFFER_EXT GL_RENDERBUFFER +#define GL_DRAW_FRAMEBUFFER_EXT GL_DRAW_FRAMEBUFFER +#define GL_READ_FRAMEBUFFER_EXT GL_READ_FRAMEBUFFER +#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 +#define GL_COLOR_ATTACHMENT1_EXT GL_COLOR_ATTACHMENT1 +#define GL_COLOR_ATTACHMENT2_EXT GL_COLOR_ATTACHMENT2 +#define GL_COLOR_ATTACHMENT3_EXT GL_COLOR_ATTACHMENT3 +#define GL_MAX_SAMPLES_EXT GL_MAX_SAMPLES -// Textures -#if !defined(GLX_H) -EXTERNOGLEXT(PFNGLACTIVETEXTUREPROC, glActiveTexture) // Core in v1.3 -#endif +#define glGenFramebuffersEXT(n, framebuffers) glGenFramebuffers(n, framebuffers) +#define glBindFramebufferEXT(target, framebuffer) glBindFramebuffer(target, framebuffer) +#define glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer) glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) +#define glFramebufferTexture2DEXT(target, attachment, textarget, texture, level) glFramebufferTexture2D(target, attachment, textarget, texture, level) +#define glCheckFramebufferStatusEXT(target) glCheckFramebufferStatus(target) +#define glDeleteFramebuffersEXT(n, framebuffers) glDeleteFramebuffers(n, framebuffers) +#define glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) -// Blending -#if !defined(GLX_H) -EXTERNOGLEXT(PFNGLBLENDEQUATIONPROC, glBlendEquation) // Core in v1.2 -#endif -EXTERNOGLEXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) // Core in v1.4 -EXTERNOGLEXT(PFNGLBLENDEQUATIONSEPARATEPROC, glBlendEquationSeparate) // Core in v2.0 +#define glGenRenderbuffersEXT(n, renderbuffers) glGenRenderbuffers(n, renderbuffers) +#define glBindRenderbufferEXT(target, renderbuffer) glBindRenderbuffer(target, renderbuffer) +#define glRenderbufferStorageEXT(target, internalformat, width, height) glRenderbufferStorage(target, internalformat, width, height) +#define glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height) glRenderbufferStorageMultisample(target, samples, internalformat, width, height) +#define glDeleteRenderbuffersEXT(n, renderbuffers) glDeleteRenderbuffers(n, renderbuffers) -// Shaders -EXTERNOGLEXT(PFNGLCREATESHADERPROC, glCreateShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLSHADERSOURCEPROC, glShaderSource) // Core in v2.0 -EXTERNOGLEXT(PFNGLCOMPILESHADERPROC, glCompileShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLCREATEPROGRAMPROC, glCreateProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLATTACHSHADERPROC, glAttachShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLDETACHSHADERPROC, glDetachShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLLINKPROGRAMPROC, glLinkProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLUSEPROGRAMPROC, glUseProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETSHADERIVPROC, glGetShaderiv) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog) // Core in v2.0 -EXTERNOGLEXT(PFNGLDELETESHADERPROC, glDeleteShader) // Core in v2.0 -EXTERNOGLEXT(PFNGLDELETEPROGRAMPROC, glDeleteProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETPROGRAMIVPROC, glGetProgramiv) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog) // Core in v2.0 -EXTERNOGLEXT(PFNGLVALIDATEPROGRAMPROC, glValidateProgram) // Core in v2.0 -EXTERNOGLEXT(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1IPROC, glUniform1i) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1IVPROC, glUniform1iv) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1FPROC, glUniform1f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM1FVPROC, glUniform1fv) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM2FPROC, glUniform2f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM4FPROC, glUniform4f) // Core in v2.0 -EXTERNOGLEXT(PFNGLUNIFORM4FVPROC, glUniform4fv) // Core in v2.0 -EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 - -// Generic vertex attributes -EXTERNOGLEXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation) // Core in v2.0 -EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3 -EXTERNOGLEXT(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray) // Core in v2.0 -EXTERNOGLEXT(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray) // Core in v2.0 -EXTERNOGLEXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) // Core in v2.0 - -// VAO -EXTERNOGLEXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays) // Core in v3.0 -EXTERNOGLEXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) // Core in v3.0 - -// VBO and PBO -EXTERNOGLEXT(PFNGLGENBUFFERSPROC, glGenBuffers) // Core in v1.5 -EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 -EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 -EXTERNOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 -EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 -EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 -EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 - -// Buffer Objects -EXTERNOGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 - -// FBO -EXTERNOGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0 -EXTERNOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0 -EXTERNOGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLDRAWBUFFERSPROC, glDrawBuffers) // Core in v2.0 - -// Multisampled FBO -EXTERNOGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 -EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 -EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 -EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 -EXTERNOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2 - -// UBO -EXTERNOGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 -EXTERNOGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Core in v3.1 -EXTERNOGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 -EXTERNOGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 - -// TBO -EXTERNOGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 - -// Sync Objects -EXTERNOGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 -EXTERNOGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 -EXTERNOGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 - -#endif // OGLRENDER_3_2_H +#endif // GL_EXT_framebuffer_object // Define the minimum required OpenGL version for the driver to support -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 1 -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR 2 -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION 0 +#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 1 +#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR 2 +#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION 0 #define OGLRENDER_VERT_INDEX_BUFFER_COUNT (CLIPPED_POLYLIST_SIZE * 6) // Assign the FBO attachments for the main geometry render -#ifdef OGLRENDER_3_2_H - #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0 - #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3 - #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1 - #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2 +#if defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_3_0) + #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0 + #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3 + #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1 + #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2 #else - #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0_EXT - #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3_EXT - #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1_EXT - #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2_EXT + #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0_EXT + #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3_EXT + #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1_EXT + #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2_EXT #endif +enum OpenGLVariantID +{ + OpenGLVariantID_Unknown = 0, + OpenGLVariantID_Legacy = 1, + OpenGLVariantID_CoreProfile_3_2 = 2, + OpenGLVariantID_ES_3_0 = 3 +}; + enum OGLVertexAttributeID { OGLVertexAttributeID_Position = 0, @@ -324,7 +348,7 @@ enum OGLTextureUnitID OGLTextureUnitID_GPolyID, OGLTextureUnitID_FogAttr, OGLTextureUnitID_PolyStates, - OGLTextureUnitID_LookupTable, + OGLTextureUnitID_LookupTable }; enum OGLBindingPointID @@ -501,7 +525,7 @@ struct OGLFogShaderID typedef OGLFogShaderID OGLFogShaderID; struct OGLRenderRef -{ +{ // OpenGL Feature Support GLint stateTexMirroredRepeat; @@ -712,6 +736,7 @@ protected: OGLRenderRef *ref; // OpenGL Feature Support + OpenGLVariantID _variantID; bool isVBOSupported; bool isPBOSupported; bool isFBOSupported; @@ -926,10 +951,10 @@ protected: }; class OpenGLRenderer_2_1 : public OpenGLRenderer_2_0 -{ +{ public: virtual Render3DError RenderFinish(); virtual Render3DError RenderFlush(bool willFlushBuffer32, bool willFlushBuffer16); }; -#endif +#endif // OGLRENDER_H diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 9f6665fe0..41ed760e6 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2023 DeSmuME team + Copyright (C) 2008-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,87 +33,91 @@ //------------------------------------------------------------ // Basic Functions -OGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0 -OGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 -OGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 +OGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0 and ES v3.0 +OGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 and ES v3.0 +OGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 and ES v3.0 // Shaders -OGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0 -OGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3 +OGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES +OGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3, not available in ES // Buffer Objects -OGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 +OGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 and ES v3.0 // FBO -OGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0 -OGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0 -OGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0 -OGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0 -OGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0 -OGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0 -OGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0 -OGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0 -OGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 -OGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 -OGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 -OGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 -OGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2 +OGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0 and ES v3.0 + +// Multisampled FBO +OGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 and ES v3.0 +OGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 and ES v2.0 +OGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2, not available in ES // UBO -OGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 -OGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Core in v3.1 -OGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 -OGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 +OGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 and ES v3.0 +OGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Core in v3.1 and ES v3.0 +OGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 and ES v3.0 +OGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 and ES v3.0 // TBO -OGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 +OGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 and ES v3.2 // Sync Objects -OGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 -OGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 -OGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 +OGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 and ES v3.0 +OGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 and ES v3.0 +OGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 and ES v3.0 void OGLLoadEntryPoints_3_2() { // Basic Functions - INITOGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) - INITOGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) - INITOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) + INITOGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0 and ES v3.0 + INITOGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 and ES v3.0 + INITOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 and ES v3.0 // Shaders - INITOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) + INITOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES // Buffer Objects - INITOGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) + INITOGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 and ES v3.0 // FBO - INITOGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Promote to core version - INITOGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Promote to core version - INITOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Promote to core version - INITOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Promote to core version - INITOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Promote to core version - INITOGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Promote to core version - INITOGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Promote to core version - INITOGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Promote to core version - INITOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Promote to core version - INITOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Promote to core version - INITOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Promote to core version - INITOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Promote to core version - INITOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) + INITOGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0 and ES v3.0 + + // Multisampled FBO + INITOGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 and ES v3.0 + INITOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 and ES v2.0 + INITOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2, not available in ES // UBO - INITOGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) - INITOGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) - INITOGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) - INITOGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) + INITOGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 and ES v3.0 + INITOGLEXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) // Core in v3.1 and ES v3.0 + INITOGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 and ES v3.0 + INITOGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 and ES v3.0 // TBO - INITOGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) + INITOGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 and ES v3.2 // Sync Objects - INITOGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 - INITOGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 - INITOGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 + INITOGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 and ES v3.0 + INITOGLEXT(PFNGLWAITSYNCPROC, glWaitSync) // Core in v3.2 and ES v3.0 + INITOGLEXT(PFNGLDELETESYNCPROC, glDeleteSync) // Core in v3.2 and ES v3.0 } // Vertex shader for geometry, GLSL 1.50 @@ -611,6 +615,7 @@ void OGLCreateRenderer_3_2(OpenGLRenderer **rendererPtr) OpenGLRenderer_3_2::OpenGLRenderer_3_2() { + _variantID = OpenGLVariantID_CoreProfile_3_2; _is64kUBOSupported = false; _isDualSourceBlendingSupported = false; _isSampleShadingSupported = false; diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 7f14d0b59..64c0cb740 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -1,7 +1,7 @@ /* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash - Copyright (C) 2008-2023 DeSmuME team + Copyright (C) 2008-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,40 +20,6 @@ #ifndef OGLRENDER_3_2_H #define OGLRENDER_3_2_H -#if defined(_WIN32) - #define WIN32_LEAN_AND_MEAN - #include - #include - #include - #include - - #define OGLEXT(procPtr, func) procPtr func = NULL; - #define INITOGLEXT(procPtr, func) func = (procPtr)wglGetProcAddress(#func); - #define EXTERNOGLEXT(procPtr, func) extern procPtr func; -#elif defined(__APPLE__) - #include - #include - - // Ignore dynamic linking on Apple OS - #define OGLEXT(procPtr, func) - #define INITOGLEXT(procPtr, func) - #define EXTERNOGLEXT(procPtr, func) -#else - #include - #include - #include - #include "utils/glcorearb.h" - - #define OGLEXT(procPtr, func) procPtr func = NULL; - #define INITOGLEXT(procPtr, func) func = (procPtr)glXGetProcAddress((const GLubyte *) #func); - #define EXTERNOGLEXT(procPtr, func) extern procPtr func; -#endif - -// Check minimum OpenGL header version -#if !defined(GL_VERSION_3_2) - #error OpenGL requires v3.2 headers or later. -#endif - #include "OGLRender.h" #define MAX_CLIPPED_POLY_COUNT_FOR_UBO 16384 diff --git a/desmume/src/frontend/posix/gtk/main.cpp b/desmume/src/frontend/posix/gtk/main.cpp index 06861431e..a9ad5b3aa 100644 --- a/desmume/src/frontend/posix/gtk/main.cpp +++ b/desmume/src/frontend/posix/gtk/main.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2007 Pascal Giard (evilynux) - Copyright (C) 2006-2021 DeSmuME team + Copyright (C) 2006-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -76,7 +76,6 @@ #ifdef HAVE_OPENGL #include - #include "OGLRender.h" #include "OGLRender_3_2.h" #endif diff --git a/desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp b/desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp index 9366a20cc..78bf89a2e 100644 --- a/desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp +++ b/desmume/src/frontend/posix/gtk/osmesa_3Demu.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2009 Guillaume Duhamel - Copyright (C) 2009-2017 DeSmuME team + Copyright (C) 2009-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,6 @@ #include #include -#include "../OGLRender.h" #include "../OGLRender_3_2.h" #include "osmesa_3Demu.h" diff --git a/desmume/src/frontend/posix/gtk2/main.cpp b/desmume/src/frontend/posix/gtk2/main.cpp index 55610d528..70946a8e7 100644 --- a/desmume/src/frontend/posix/gtk2/main.cpp +++ b/desmume/src/frontend/posix/gtk2/main.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2007 Pascal Giard (evilynux) - Copyright (C) 2006-2021 DeSmuME team + Copyright (C) 2006-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -72,7 +72,6 @@ #ifdef HAVE_OPENGL #include - #include "OGLRender.h" #include "OGLRender_3_2.h" #endif diff --git a/desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp b/desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp index 9366a20cc..78bf89a2e 100644 --- a/desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp +++ b/desmume/src/frontend/posix/gtk2/osmesa_3Demu.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2009 Guillaume Duhamel - Copyright (C) 2009-2017 DeSmuME team + Copyright (C) 2009-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,6 @@ #include #include -#include "../OGLRender.h" #include "../OGLRender_3_2.h" #include "osmesa_3Demu.h" diff --git a/desmume/src/frontend/windows/main.cpp b/desmume/src/frontend/windows/main.cpp index 5588ace62..7766d3a47 100644 --- a/desmume/src/frontend/windows/main.cpp +++ b/desmume/src/frontend/windows/main.cpp @@ -1,6 +1,6 @@ -/* +/* Copyright (C) 2006 Theo Berkau - Copyright (C) 2006-2023 DeSmuME team + Copyright (C) 2006-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,7 +52,6 @@ #include "slot2.h" #include "GPU.h" #include "SPU.h" -#include "OGLRender.h" #include "OGLRender_3_2.h" #include "rasterize.h" #include "gfx3d.h" From d4163a1893b47c341b9b79bceab381acf3416b4f Mon Sep 17 00:00:00 2001 From: rogerman Date: Mon, 1 Jul 2024 16:26:46 -0700 Subject: [PATCH 35/49] OpenGL: Fix building on Windows and Linux. (Regression from commit 086980d.) --- desmume/src/OGLRender.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index e226dab3a..802c6c162 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -53,12 +53,11 @@ #define OPENGL_VARIANT_STANDARD #define WIN32_LEAN_AND_MEAN #include + #include + #include #ifdef OGLRENDER_3_2_H #include - #else - #include - #include #endif #define OGLEXT(procPtr, func) procPtr func = NULL; @@ -96,14 +95,13 @@ #define EXTERNOGLEXT(procPtr, func) #else #define OPENGL_VARIANT_STANDARD + #include + #include + #include #ifdef OGLRENDER_3_2_H #include "utils/glcorearb.h" #else - #include - #include - #include - /* This is a workaround needed to compile against nvidia GL headers */ #ifndef GL_ALPHA_BLEND_EQUATION_ATI #undef GL_VERSION_1_3 From fe0ae83c40fab1a01887fdb142b5a8acb0b072b1 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 2 Jul 2024 00:16:46 -0700 Subject: [PATCH 36/49] Cocoa Port: Fix a longstanding, yet rare, crash that may occur when quitting the app. --- desmume/src/frontend/cocoa/cocoa_GPU.mm | 2 -- desmume/src/frontend/cocoa/cocoa_core.mm | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/desmume/src/frontend/cocoa/cocoa_GPU.mm b/desmume/src/frontend/cocoa/cocoa_GPU.mm index c9437cf5a..156a2da11 100644 --- a/desmume/src/frontend/cocoa/cocoa_GPU.mm +++ b/desmume/src/frontend/cocoa/cocoa_GPU.mm @@ -193,8 +193,6 @@ GPU3DInterface *core3DList[GPU_3D_RENDERER_COUNT+1] = { - (void)dealloc { - DestroyOpenGLRenderer(); - delete fetchObject; delete gpuEvent; diff --git a/desmume/src/frontend/cocoa/cocoa_core.mm b/desmume/src/frontend/cocoa/cocoa_core.mm index e4e7f6e43..4903cdb1a 100644 --- a/desmume/src/frontend/cocoa/cocoa_core.mm +++ b/desmume/src/frontend/cocoa/cocoa_core.mm @@ -226,6 +226,10 @@ volatile bool execute = true; delete execControl; NDS_DeInit(); + // We must call DestroyOpenGLRenderer() after NDS_Init() because we need to wait for + // the OpenGL renderer to finish before we destroy its associated context. + DestroyOpenGLRenderer(); + [super dealloc]; } From fc6ff8edbd0cc72116a52a94254c3cb1340afef3 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 2 Jul 2024 01:35:10 -0700 Subject: [PATCH 37/49] GPU: Fix a bug on big-endian systems where setting the backdrop color could cause a crash. --- desmume/src/GPU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desmume/src/GPU.cpp b/desmume/src/GPU.cpp index 8081ad2b0..ae4d29ca9 100644 --- a/desmume/src/GPU.cpp +++ b/desmume/src/GPU.cpp @@ -848,7 +848,7 @@ void GPUEngineBase::UpdateRenderStates(const size_t l) { currRenderState.workingBackdropColor16 = currRenderState.backdropColor16; } - currRenderState.workingBackdropColor32.value = LOCAL_TO_LE_32( (this->_targetDisplay->GetColorFormat() == NDSColorFormat_BGR666_Rev) ? COLOR555TO666(LOCAL_TO_LE_16(currRenderState.workingBackdropColor16)) : COLOR555TO888(LOCAL_TO_LE_16(currRenderState.workingBackdropColor16)) ); + currRenderState.workingBackdropColor32.value = LOCAL_TO_LE_32( (this->_targetDisplay->GetColorFormat() == NDSColorFormat_BGR666_Rev) ? COLOR555TO666(currRenderState.workingBackdropColor16) : COLOR555TO888(currRenderState.workingBackdropColor16) ); // Save the current render states to this line's compositor info. compInfo.renderState = currRenderState; From 3ec0b0c2e197c751014aca0ff9992acb0501ccb6 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 3 Jul 2024 13:01:17 -0700 Subject: [PATCH 38/49] OpenGL: Continue preparation for adding OpenGL ES. (Related to commit 086980d.) --- desmume/src/OGLRender.cpp | 127 +++++++++++++++++++++++----------- desmume/src/OGLRender.h | 2 + desmume/src/OGLRender_3_2.cpp | 9 +-- desmume/src/OGLRender_3_2.h | 3 +- 4 files changed, 95 insertions(+), 46 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 63c6180f1..448e6d919 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -38,10 +38,30 @@ #include "./utils/colorspacehandler/colorspacehandler_SSE2.h" #endif -#if MSB_FIRST - #define GL_TEXTURE_SRC_FORMAT GL_UNSIGNED_INT_8_8_8_8 +#if defined(OPENGL_VARIANT_STANDARD) + #if MSB_FIRST + #define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_SHORT_1_5_5_5_REV + #define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_INT_8_8_8_8_REV + #define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_INT_8_8_8_8 + #define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_1_5_5_5_REV + #else + #define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_SHORT_1_5_5_5_REV + #define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_INT_8_8_8_8_REV + #define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_INT_8_8_8_8_REV + #define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_1_5_5_5_REV + #endif +#elif defined(OPENGL_VARIANT_ES) + #define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_SHORT_5_5_5_1 + #define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_BYTE + #define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_BYTE + #define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_5_5_5_1 + + #define GL_TEXTURE_1D GL_TEXTURE_2D + #define glTexSubImage1D(target, level, xoffset, width, format, type, pixels) + + #define glClearDepth(depth) glClearDepthf(depth) #else - #define GL_TEXTURE_SRC_FORMAT GL_UNSIGNED_INT_8_8_8_8_REV + #error Unknown OpenGL variant. #endif typedef struct @@ -82,7 +102,7 @@ CACHE_ALIGN const GLfloat divide6bitBy63_LUT[64] = {0.0, 0.015873015 0.9523809523810, 0.9682539682540, 0.9841269841270, 1.0}; const GLfloat PostprocessVtxBuffer[16] = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}; + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}; const GLenum GeometryDrawBuffersEnum[8][4] = { { GL_COLOROUT_ATTACHMENT_ID, GL_NONE, GL_NONE, GL_NONE }, @@ -205,7 +225,9 @@ OGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 OGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 OGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 OGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 +#if !defined(GL_ES_VERSION_3_0) OGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 +#endif OGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 #ifdef GL_EXT_framebuffer_object @@ -278,7 +300,9 @@ static void OGLLoadEntryPoints_Legacy() INITOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 INITOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 INITOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 +#if !defined(GL_ES_VERSION_3_0) INITOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 +#endif INITOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 // VAO (always available in Apple's implementation of OpenGL, including old versions) @@ -821,11 +845,11 @@ void OpenGLTexture::Load(bool forceTextureInit) if (forceTextureInit || !this->_isTexInited) { this->_isTexInited = true; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_sizeS, this->_sizeT, 0, GL_RGBA, GL_TEXTURE_SRC_FORMAT, textureSrc); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_sizeS, this->_sizeT, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_sizeS, this->_sizeT, GL_RGBA, GL_TEXTURE_SRC_FORMAT, textureSrc); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_sizeS, this->_sizeT, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } break; } @@ -840,13 +864,13 @@ void OpenGLTexture::Load(bool forceTextureInit) if (forceTextureInit || !this->_isTexInited) { this->_isTexInited = true; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_sizeS*2, this->_sizeT*2, 0, GL_RGBA, GL_TEXTURE_SRC_FORMAT, this->_upscaleBuffer); - glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, this->_sizeS*1, this->_sizeT*1, 0, GL_RGBA, GL_TEXTURE_SRC_FORMAT, textureSrc); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_sizeS*2, this->_sizeT*2, 0, GL_RGBA, GL_UNSIGNED_BYTE, this->_upscaleBuffer); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, this->_sizeS*1, this->_sizeT*1, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_sizeS*2, this->_sizeT*2, GL_RGBA, GL_TEXTURE_SRC_FORMAT, this->_upscaleBuffer); - glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, this->_sizeS*1, this->_sizeT*1, GL_RGBA, GL_TEXTURE_SRC_FORMAT, textureSrc); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_sizeS*2, this->_sizeT*2, GL_RGBA, GL_UNSIGNED_BYTE, this->_upscaleBuffer); + glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, this->_sizeS*1, this->_sizeT*1, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } break; } @@ -861,21 +885,21 @@ void OpenGLTexture::Load(bool forceTextureInit) if (forceTextureInit || !this->_isTexInited) { this->_isTexInited = true; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_sizeS*4, this->_sizeT*4, 0, GL_RGBA, GL_TEXTURE_SRC_FORMAT, this->_upscaleBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_sizeS*4, this->_sizeT*4, 0, GL_RGBA, GL_UNSIGNED_BYTE, this->_upscaleBuffer); this->_Upscale<2>(textureSrc, this->_upscaleBuffer); - glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, this->_sizeS*2, this->_sizeT*2, 0, GL_RGBA, GL_TEXTURE_SRC_FORMAT, this->_upscaleBuffer); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, this->_sizeS*2, this->_sizeT*2, 0, GL_RGBA, GL_UNSIGNED_BYTE, this->_upscaleBuffer); - glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, this->_sizeS*1, this->_sizeT*1, 0, GL_RGBA, GL_TEXTURE_SRC_FORMAT, textureSrc); + glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, this->_sizeS*1, this->_sizeT*1, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_sizeS*4, this->_sizeT*4, GL_RGBA, GL_TEXTURE_SRC_FORMAT, this->_upscaleBuffer); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_sizeS*4, this->_sizeT*4, GL_RGBA, GL_UNSIGNED_BYTE, this->_upscaleBuffer); this->_Upscale<2>(textureSrc, this->_upscaleBuffer); - glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, this->_sizeS*2, this->_sizeT*2, GL_RGBA, GL_TEXTURE_SRC_FORMAT, this->_upscaleBuffer); + glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, this->_sizeS*2, this->_sizeT*2, GL_RGBA, GL_UNSIGNED_BYTE, this->_upscaleBuffer); - glTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, this->_sizeS*1, this->_sizeT*1, GL_RGBA, GL_TEXTURE_SRC_FORMAT, textureSrc); + glTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, this->_sizeS*1, this->_sizeT*1, GL_RGBA, GL_UNSIGNED_BYTE, textureSrc); } break; } @@ -2387,6 +2411,7 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() std::set oglExtensionSet; this->GetExtensionSet(&oglExtensionSet); +#if !defined(GL_ES_VERSION_3_0) if (!this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_multitexture")) { return OGLERROR_DRIVER_VERSION_TOO_OLD; @@ -2394,13 +2419,14 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() else { GLint maxFixedFunctionTexUnitsOGL = 0; - glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxFixedFunctionTexUnitsOGL); + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxFixedFunctionTexUnitsOGL); if (maxFixedFunctionTexUnitsOGL < 4) { return OGLERROR_DRIVER_VERSION_TOO_OLD; } } +#endif // Get host GPU device properties GLfloat maxAnisotropyOGL = 1.0f; @@ -2417,7 +2443,7 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); this->isVBOSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_buffer_object"); @@ -2665,7 +2691,9 @@ Render3DError OpenGLRenderer_1_2::CreatePBOs() glGenBuffers(1, &OGLRef.pboRenderDataID); glBindBuffer(GL_PIXEL_PACK_BUFFER, OGLRef.pboRenderDataID); glBufferData(GL_PIXEL_PACK_BUFFER, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ); +#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); +#endif return OGLERROR_NOERR; } @@ -2710,6 +2738,7 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, texCoord)); glVertexAttribPointer(OGLVertexAttributeID_Color, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, color)); } +#if !defined(GL_ES_VERSION_3_0) else { glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -2721,6 +2750,7 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() glTexCoordPointer(2, GL_FLOAT, 0, OGLRef.texCoord2fBuffer); glColorPointer(4, GL_FLOAT, 0, OGLRef.color4fBuffer); } +#endif glBindVertexArray(0); @@ -2747,13 +2777,13 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() void OpenGLRenderer_1_2::DestroyVAOs() { - OGLRenderRef &OGLRef = *this->ref; - if (!this->isVAOSupported) { return; } + OGLRenderRef &OGLRef = *this->ref; + glBindVertexArray(0); glDeleteVertexArrays(1, &OGLRef.vaoGeometryStatesID); glDeleteVertexArrays(1, &OGLRef.vaoPostprocessStatesID); @@ -2790,7 +2820,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); glBindTexture(GL_TEXTURE_2D, OGLRef.texGPolyID); @@ -2798,7 +2828,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID); @@ -2806,7 +2836,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); @@ -2818,7 +2848,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, tempClearImageBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempClearImageBuffer); glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -2833,7 +2863,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, tempClearImageBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempClearImageBuffer); glBindTexture(GL_TEXTURE_2D, 0); @@ -3041,7 +3071,7 @@ Render3DError OpenGLRenderer_1_2::CreateGeometryPrograms() glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL); + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glGenTextures(1, &OGLRef.texEdgeColorTableID); glBindTexture(GL_TEXTURE_1D, OGLRef.texEdgeColorTableID); @@ -3049,7 +3079,7 @@ Render3DError OpenGLRenderer_1_2::CreateGeometryPrograms() glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 8, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glGenTextures(1, &OGLRef.texFogDensityTableID); glBindTexture(GL_TEXTURE_1D, OGLRef.texFogDensityTableID); @@ -3057,7 +3087,7 @@ Render3DError OpenGLRenderer_1_2::CreateGeometryPrograms() glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage1D(GL_TEXTURE_1D, 0, GL_INTENSITY, 32, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + glTexImage1D(GL_TEXTURE_1D, 0, GL_RED, 32, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); OGLGeometryFlags programFlags; @@ -3773,7 +3803,7 @@ Render3DError OpenGLRenderer_1_2::UploadClearImage(const u16 *__restrict colorBu { memcpy(OGLRef.workingCIColorBuffer, colorBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16)); glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, OGLRef.workingCIColorBuffer); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, OGL_TEXTURE_SRC_CI_COLOR, OGLRef.workingCIColorBuffer); } if (didDepthStencilChange) @@ -3785,7 +3815,7 @@ Render3DError OpenGLRenderer_1_2::UploadClearImage(const u16 *__restrict colorBu if (didFogAttributesChange) { glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIFogAttributesBuffer[this->_clearImageIndex]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, OGL_TEXTURE_SRC_CI_FOG, OGLRef.workingCIFogAttributesBuffer[this->_clearImageIndex]); } glBindTexture(GL_TEXTURE_2D, 0); @@ -3859,6 +3889,7 @@ Render3DError OpenGLRenderer_1_2::EnableVertexAttributes() glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, texCoord)); glVertexAttribPointer(OGLVertexAttributeID_Color, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, color)); } +#if !defined(GL_ES_VERSION_3_0) else { glEnableClientState(GL_VERTEX_ARRAY); @@ -3868,6 +3899,7 @@ Render3DError OpenGLRenderer_1_2::EnableVertexAttributes() glTexCoordPointer(2, GL_FLOAT, 0, OGLRef.texCoord2fBuffer); glColorPointer(4, GL_FLOAT, 0, OGLRef.color4fBuffer); } +#endif } return OGLERROR_NOERR; @@ -3887,12 +3919,14 @@ Render3DError OpenGLRenderer_1_2::DisableVertexAttributes() glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0); glDisableVertexAttribArray(OGLVertexAttributeID_Color); } +#if !defined(GL_ES_VERSION_3_0) else { glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } +#endif } return OGLERROR_NOERR; @@ -4343,7 +4377,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); glBindTexture(GL_TEXTURE_1D, OGLRef.texEdgeColorTableID); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, edgeColor32); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 8, GL_RGBA, OGL_TEXTURE_SRC_EDGE_COLOR, edgeColor32); } if (this->isShaderSupported) @@ -4363,9 +4397,10 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co { glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); glBindTexture(GL_TEXTURE_1D, OGLRef.texToonTableID); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderState.toonTable16); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, OGL_TEXTURE_SRC_TOON_TABLE, renderState.toonTable16); } } +#if !defined(GL_ES_VERSION_3_0) else { if (renderState.DISP3DCNT.EnableAlphaTest && (renderState.alphaTestRef > 0)) @@ -4385,6 +4420,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); } } +#endif glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); @@ -4693,6 +4729,7 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboRenderID); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); + // See above comment for why we need to get clear the stencil buffer separately. glClearStencil(opaquePolyID); glClear(GL_STENCIL_BUFFER_BIT); @@ -4887,12 +4924,14 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly, bool treatAs glUniform1f(OGLRef.uniformPolyDepthOffset[this->_geometryProgramFlags.value], 0.0f); glUniform1i(OGLRef.uniformPolyIsBackFacing[this->_geometryProgramFlags.value], (isBackFacing) ? GL_TRUE : GL_FALSE); } +#if !defined(GL_ES_VERSION_3_0) else { // Set the texture blending mode static const GLint oglTexBlendMode[4] = {GL_MODULATE, GL_DECAL, GL_MODULATE, GL_MODULATE}; glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, oglTexBlendMode[thePoly.attribute.Mode]); } +#endif return OGLERROR_NOERR; } @@ -4927,6 +4966,7 @@ Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, size_t polyR glUniform1i(OGLRef.uniformTexSingleBitAlpha[this->_geometryProgramFlags.value], (packFormat != TEXMODE_A3I5 && packFormat != TEXMODE_A5I3) ? GL_TRUE : GL_FALSE); glUniform2f(OGLRef.uniformPolyTexScale[this->_geometryProgramFlags.value], theTexture->GetInvWidth(), theTexture->GetInvHeight()); } +#if !defined(GL_ES_VERSION_3_0) else { glEnable(GL_TEXTURE_2D); @@ -4934,6 +4974,7 @@ Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, size_t polyR glLoadIdentity(); glScalef(theTexture->GetInvWidth(), theTexture->GetInvHeight(), 1.0f); } +#endif glBindTexture(GL_TEXTURE_2D, theTexture->GetID()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ((thePoly.texParam.RepeatS_Enable) ? ((thePoly.texParam.MirroredRepeatS_Enable) ? OGLRef.stateTexMirroredRepeat : GL_REPEAT) : GL_CLAMP_TO_EDGE)); @@ -5131,6 +5172,7 @@ Render3DError OpenGLRenderer_1_2::Reset() glFinish(); +#if !defined(GL_ES_VERSION_3_0) if (!this->isShaderSupported) { glEnable(GL_NORMALIZE); @@ -5140,6 +5182,7 @@ Render3DError OpenGLRenderer_1_2::Reset() glEnable(GL_ALPHA_TEST); glEnable(GL_BLEND); } +#endif ENDGL(); @@ -5232,7 +5275,9 @@ Render3DError OpenGLRenderer_1_2::RenderFinish() if (this->isPBOSupported) { +#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); +#endif } else { @@ -5301,7 +5346,9 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) if (this->_mappedFramebuffer != NULL) { +#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); +#endif glFinish(); } } @@ -5309,7 +5356,7 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) if (this->isShaderSupported || this->isFBOSupported) { glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } if (this->isFBOSupported) @@ -5318,13 +5365,13 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, (GLsizei)w, (GLsizei)h, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } glActiveTexture(GL_TEXTURE0); @@ -5553,7 +5600,7 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State &renderState, co glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); glBindTexture(GL_TEXTURE_1D, OGLRef.texEdgeColorTableID); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, edgeColor32); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 8, GL_RGBA, OGL_TEXTURE_SRC_EDGE_COLOR, edgeColor32); } // Setup render states @@ -5572,7 +5619,7 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State &renderState, co { glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); glBindTexture(GL_TEXTURE_1D, OGLRef.texToonTableID); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderState.toonTable16); + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, OGL_TEXTURE_SRC_TOON_TABLE, renderState.toonTable16); } glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); @@ -5642,9 +5689,9 @@ Render3DError OpenGLRenderer_2_1::RenderFinish() { return OGLERROR_BEGINGL_FAILED; } - +#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); - +#endif ENDGL(); } diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index 802c6c162..b8443bd40 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -178,7 +178,9 @@ EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 EXTERNOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 +#if !defined(GL_ES_VERSION_3_0) EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 +#endif EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 // VAO (always available in Apple's implementation of OpenGL, including old versions) diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 41ed760e6..5629627d3 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -2273,6 +2273,7 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); } else +#endif { glDrawBuffer(GL_WORKING_ATTACHMENT_ID); glDisable(GL_BLEND); @@ -2551,19 +2552,19 @@ Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h) } glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_DepthStencil); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, (GLsizei)w, (GLsizei)h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 64c0cb740..4d2d051c9 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -39,8 +39,6 @@ protected: GLsync _syncBufferSetup; CACHE_ALIGN OGLPolyStates _pendingPolyStates[CLIPPED_POLYLIST_SIZE]; - virtual Render3DError InitExtensions(); - virtual Render3DError CreateFBOs(); virtual void DestroyFBOs(); virtual Render3DError CreateMultisampledFBO(GLsizei numSamples); @@ -83,6 +81,7 @@ public: OpenGLRenderer_3_2(); ~OpenGLRenderer_3_2(); + virtual Render3DError InitExtensions(); virtual Render3DError RenderPowerOff(); }; From ba56bbc7c285af2608e84b410ed9e0b901d99aa9 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 3 Jul 2024 13:05:43 -0700 Subject: [PATCH 39/49] OGLRender_3_2.cpp... try again... --- desmume/src/OGLRender_3_2.cpp | 40 ++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 5629627d3..c21ed3a7a 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -657,6 +657,9 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() this->_deviceInfo.isEdgeMarkSupported = true; this->_deviceInfo.isFogSupported = true; + // Need to generate this texture first because FBO creation needs it. + // This texture is only required by shaders, and so if shader creation + // fails, then we can immediately delete this texture if an error occurs. glGenTextures(1, &OGLRef.texFinalColorID); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID); @@ -664,17 +667,16 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); - // Load and create shaders. Return on any error, since v3.2 Core Profile makes shaders mandatory. - this->isShaderSupported = true; - // OpenGL v3.2 Core Profile should have all the necessary features to be able to flip and convert the framebuffer. this->willFlipOnlyFramebufferOnGPU = true; this->willFlipAndConvertFramebufferOnGPU = true; +#ifdef GL_VERSION_3_3 this->_isDualSourceBlendingSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_blend_func_extended"); +#endif this->_isSampleShadingSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_sample_shading"); this->_isConservativeDepthSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_conservative_depth") && IsOpenGLDriverVersionSupported(4, 0, 0); this->_isConservativeDepthAMDSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_AMD_conservative_depth") && IsOpenGLDriverVersionSupported(4, 0, 0); @@ -685,6 +687,9 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() this->_emulateNDSDepthCalculation = CommonSettings.OpenGL_Emulation_NDSDepthCalculation; this->_emulateDepthLEqualPolygonFacing = CommonSettings.OpenGL_Emulation_DepthLEqualPolygonFacing; + // Load and create shaders. Return on any error, since v3.2 Core Profile makes shaders mandatory. + this->isShaderSupported = true; + error = this->CreateGeometryPrograms(); if (error != OGLERROR_NOERR) { @@ -727,10 +732,10 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() INFO("OpenGL: Successfully created geometry shaders.\n"); error = this->InitPostprocessingPrograms(EdgeMarkVtxShader_150, - EdgeMarkFragShader_150, - FramebufferOutputVtxShader_150, - FramebufferOutput6665FragShader_150, - NULL); + EdgeMarkFragShader_150, + FramebufferOutputVtxShader_150, + FramebufferOutput6665FragShader_150, + NULL); if (error != OGLERROR_NOERR) { glUseProgram(0); @@ -836,7 +841,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); glBindTexture(GL_TEXTURE_2D, OGLRef.texGPolyID); @@ -844,7 +849,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID); @@ -852,7 +857,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); @@ -864,7 +869,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, tempClearImageBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempClearImageBuffer); glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -879,7 +884,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, tempClearImageBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempClearImageBuffer); glBindTexture(GL_TEXTURE_2D, 0); @@ -888,8 +893,8 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glGenFramebuffers(1, &OGLRef.fboRenderID); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboClearImageID); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) @@ -1601,12 +1606,14 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro glBindAttribLocation(shaderID.program, OGLVertexAttributeID_Position, "inPosition"); +#ifdef GL_VERSION_3_3 if (this->_isDualSourceBlendingSupported) { glBindFragDataLocationIndexed(shaderID.program, 0, 0, "outFogColor"); glBindFragDataLocationIndexed(shaderID.program, 0, 1, "outFogWeight"); } else +#endif { glBindFragDataLocation(shaderID.program, 0, "outFragColor"); } @@ -1735,10 +1742,12 @@ Render3DError OpenGLRenderer_3_2::InitFinalRenderStates(const std::set_isDualSourceBlendingSupported) { INITOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) } +#endif return error; } @@ -2260,6 +2269,7 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() glUseProgram(shaderID.program); glDisable(GL_STENCIL_TEST); +#ifdef GL_VERSION_3_3 if (this->_isDualSourceBlendingSupported) { glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); From 76fe5f758c1a0d683254693677750cbaadf0bbe5 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 3 Jul 2024 16:55:47 -0700 Subject: [PATCH 40/49] OpenGL: More changes in preparation of OpenGL ES. - Slightly change the names of attachment defines so that they can be distinguished from the native OpenGL attachment defines. - The minimum version driver check now accounts for OpenGL ES. - OpenGLRendererCreate() can now handle any possible OpenGL variant, as declared in the OpenGLVariantID enum. - Framebuffer read backs may now assigned their format and data type. (Legacy OpenGL assigns the format as GL_BGRA, while 3.2 Core Profile assigns the format as GL_RGBA.) --- desmume/src/OGLRender.cpp | 348 ++++++++++++++++++++++------------ desmume/src/OGLRender.h | 51 +++-- desmume/src/OGLRender_3_2.cpp | 110 +++++------ 3 files changed, 320 insertions(+), 189 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 448e6d919..00b698e40 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -105,14 +105,14 @@ const GLfloat PostprocessVtxBuffer[16] = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1. 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}; const GLenum GeometryDrawBuffersEnum[8][4] = { - { GL_COLOROUT_ATTACHMENT_ID, GL_NONE, GL_NONE, GL_NONE }, - { GL_COLOROUT_ATTACHMENT_ID, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_NONE, GL_NONE }, - { GL_COLOROUT_ATTACHMENT_ID, GL_POLYID_ATTACHMENT_ID, GL_NONE, GL_NONE }, - { GL_COLOROUT_ATTACHMENT_ID, GL_POLYID_ATTACHMENT_ID, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_NONE }, - { GL_COLOROUT_ATTACHMENT_ID, GL_WORKING_ATTACHMENT_ID, GL_NONE, GL_NONE }, - { GL_COLOROUT_ATTACHMENT_ID, GL_WORKING_ATTACHMENT_ID, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_NONE }, - { GL_COLOROUT_ATTACHMENT_ID, GL_WORKING_ATTACHMENT_ID, GL_POLYID_ATTACHMENT_ID, GL_NONE }, - { GL_COLOROUT_ATTACHMENT_ID, GL_WORKING_ATTACHMENT_ID, GL_POLYID_ATTACHMENT_ID, GL_FOGATTRIBUTES_ATTACHMENT_ID } + { OGL_COLOROUT_ATTACHMENT_ID, GL_NONE, GL_NONE, GL_NONE }, + { OGL_COLOROUT_ATTACHMENT_ID, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_NONE, GL_NONE }, + { OGL_COLOROUT_ATTACHMENT_ID, OGL_POLYID_ATTACHMENT_ID, GL_NONE, GL_NONE }, + { OGL_COLOROUT_ATTACHMENT_ID, OGL_POLYID_ATTACHMENT_ID, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_NONE }, + { OGL_COLOROUT_ATTACHMENT_ID, OGL_WORKING_ATTACHMENT_ID, GL_NONE, GL_NONE }, + { OGL_COLOROUT_ATTACHMENT_ID, OGL_WORKING_ATTACHMENT_ID, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_NONE }, + { OGL_COLOROUT_ATTACHMENT_ID, OGL_WORKING_ATTACHMENT_ID, OGL_POLYID_ATTACHMENT_ID, GL_NONE }, + { OGL_COLOROUT_ATTACHMENT_ID, OGL_WORKING_ATTACHMENT_ID, OGL_POLYID_ATTACHMENT_ID, OGL_FOGATTRIBUTES_ATTACHMENT_ID } }; const GLint GeometryAttachmentWorkingBuffer[8] = { @@ -161,13 +161,17 @@ void ENDGL() oglrender_endOpenGL(); } -// Function Pointers +// OPENGL CLIENT CONTEXT FUNCTION POINTERS bool (*oglrender_init)() = NULL; bool (*oglrender_beginOpenGL)() = NULL; void (*oglrender_endOpenGL)() = NULL; bool (*oglrender_framebufferDidResizeCallback)(const bool isFBOSupported, size_t w, size_t h) = NULL; + +// OPENGL RENDERER OBJECT CREATION FUNCTION POINTERS void (*OGLLoadEntryPoints_3_2_Func)() = NULL; void (*OGLCreateRenderer_3_2_Func)(OpenGLRenderer **rendererPtr) = NULL; +void (*OGLLoadEntryPoints_ES_3_0_Func)() = NULL; +void (*OGLCreateRenderer_ES_3_0_Func)(OpenGLRenderer **rendererPtr) = NULL; //------------------------------------------------------------ @@ -942,7 +946,7 @@ void OpenGLTexture::SetUpscalingBuffer(void *upscaleBuffer) this->_upscaleBuffer = (u32 *)upscaleBuffer; } -template +template static Render3D* OpenGLRendererCreate() { OpenGLRenderer *newRenderer = NULL; @@ -950,18 +954,64 @@ static Render3D* OpenGLRendererCreate() if (oglrender_init == NULL) { - return NULL; + INFO("OpenGL: oglrender_init is unassigned. Clients must assign this function pointer and have a working context before running OpenGL.\n"); + return newRenderer; + } + + if (oglrender_beginOpenGL == NULL) + { + INFO("OpenGL: oglrender_beginOpenGL is unassigned. Clients must assign this function pointer before running OpenGL.\n"); + return newRenderer; + } + + if (oglrender_endOpenGL == NULL) + { + INFO("OpenGL: oglrender_endOpenGL is unassigned. Clients must assign this function pointer before running OpenGL.\n"); + return newRenderer; } if (!oglrender_init()) { - return NULL; + return newRenderer; } if (!BEGINGL()) { - INFO("OpenGL<%s,%s>: Could not initialize -- BEGINGL() failed.\n", require_profile?"force":"auto", enable_3_2?"3_2":"old"); - return NULL; + char variantString[32] = {0}; + + switch (VARIANTID) + { + case OpenGLVariantID_Legacy_1_2: + strncpy(variantString, "Open GL 1.2 (forced)", sizeof(variantString)); + break; + + case OpenGLVariantID_Legacy_2_0: + strncpy(variantString, "Open GL 2.0 (forced)", sizeof(variantString)); + break; + + case OpenGLVariantID_Legacy_2_1: + strncpy(variantString, "Open GL 2.1 (forced)", sizeof(variantString)); + break; + + case OpenGLVariantID_CoreProfile_3_2: + strncpy(variantString, "Open GL 3.2 (forced)", sizeof(variantString)); + break; + + case OpenGLVariantID_LegacyAuto: + case OpenGLVariantID_StandardAuto: + strncpy(variantString, "Open GL (auto)", sizeof(variantString)); + break; + + case OpenGLVariantID_ES_3_0: + strncpy(variantString, "Open GL ES 3.0", sizeof(variantString)); + break; + + default: + break; + } + + INFO("%s: Could not initialize -- BEGINGL() failed.\n", variantString); + return newRenderer; } // Get OpenGL info @@ -986,59 +1036,102 @@ static Render3D* OpenGLRendererCreate() if (!IsOpenGLDriverVersionSupported(OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION)) { INFO("OpenGL: Driver does not support OpenGL v%u.%u.%u or later. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION, - oglVersionString, oglVendorString, oglRendererString); + OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR, OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION, + oglVersionString, oglVendorString, oglRendererString); ENDGL(); return newRenderer; } // Create new OpenGL rendering object - if (enable_3_2) + if (VARIANTID == OpenGLVariantID_ES_3_0) { - if (OGLLoadEntryPoints_3_2_Func != NULL && OGLCreateRenderer_3_2_Func != NULL) + if ( (OGLLoadEntryPoints_ES_3_0_Func != NULL) && (OGLCreateRenderer_ES_3_0_Func != NULL) ) { - OGLLoadEntryPoints_3_2_Func(); - OGLLoadEntryPoints_Legacy(); //zero 04-feb-2013 - this seems to be necessary as well - OGLCreateRenderer_3_2_Func(&newRenderer); + OGLLoadEntryPoints_ES_3_0_Func(); + OGLLoadEntryPoints_Legacy(); + OGLCreateRenderer_ES_3_0_Func(&newRenderer); } - else + else { - if(require_profile) + ENDGL(); + return newRenderer; + } + } + else + { + if ( (VARIANTID == OpenGLVariantID_StandardAuto) || (VARIANTID == OpenGLVariantID_CoreProfile_3_2) ) + { + if ( (OGLLoadEntryPoints_3_2_Func != NULL) && (OGLCreateRenderer_3_2_Func != NULL) ) + { + OGLLoadEntryPoints_3_2_Func(); + OGLLoadEntryPoints_Legacy(); //zero 04-feb-2013 - this seems to be necessary as well + OGLCreateRenderer_3_2_Func(&newRenderer); + } + else if (VARIANTID == OpenGLVariantID_CoreProfile_3_2) { ENDGL(); return newRenderer; } } - } - - // If the renderer doesn't initialize with OpenGL v3.2 or higher, fall back - // to one of the lower versions. - if (newRenderer == NULL) - { - OGLLoadEntryPoints_Legacy(); - if (IsOpenGLDriverVersionSupported(2, 1, 0)) + if ( (VARIANTID == OpenGLVariantID_StandardAuto) || (VARIANTID == OpenGLVariantID_LegacyAuto) ) { - newRenderer = new OpenGLRenderer_2_1; - newRenderer->SetVersion(2, 1, 0); + // If the renderer doesn't initialize with OpenGL v3.2 or higher, fall back + // to one of the lower versions. + if (newRenderer == NULL) + { + OGLLoadEntryPoints_Legacy(); + if (IsOpenGLDriverVersionSupported(2, 1, 0)) + { + newRenderer = new OpenGLRenderer_2_1; + newRenderer->SetVersion(2, 1, 0); + } + else if (IsOpenGLDriverVersionSupported(2, 0, 0)) + { + newRenderer = new OpenGLRenderer_2_0; + newRenderer->SetVersion(2, 0, 0); + } + else if (IsOpenGLDriverVersionSupported(1, 2, 0)) + { + newRenderer = new OpenGLRenderer_1_2; + newRenderer->SetVersion(1, 2, 0); + } + } } - else if (IsOpenGLDriverVersionSupported(2, 0, 0)) + else if (VARIANTID == OpenGLVariantID_Legacy_2_1) { - newRenderer = new OpenGLRenderer_2_0; - newRenderer->SetVersion(2, 0, 0); + OGLLoadEntryPoints_Legacy(); + if (IsOpenGLDriverVersionSupported(2, 1, 0)) + { + newRenderer = new OpenGLRenderer_2_1; + newRenderer->SetVersion(2, 1, 0); + } } - else if (IsOpenGLDriverVersionSupported(1, 2, 0)) + else if (VARIANTID == OpenGLVariantID_Legacy_2_0) { - newRenderer = new OpenGLRenderer_1_2; - newRenderer->SetVersion(1, 2, 0); + OGLLoadEntryPoints_Legacy(); + if (IsOpenGLDriverVersionSupported(2, 0, 0)) + { + newRenderer = new OpenGLRenderer_2_0; + newRenderer->SetVersion(2, 0, 0); + } + } + else if (VARIANTID == OpenGLVariantID_Legacy_1_2) + { + OGLLoadEntryPoints_Legacy(); + if (IsOpenGLDriverVersionSupported(1, 2, 0)) + { + newRenderer = new OpenGLRenderer_1_2; + newRenderer->SetVersion(1, 2, 0); + } } } if (newRenderer == NULL) { INFO("OpenGL: Renderer did not initialize. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - oglVersionString, oglVendorString, oglRendererString); + oglVersionString, oglVendorString, oglRendererString); ENDGL(); return newRenderer; @@ -1051,30 +1144,30 @@ static Render3D* OpenGLRendererCreate() if (error == OGLERROR_DRIVER_VERSION_TOO_OLD) { INFO("OpenGL: This driver does not support the minimum feature set required to run this renderer. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - oglVersionString, oglVendorString, oglRendererString); + oglVersionString, oglVendorString, oglRendererString); } else if (newRenderer->IsVersionSupported(1, 5, 0) && (error == OGLERROR_VBO_UNSUPPORTED)) { INFO("OpenGL: VBOs are not available, even though this version of OpenGL requires them. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - oglVersionString, oglVendorString, oglRendererString); + oglVersionString, oglVendorString, oglRendererString); } else if ( newRenderer->IsVersionSupported(2, 0, 0) && - (error == OGLERROR_SHADER_CREATE_ERROR || - error == OGLERROR_VERTEX_SHADER_PROGRAM_LOAD_ERROR || - error == OGLERROR_FRAGMENT_SHADER_PROGRAM_LOAD_ERROR) ) + (error == OGLERROR_SHADER_CREATE_ERROR || + error == OGLERROR_VERTEX_SHADER_PROGRAM_LOAD_ERROR || + error == OGLERROR_FRAGMENT_SHADER_PROGRAM_LOAD_ERROR) ) { INFO("OpenGL: Shaders are not working, even though they should be on this version of OpenGL. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - oglVersionString, oglVendorString, oglRendererString); + oglVersionString, oglVendorString, oglRendererString); } else if (newRenderer->IsVersionSupported(2, 1, 0) && (error == OGLERROR_PBO_UNSUPPORTED)) { INFO("OpenGL: PBOs are not available, even though this version of OpenGL requires them. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - oglVersionString, oglVendorString, oglRendererString); + oglVersionString, oglVendorString, oglRendererString); } else if (newRenderer->IsVersionSupported(3, 0, 0) && (error == OGLERROR_FBO_CREATE_ERROR) && (OGLLoadEntryPoints_3_2_Func != NULL)) { INFO("OpenGL: FBOs are not available, even though this version of OpenGL requires them. Disabling 3D renderer.\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - oglVersionString, oglVendorString, oglRendererString); + oglVersionString, oglVendorString, oglRendererString); } delete newRenderer; @@ -1095,7 +1188,7 @@ static Render3D* OpenGLRendererCreate() newRenderer->GetVersion(&major, &minor, &revision); INFO("OpenGL: Renderer initialized successfully (v%u.%u.%u).\n[ Driver Info -\n Version: %s\n Vendor: %s\n Renderer: %s ]\n", - major, minor, revision, oglVersionString, oglVendorString, oglRendererString); + major, minor, revision, oglVersionString, oglVendorString, oglRendererString); return newRenderer; } @@ -1118,27 +1211,34 @@ static void OpenGLRendererDestroy() //automatically select 3.2 or old profile depending on whether 3.2 is available GPU3DInterface gpu3Dgl = { "OpenGL", - OpenGLRendererCreate, + OpenGLRendererCreate, OpenGLRendererDestroy }; //forcibly use old profile GPU3DInterface gpu3DglOld = { "OpenGL Old", - OpenGLRendererCreate, + OpenGLRendererCreate, OpenGLRendererDestroy }; //forcibly use new profile GPU3DInterface gpu3Dgl_3_2 = { "OpenGL 3.2", - OpenGLRendererCreate, + OpenGLRendererCreate, + OpenGLRendererDestroy +}; + +// OpenGL ES 3.0 (this is the only version of ES that is supported right now) +GPU3DInterface gpu3Dgl_ES_3_0 = { + "OpenGL ES 3.0", + OpenGLRendererCreate, OpenGLRendererDestroy }; OpenGLRenderer::OpenGLRenderer() { - _variantID = OpenGLVariantID_Legacy; + _variantID = OpenGLVariantID_LegacyAuto; _deviceInfo.renderID = RENDERID_OPENGL_AUTO; _deviceInfo.renderName = "OpenGL"; @@ -2433,6 +2533,10 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL); this->_deviceInfo.maxAnisotropy = maxAnisotropyOGL; + // This is traditionally the fastest format and data type for glReadPixels in legacy mode. + OGLRef.readPixelsBestFormat = GL_BGRA; + OGLRef.readPixelsBestDataType = GL_UNSIGNED_BYTE; + // Need to generate this texture first because FBO creation needs it. // This texture is only required by shaders, and so if shader creation // fails, then we can immediately delete this texture if an error occurs. @@ -2873,8 +2977,8 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glGenFramebuffersEXT(1, &OGLRef.fboRenderID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboClearImageID); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0); @@ -2887,8 +2991,8 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboFramebufferFlipID); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -2899,10 +3003,10 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0); @@ -2914,8 +3018,8 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() return OGLERROR_FBO_CREATE_ERROR; } - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); OGLRef.selectedRenderingFBO = OGLRef.fboRenderID; INFO("OpenGL: Successfully created FBOs.\n"); @@ -2976,10 +3080,10 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO(GLsizei numSamples) // Set up multisampled rendering FBO glGenFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOROUT_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_WORKING_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGWorkingID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, OGL_COLOROUT_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, OGL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, OGL_WORKING_ATTACHMENT_ID, GL_RENDERBUFFER_EXT, OGLRef.rboMSGWorkingID); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID); @@ -2991,8 +3095,8 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO(GLsizei numSamples) return OGLERROR_FBO_CREATE_ERROR; } - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); INFO("OpenGL: Successfully created multisampled FBO.\n"); @@ -3853,7 +3957,7 @@ void OpenGLRenderer_1_2::_SetupGeometryShaders(const OGLGeometryFlags flags) { if (this->isFBOSupported) { - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); } return; } @@ -3954,7 +4058,7 @@ Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const POLY *rawPolyList, cons // Just downsample the color buffer now so that we have some texture data to sample from in the non-multisample shader. // This is not perfectly pixel accurate, but it's better than nothing. glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); glDrawBuffers(4, GeometryDrawBuffersEnum[this->_geometryProgramFlags.DrawBuffersMode]); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); @@ -4003,7 +4107,7 @@ Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const POLY *rawPolyList, cons this->_geometryProgramFlags.EnableEdgeMark = 0; this->_geometryProgramFlags.EnableFog = 0; this->_SetupGeometryShaders(this->_geometryProgramFlags); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); @@ -4048,12 +4152,12 @@ void OpenGLRenderer_1_2::_ResolveWorkingBackFacing() glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderID); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); + glReadBuffer(OGL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Reset framebuffer targets - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); glDrawBuffers(4, GeometryDrawBuffersEnum[this->_geometryProgramFlags.DrawBuffersMode]); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID); @@ -4076,21 +4180,21 @@ void OpenGLRenderer_1_2::_ResolveGeometry() { if (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) { - glReadBuffer(GL_POLYID_ATTACHMENT_ID); - glDrawBuffer(GL_POLYID_ATTACHMENT_ID); + glReadBuffer(OGL_POLYID_ATTACHMENT_ID); + glDrawBuffer(OGL_POLYID_ATTACHMENT_ID); glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } if (this->_enableFog && this->_deviceInfo.isFogSupported) { - glReadBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); - glDrawBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); + glReadBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); + glDrawBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } // Blit the color and depth buffers - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); // Reset framebuffer targets @@ -4103,8 +4207,8 @@ void OpenGLRenderer_1_2::_ResolveGeometry() glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); } } @@ -4122,16 +4226,16 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() { const GLuint convertProgramID = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.programFramebufferRGBA6665OutputID[1] : OGLRef.programFramebufferRGBA8888OutputID[1]; glUseProgram(convertProgramID); - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); + glReadBuffer(OGL_WORKING_ATTACHMENT_ID); this->_lastTextureDrawTarget = OGLTextureUnitID_FinalColor; } else { const GLuint convertProgramID = (this->_outputFormat == NDSColorFormat_BGR666_Rev) ? OGLRef.programFramebufferRGBA6665OutputID[0] : OGLRef.programFramebufferRGBA8888OutputID[0]; glUseProgram(convertProgramID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); this->_lastTextureDrawTarget = OGLTextureUnitID_GColor; } } @@ -4181,7 +4285,7 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() // Just flips the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware. // Further colorspace conversion will need to be done in a later step. - const GLenum flipTarget = (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) ? GL_WORKING_ATTACHMENT_ID : GL_COLOROUT_ATTACHMENT_ID; + const GLenum flipTarget = (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) ? OGL_WORKING_ATTACHMENT_ID : OGL_COLOROUT_ATTACHMENT_ID; glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboFramebufferFlipID); glDrawBuffer(flipTarget); @@ -4202,7 +4306,7 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() this->_mappedFramebuffer = NULL; } - glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0); + glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, OGLRef.readPixelsBestFormat, OGLRef.readPixelsBestDataType, 0); } this->_pixelReadNeedsFinish = true; @@ -4417,12 +4521,12 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co if (this->isFBOSupported) { - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); } } #endif - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); @@ -4573,7 +4677,7 @@ Render3DError OpenGLRenderer_1_2::PostprocessFramebuffer() glBindTexture(GL_TEXTURE_1D, OGLRef.texEdgeColorTableID); glActiveTexture(GL_TEXTURE0); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glUseProgram(OGLRef.programEdgeMarkID); glUniform1i(OGLRef.uniformStateClearPolyID, this->_pendingRenderStates.clearPolyID); glUniform1f(OGLRef.uniformStateClearDepth, this->_pendingRenderStates.clearDepth); @@ -4596,7 +4700,7 @@ Render3DError OpenGLRenderer_1_2::PostprocessFramebuffer() glUseProgram(OGLRef.programEdgeMarkID); glUniform1i(OGLRef.uniformStateClearPolyID, this->_pendingRenderStates.clearPolyID); glUniform1f(OGLRef.uniformStateClearDepth, this->_pendingRenderStates.clearDepth); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glEnable(GL_BLEND); glDisable(GL_STENCIL_TEST); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -4622,7 +4726,7 @@ Render3DError OpenGLRenderer_1_2::PostprocessFramebuffer() OGLFogShaderID shaderID = this->_fogProgramMap[this->_fogProgramKey.key]; - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); glUseProgram(shaderID.program); glUniform1i(OGLRef.uniformStateEnableFogAlphaOnly, this->_pendingRenderStates.enableFogAlphaOnly); glUniform4fv(OGLRef.uniformStateFogColor, 1, (const GLfloat *)&this->_pendingRenderStates.fogColor); @@ -4686,28 +4790,28 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf { if (this->_emulateDepthLEqualPolygonFacing && this->_isDepthLEqualPolygonFacingSupported) { - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); } if (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) { - glDrawBuffer(GL_POLYID_ATTACHMENT_ID); + glDrawBuffer(OGL_POLYID_ATTACHMENT_ID); glClearColor((GLfloat)opaquePolyID/63.0f, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } if (this->_enableFog && this->_deviceInfo.isFogSupported) { - glReadBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); - glDrawBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); + glReadBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); + glDrawBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); glBlitFramebufferEXT(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } // Blit the color buffer. Do this last so that color attachment 0 is set to the read FBO. - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebufferEXT(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); @@ -4717,8 +4821,8 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf { glBlitFramebufferEXT(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); } if (this->isMultisampledFBOSupported) @@ -4737,28 +4841,28 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf { if (this->_emulateDepthLEqualPolygonFacing && this->_isDepthLEqualPolygonFacingSupported) { - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); } if (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) { - glDrawBuffer(GL_POLYID_ATTACHMENT_ID); + glDrawBuffer(OGL_POLYID_ATTACHMENT_ID); glClearColor((GLfloat)opaquePolyID/63.0f, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } if (this->_enableFog && this->_deviceInfo.isFogSupported) { - glReadBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); - glDrawBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); + glReadBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); + glDrawBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } // Blit the color and depth buffers. Do this last so that color attachment 0 is set to the read FBO. - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); @@ -4770,8 +4874,8 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); } } } @@ -4791,7 +4895,7 @@ Render3DError OpenGLRenderer_1_2::ClearUsingValues(const Color4u8 &clearColor666 if (this->isShaderSupported && this->isFBOSupported) { - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glClearColor(divide6bitBy63_LUT[clearColor6665.r], divide6bitBy63_LUT[clearColor6665.g], divide6bitBy63_LUT[clearColor6665.b], divide5bitBy31_LUT[clearColor6665.a]); glClearDepth((GLclampd)clearAttributes.depth / (GLclampd)0x00FFFFFF); glClearStencil(clearAttributes.opaquePolyID); @@ -4799,21 +4903,21 @@ Render3DError OpenGLRenderer_1_2::ClearUsingValues(const Color4u8 &clearColor666 if (this->_emulateDepthLEqualPolygonFacing && this->_isDepthLEqualPolygonFacingSupported) { - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); } if (this->_enableEdgeMark && this->_deviceInfo.isEdgeMarkSupported) { - glDrawBuffer(GL_POLYID_ATTACHMENT_ID); + glDrawBuffer(OGL_POLYID_ATTACHMENT_ID); glClearColor((GLfloat)clearAttributes.opaquePolyID/63.0f, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } if (this->_enableFog && this->_deviceInfo.isFogSupported) { - glDrawBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); + glDrawBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); glClearColor(clearAttributes.isFogged, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } @@ -4825,8 +4929,8 @@ Render3DError OpenGLRenderer_1_2::ClearUsingValues(const Color4u8 &clearColor666 { if (this->isFBOSupported) { - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); } glClearColor(divide6bitBy63_LUT[clearColor6665.r], divide6bitBy63_LUT[clearColor6665.g], divide6bitBy63_LUT[clearColor6665.b], divide5bitBy31_LUT[clearColor6665.a]); @@ -5233,8 +5337,8 @@ Render3DError OpenGLRenderer_1_2::RenderPowerOff() if (this->isFBOSupported) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); } glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -5248,7 +5352,7 @@ Render3DError OpenGLRenderer_1_2::RenderPowerOff() this->_mappedFramebuffer = NULL; } - glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0); + glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, OGLRef.readPixelsBestFormat, OGLRef.readPixelsBestDataType, 0); } ENDGL(); @@ -5259,6 +5363,8 @@ Render3DError OpenGLRenderer_1_2::RenderPowerOff() Render3DError OpenGLRenderer_1_2::RenderFinish() { + OGLRenderRef &OGLRef = *this->ref; + if (!this->_renderNeedsFinish) { return OGLERROR_NOERR; @@ -5281,7 +5387,7 @@ Render3DError OpenGLRenderer_1_2::RenderFinish() } else { - glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, this->_framebufferColor); + glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, OGLRef.readPixelsBestFormat, OGLRef.readPixelsBestDataType, this->_framebufferColor); } ENDGL(); @@ -5622,7 +5728,7 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State &renderState, co glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, OGL_TEXTURE_SRC_TOON_TABLE, renderState.toonTable16); } - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index b8443bd40..db688186f 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -305,31 +305,43 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) #endif // GL_EXT_framebuffer_object // Define the minimum required OpenGL version for the driver to support -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 1 -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR 2 -#define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION 0 +#if defined(OPENGL_VARIANT_STANDARD) + #define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 1 + #define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR 2 + #define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION 0 +#elif defined(OPENGL_VARIANT_ES) + #define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 3 + #define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MINOR 0 + #define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_REVISION 0 +#else + #error Unknown OpenGL variant. +#endif #define OGLRENDER_VERT_INDEX_BUFFER_COUNT (CLIPPED_POLYLIST_SIZE * 6) // Assign the FBO attachments for the main geometry render #if defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_3_0) - #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0 - #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3 - #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1 - #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2 + #define OGL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0 + #define OGL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3 + #define OGL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1 + #define OGL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2 #else - #define GL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0_EXT - #define GL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3_EXT - #define GL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1_EXT - #define GL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2_EXT + #define OGL_COLOROUT_ATTACHMENT_ID GL_COLOR_ATTACHMENT0_EXT + #define OGL_WORKING_ATTACHMENT_ID GL_COLOR_ATTACHMENT3_EXT + #define OGL_POLYID_ATTACHMENT_ID GL_COLOR_ATTACHMENT1_EXT + #define OGL_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT2_EXT #endif enum OpenGLVariantID { OpenGLVariantID_Unknown = 0, - OpenGLVariantID_Legacy = 1, - OpenGLVariantID_CoreProfile_3_2 = 2, - OpenGLVariantID_ES_3_0 = 3 + OpenGLVariantID_LegacyAuto = 0x1000, + OpenGLVariantID_Legacy_1_2 = 0x1012, + OpenGLVariantID_Legacy_2_0 = 0x1020, + OpenGLVariantID_Legacy_2_1 = 0x1021, + OpenGLVariantID_CoreProfile_3_2 = 0x2032, + OpenGLVariantID_StandardAuto = 0x3000, + OpenGLVariantID_ES_3_0 = 0x4030 }; enum OGLVertexAttributeID @@ -528,6 +540,8 @@ struct OGLRenderRef { // OpenGL Feature Support GLint stateTexMirroredRepeat; + GLint readPixelsBestDataType; + GLint readPixelsBestFormat; // VBO GLuint vboGeometryVtxID; @@ -681,6 +695,15 @@ void ENDGL(); extern void (*OGLLoadEntryPoints_3_2_Func)(); extern void (*OGLCreateRenderer_3_2_Func)(OpenGLRenderer **rendererPtr); +// These functions need to be assigned by ports that support using an +// OpenGL ES 3.0 context. The OGLRender_ES3.cpp file includes the corresponding +// functions to assign to each function pointer. +// +// If any of these functions are unassigned, then the renderer object +// creation will fail. +extern void (*OGLLoadEntryPoints_ES_3_0_Func)(); +extern void (*OGLCreateRenderer_ES_3_0_Func)(OpenGLRenderer **rendererPtr); + bool IsOpenGLDriverVersionSupported(unsigned int checkVersionMajor, unsigned int checkVersionMinor, unsigned int checkVersionRevision); class OpenGLTexture : public Render3DTexture diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index c21ed3a7a..46537e18e 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -593,9 +593,7 @@ out vec4 outFragColor6665;\n\ \n\ void main()\n\ {\n\ - // Note that we swap B and R since pixel readbacks are done in BGRA format for fastest\n\ - // performance. The final color is still in RGBA format.\n\ - outFragColor6665 = texelFetch(texInFragColor, ivec2(gl_FragCoord.x, FRAMEBUFFER_SIZE_Y - gl_FragCoord.y), 0).bgra;\n\ + outFragColor6665 = texelFetch(texInFragColor, ivec2(gl_FragCoord.x, FRAMEBUFFER_SIZE_Y - gl_FragCoord.y), 0);\n\ outFragColor6665 = floor((outFragColor6665 * 255.0) + 0.5);\n\ outFragColor6665.rgb = floor(outFragColor6665.rgb / 4.0);\n\ outFragColor6665.a = floor(outFragColor6665.a / 8.0);\n\ @@ -654,6 +652,10 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL); this->_deviceInfo.maxAnisotropy = (float)maxAnisotropyOGL; + // OpenGL 3.2 should be able to handle the GL_RGBA format in glReadPixels without any performance penalty. + OGLRef.readPixelsBestFormat = GL_RGBA; + OGLRef.readPixelsBestDataType = GL_UNSIGNED_BYTE; + this->_deviceInfo.isEdgeMarkSupported = true; this->_deviceInfo.isFogSupported = true; @@ -893,8 +895,8 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glGenFramebuffers(1, &OGLRef.fboRenderID); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboClearImageID); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) @@ -906,10 +908,10 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() } glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) @@ -1008,17 +1010,17 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) if (this->willUsePerSampleZeroDstPass) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGWorkingID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGWorkingID, 0); } else { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOROUT_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGColorID); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_WORKING_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGColorID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) @@ -1794,7 +1796,7 @@ Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const POLY *rawPolyList, cons // Just downsample the color buffer now so that we have some texture data to sample from in the non-multisample shader. // This is not perfectly pixel accurate, but it's better than nothing. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboRenderID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); glDrawBuffers(4, GeometryDrawBuffersEnum[this->_geometryProgramFlags.DrawBuffersMode]); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO); @@ -1822,7 +1824,7 @@ Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const POLY *rawPolyList, cons this->_geometryProgramFlags.EnableEdgeMark = 0; this->_geometryProgramFlags.EnableFog = 0; this->_SetupGeometryShaders(this->_geometryProgramFlags); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); @@ -1867,12 +1869,12 @@ void OpenGLRenderer_3_2::_ResolveWorkingBackFacing() glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboRenderID); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); + glReadBuffer(OGL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Reset framebuffer targets - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); glDrawBuffers(4, GeometryDrawBuffersEnum[this->_geometryProgramFlags.DrawBuffersMode]); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); @@ -1893,21 +1895,21 @@ void OpenGLRenderer_3_2::_ResolveGeometry() if (this->_enableEdgeMark) { - glReadBuffer(GL_POLYID_ATTACHMENT_ID); - glDrawBuffer(GL_POLYID_ATTACHMENT_ID); + glReadBuffer(OGL_POLYID_ATTACHMENT_ID); + glDrawBuffer(OGL_POLYID_ATTACHMENT_ID); glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } if (this->_enableFog) { - glReadBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); - glDrawBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); + glReadBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); + glDrawBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } // Blit the color and depth buffers - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); // Reset framebuffer targets @@ -1927,15 +1929,15 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels() { // Use the alternate program where the output color is not at index 0. glUseProgram(OGLRef.programFramebufferRGBA6665OutputID[1]); - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); + glReadBuffer(OGL_WORKING_ATTACHMENT_ID); } else { // Use the program where the output color is from index 0. glUseProgram(OGLRef.programFramebufferRGBA6665OutputID[0]); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); } glViewport(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); @@ -1954,24 +1956,24 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels() this->_mappedFramebuffer = NULL; } - glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0); + glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, OGLRef.readPixelsBestFormat, OGLRef.readPixelsBestDataType, 0); } else { // Just flips the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware. if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) { - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebuffer(0, (GLint)this->_framebufferHeight, (GLint)this->_framebufferWidth, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); + glReadBuffer(OGL_WORKING_ATTACHMENT_ID); } else { - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_WORKING_ATTACHMENT_ID); glBlitFramebuffer(0, (GLint)this->_framebufferHeight, (GLint)this->_framebufferWidth, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); } // Read back the pixels in RGBA format, since an OpenGL 3.2 device should be able to read back this @@ -1982,7 +1984,7 @@ Render3DError OpenGLRenderer_3_2::ReadBackPixels() this->_mappedFramebuffer = NULL; } - glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, OGLRef.readPixelsBestFormat, OGLRef.readPixelsBestDataType, 0); } this->_pixelReadNeedsFinish = true; @@ -2186,7 +2188,7 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co this->_geometryProgramFlags.OpaqueDrawMode = 1; this->_SetupGeometryShaders(this->_geometryProgramFlags); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); @@ -2230,7 +2232,7 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Pass 2: Unblended edge mark colors to zero-alpha pixels - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glUseProgram(OGLRef.programEdgeMarkID); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); glStencilFunc(GL_NOTEQUAL, 0x40, 0x40); @@ -2245,7 +2247,7 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() else { glUseProgram(OGLRef.programEdgeMarkID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glEnable(GL_BLEND); glDisable(GL_STENCIL_TEST); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -2272,7 +2274,7 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() #ifdef GL_VERSION_3_3 if (this->_isDualSourceBlendingSupported) { - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glEnable(GL_BLEND); glBlendFunc(GL_SRC1_COLOR, GL_ONE_MINUS_SRC1_COLOR); glBlendEquation(GL_FUNC_ADD); @@ -2285,7 +2287,7 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() else #endif { - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); + glDrawBuffer(OGL_WORKING_ATTACHMENT_ID); glDisable(GL_BLEND); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -2324,14 +2326,14 @@ Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuf if (this->_enableFog) { // Blit the fog buffer - glReadBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); - glDrawBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); + glReadBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); + glDrawBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); glBlitFramebuffer(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } // Blit the color and depth/stencil buffers. Do this last so that color attachment 0 is set to the read FBO. - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebuffer(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GPU_FRAMEBUFFER_NATIVE_WIDTH, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); @@ -2358,14 +2360,14 @@ Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuf if (this->_enableFog) { - glReadBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); - glDrawBuffer(GL_FOGATTRIBUTES_ATTACHMENT_ID); + glReadBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); + glDrawBuffer(OGL_FOGATTRIBUTES_ATTACHMENT_ID); glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } // Blit the color and depth/stencil buffers. Do this last so that color attachment 0 is set to the read FBO. - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO); @@ -2640,8 +2642,8 @@ Render3DError OpenGLRenderer_3_2::RenderPowerOff() } glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glClearBufferfv(GL_COLOR, 0, oglColor); if (this->_mappedFramebuffer != NULL) @@ -2650,7 +2652,7 @@ Render3DError OpenGLRenderer_3_2::RenderPowerOff() this->_mappedFramebuffer = NULL; } - glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0); + glReadPixels(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, OGLRef.readPixelsBestFormat, OGLRef.readPixelsBestDataType, 0); ENDGL(); From c962c550e76cb92d22460b648153cbc9a00f3473 Mon Sep 17 00:00:00 2001 From: rogerman Date: Fri, 5 Jul 2024 18:13:43 -0700 Subject: [PATCH 41/49] OpenGL: Handle legacy functions and tokens more gracefully for OpenGL variants that may not have them. --- desmume/src/OGLRender.cpp | 17 ++------------- desmume/src/OGLRender.h | 40 ++++++++++++++++++++++++++++++++--- desmume/src/OGLRender_3_2.cpp | 5 +++++ 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 00b698e40..782dac4c3 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -55,11 +55,6 @@ #define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_BYTE #define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_BYTE #define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_5_5_5_1 - - #define GL_TEXTURE_1D GL_TEXTURE_2D - #define glTexSubImage1D(target, level, xoffset, width, format, type, pixels) - - #define glClearDepth(depth) glClearDepthf(depth) #else #error Unknown OpenGL variant. #endif @@ -229,7 +224,7 @@ OGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 OGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 OGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 OGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 -#if !defined(GL_ES_VERSION_3_0) +#if defined(GL_VERSION_1_5) OGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 #endif OGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 @@ -304,7 +299,7 @@ static void OGLLoadEntryPoints_Legacy() INITOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 INITOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 INITOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 -#if !defined(GL_ES_VERSION_3_0) +#if defined(GL_VERSION_1_5) INITOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 #endif INITOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 @@ -2795,9 +2790,7 @@ Render3DError OpenGLRenderer_1_2::CreatePBOs() glGenBuffers(1, &OGLRef.pboRenderDataID); glBindBuffer(GL_PIXEL_PACK_BUFFER, OGLRef.pboRenderDataID); glBufferData(GL_PIXEL_PACK_BUFFER, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ); -#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); -#endif return OGLERROR_NOERR; } @@ -5381,9 +5374,7 @@ Render3DError OpenGLRenderer_1_2::RenderFinish() if (this->isPBOSupported) { -#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); -#endif } else { @@ -5452,9 +5443,7 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) if (this->_mappedFramebuffer != NULL) { -#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); -#endif glFinish(); } } @@ -5795,9 +5784,7 @@ Render3DError OpenGLRenderer_2_1::RenderFinish() { return OGLERROR_BEGINGL_FAILED; } -#if !defined(GL_ES_VERSION_3_0) this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); -#endif ENDGL(); } diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index db688186f..b86e34759 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -178,7 +178,7 @@ EXTERNOGLEXT(PFNGLDELETEBUFFERSPROC, glDeleteBuffers) // Core in v1.5 EXTERNOGLEXT(PFNGLBINDBUFFERPROC, glBindBuffer) // Core in v1.5 EXTERNOGLEXT(PFNGLBUFFERDATAPROC, glBufferData) // Core in v1.5 EXTERNOGLEXT(PFNGLBUFFERSUBDATAPROC, glBufferSubData) // Core in v1.5 -#if !defined(GL_ES_VERSION_3_0) +#if defined(GL_VERSION_1_5) EXTERNOGLEXT(PFNGLMAPBUFFERPROC, glMapBuffer) // Core in v1.5 #endif EXTERNOGLEXT(PFNGLUNMAPBUFFERPROC, glUnmapBuffer) // Core in v1.5 @@ -199,8 +199,10 @@ EXTERNOGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 and ES v3. EXTERNOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 and ES v3.0 // Shaders -#if !defined(GL_ES_VERSION_3_0) +#if defined(GL_VERSION_3_0) EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES +#endif +#if defined(GL_VERSION_3_3) || defined(GL_ARB_blend_func_extended) EXTERNOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3, not available in ES #endif @@ -222,7 +224,7 @@ EXTERNOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 and EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 and ES v2.0 EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 and ES v3.0 EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 and ES v2.0 -#if !defined(GL_ES_VERSION_3_0) +#if defined(GL_VERSION_3_2) || defined(GL_ARB_texture_multisample) EXTERNOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2, not available in ES #endif @@ -304,6 +306,38 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) #endif // GL_EXT_framebuffer_object +// OPENGL CORE EQUIVALENTS FOR LEGACY FUNCTIONS +// Some OpenGL variants, such as OpenGL ES, do not include certain legacy functions in their +// API. The loss of these functions will cause compile time errors when referenced, and so +// we will redeclare them to something that is supported for the sake of compiling. +// +// Do note that a redeclared function will most likely not work in exactly the same way as +// a native legacy version, and so implmentations are responsible for overriding any methods +// that use these legacy functions to whatever is available in the specific OpenGL variant. + +#ifndef GL_VERSION_1_2 + // These legacy functions can be promoted to later core equivalents without any further + // modification. In other words, these are one-to-one drop-in replacements. + #define glClearDepth(depth) glClearDepthf(depth) + #define glDrawBuffer(x) glDrawBuffers(1, ((GLenum[]){x})) + + // 1D textures may not exist for a particular OpenGL variant, so they will be promoted to + // 2D textures instead. Implementations need to modify their GLSL shaders accordingly to + // treat any 1D textures as 2D textures instead. + #define GL_TEXTURE_1D GL_TEXTURE_2D + #define glTexImage1D(target, level, internalformat, width, border, format, type, pixels) glTexImage2D(target, level, internalformat, width, 1, border, format, type, pixels) + #define glTexSubImage1D(target, level, xoffset, width, format, type, pixels) glTexSubImage2D(target, level, xoffset, 0, width, 1, format, type, pixels) +#endif + +#ifndef GL_VERSION_1_5 + // Calling glMapBuffer with an OpenGL variant that forgoes legacy functions will cause a + // GL_INVALID_OPERATION error if used in practice. Implementations need to override any + // methods that would call glMapBuffer with glMapBufferRange. + #define GL_READ_ONLY GL_MAP_READ_BIT + #define GL_WRITE_ONLY GL_MAP_WRITE_BIT + #define glMapBuffer(target, access) glMapBufferRange(target, 0, 0, access) +#endif + // Define the minimum required OpenGL version for the driver to support #if defined(OPENGL_VARIANT_STANDARD) #define OGLRENDER_MINIMUM_DRIVER_VERSION_REQUIRED_MAJOR 1 diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 46537e18e..7fe311882 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -39,7 +39,9 @@ OGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 and ES v3.0 // Shaders OGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES +#if defined(GL_VERSION_3_3) || defined(GL_ARB_blend_func_extended) OGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3, not available in ES +#endif // Buffer Objects OGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 and ES v3.0 @@ -84,6 +86,9 @@ void OGLLoadEntryPoints_3_2() // Shaders INITOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES +#if defined(GL_VERSION_3_3) || defined(GL_ARB_blend_func_extended) + INITOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3, not available in ES +#endif // Buffer Objects INITOGLEXT(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange) // Core in v3.0 and ES v3.0 From 09090e93f9b5281f48b927a6e95f01edd3e88b82 Mon Sep 17 00:00:00 2001 From: rogerman Date: Sat, 6 Jul 2024 13:58:05 -0700 Subject: [PATCH 42/49] GFX3D: Change POLYLIST_SIZE to 16384 to ensure proper memory alignment with buffers based on CLIPPED_POLYLIST_SIZE and VERTLIST_SIZE. --- desmume/src/gfx3d.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index 3328a44ce..ed993a252 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006 yopyop - Copyright (C) 2008-2023 DeSmuME team + Copyright (C) 2008-2024 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -561,7 +561,7 @@ bool GFX3D_IsPolyWireframe(const POLY &p); bool GFX3D_IsPolyOpaque(const POLY &p); bool GFX3D_IsPolyTranslucent(const POLY &p); -#define POLYLIST_SIZE 16383 +#define POLYLIST_SIZE 16384 #define CLIPPED_POLYLIST_SIZE (POLYLIST_SIZE * 2) #define VERTLIST_SIZE (POLYLIST_SIZE * 4) From 7dbece1082cccc8a6fda15b3ca3f6f2bc5fce016 Mon Sep 17 00:00:00 2001 From: rogerman Date: Sat, 6 Jul 2024 16:20:53 -0700 Subject: [PATCH 43/49] OpenGL: Do some minor changes to the 3.2 Core Profile renderer to make it more cross-compatible with OpenGL ES 3.0. - PBO handling now works via glMapBufferRange() instead of glMapBuffer(). - Polygon states can now be uploaded using plain integer textures. 64k UBOs and TBOs are no longer required. --- desmume/src/OGLRender_3_2.cpp | 86 ++++++++++++++++++++++++++++++++--- desmume/src/OGLRender_3_2.h | 3 ++ 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 7fe311882..ca1de48ea 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -136,8 +136,10 @@ layout (std140) uniform PolyStates\n\ {\n\ ivec4 value[4096];\n\ } polyState;\n\ -#else\n\ +#elif IS_USING_TBO_POLY_STATES\n\ uniform isamplerBuffer PolyStates;\n\ +#else\n\ +uniform isampler2D PolyStates;\n\ #endif\n\ uniform int polyIndex;\n\ uniform bool polyDrawShadow;\n\ @@ -159,8 +161,10 @@ void main()\n\ #if IS_USING_UBO_POLY_STATES\n\ ivec4 polyStateVec = polyState.value[polyIndex >> 2];\n\ int polyStateBits = polyStateVec[polyIndex & 0x03];\n\ -#else\n\ +#elif IS_USING_TBO_POLY_STATES\n\ int polyStateBits = texelFetch(PolyStates, polyIndex).r;\n\ +#else\n\ + int polyStateBits = texelFetch(PolyStates, ivec2(polyIndex & 0x00FF, (polyIndex >> 8) & 0x007F), 0).r;\n\ #endif\n\ int texSizeShiftS = (polyStateBits >> 18) & 0x07;\n\ int texSizeShiftT = (polyStateBits >> 21) & 0x07;\n\ @@ -620,6 +624,7 @@ OpenGLRenderer_3_2::OpenGLRenderer_3_2() { _variantID = OpenGLVariantID_CoreProfile_3_2; _is64kUBOSupported = false; + _isTBOSupported = false; _isDualSourceBlendingSupported = false; _isSampleShadingSupported = false; _isConservativeDepthSupported = false; @@ -653,6 +658,9 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUBOSize); this->_is64kUBOSupported = (maxUBOSize >= 65536); + // TBOs should always be supported in 3.2 Core Profile. + this->_isTBOSupported = true; + GLfloat maxAnisotropyOGL = 1.0f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL); this->_deviceInfo.maxAnisotropy = (float)maxAnisotropyOGL; @@ -819,6 +827,18 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() return OGLERROR_NOERR; } +Render3DError OpenGLRenderer_3_2::CreatePBOs() +{ + OGLRenderRef &OGLRef = *this->ref; + + glGenBuffers(1, &OGLRef.pboRenderDataID); + glBindBuffer(GL_PIXEL_PACK_BUFFER, OGLRef.pboRenderDataID); + glBufferData(GL_PIXEL_PACK_BUFFER, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ); + this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, this->_framebufferColorSizeBytes, GL_MAP_READ_BIT); + + return OGLERROR_NOERR; +} + Render3DError OpenGLRenderer_3_2::CreateFBOs() { OGLRenderRef &OGLRef = *this->ref; @@ -1182,6 +1202,9 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() if (this->_is64kUBOSupported) { + // Try transferring the polygon states through a UBO first. This is the fastest method, + // but requires a GPU that supports 64k UBO transfers. Most modern GPUs should support + // this. if (OGLRef.uboPolyStatesID == 0) { glGenBuffers(1, &OGLRef.uboPolyStatesID); @@ -1190,8 +1213,11 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() glBindBufferBase(GL_UNIFORM_BUFFER, OGLBindingPointID_PolyStates, OGLRef.uboPolyStatesID); } } - else + else if (this->_isTBOSupported) { + // Older GPUs that support 3.2 Core Profile but not 64k UBOs can transfer the polygon + // states through a TBO instead. While not as fast as using a UBO, TBOs are always + // available on any GPU that supports 3.2 Core Profile. if (OGLRef.tboPolyStatesID == 0) { // Set up poly states TBO @@ -1206,6 +1232,21 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() glActiveTexture(GL_TEXTURE0); } } + else + { + // For compatibility reasons, we can transfer the polygon states through a plain old + // integer texture. This can be useful for inheritors of this class that may not support + // 64k UBOs or TBOs. + glGenTextures(1, &OGLRef.texPolyStatesID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPolyStatesID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, 256, 128, 0, GL_RED_INTEGER, GL_INT, NULL); + glActiveTexture(GL_TEXTURE0); + } glGenTextures(1, &OGLRef.texFogDensityTableID); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); @@ -1231,6 +1272,7 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() } vtxShaderHeader << "\n"; vtxShaderHeader << "#define IS_USING_UBO_POLY_STATES " << ((OGLRef.uboPolyStatesID != 0) ? 1 : 0) << "\n"; + vtxShaderHeader << "#define IS_USING_TBO_POLY_STATES " << ((OGLRef.tboPolyStatesID != 0) ? 1 : 0) << "\n"; vtxShaderHeader << "#define DEPTH_EQUALS_TEST_TOLERANCE " << DEPTH_EQUALS_TEST_TOLERANCE << ".0\n"; vtxShaderHeader << "\n"; @@ -2138,7 +2180,7 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co OGLPolyStates *polyStates = this->_pendingPolyStates; - if (OGLRef.uboPolyStatesID == 0) + if (OGLRef.tboPolyStatesID != 0) { // Some drivers seem to have problems with GL_TEXTURE_BUFFER used as the target for // glMapBufferRange() or glBufferSubData(), causing certain polygons to intermittently @@ -2177,10 +2219,17 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboPolyStatesID); glBufferSubData(GL_UNIFORM_BUFFER, 0, MAX_CLIPPED_POLY_COUNT_FOR_UBO * sizeof(OGLPolyStates), this->_pendingPolyStates); } - else + else if (OGLRef.tboPolyStatesID != 0) { glUnmapBuffer(GL_TEXTURE_BUFFER); } + else + { + const GLsizei texH = (GLsizei)((this->_clippedPolyCount >> 8) & 0x007F) + 1; + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPolyStatesID); // Why is this bind necessary? Theoretically, it shouldn't be necessary, but real-world testing has proven otherwise... + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, texH, GL_RED_INTEGER, GL_INT, this->_pendingPolyStates); + } // Set up the default draw call states. this->_geometryProgramFlags.value = 0; @@ -2564,7 +2613,7 @@ Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h) if (this->_mappedFramebuffer != NULL) { - this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); + this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, newFramebufferColorSizeBytes, GL_MAP_READ_BIT); glFinish(); } @@ -2627,6 +2676,31 @@ Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h) return error; } +Render3DError OpenGLRenderer_3_2::RenderFinish() +{ + if (!this->_renderNeedsFinish) + { + return OGLERROR_NOERR; + } + + if (this->_pixelReadNeedsFinish) + { + this->_pixelReadNeedsFinish = false; + + if(!BEGINGL()) + { + return OGLERROR_BEGINGL_FAILED; + } + this->_mappedFramebuffer = (Color4u8 *__restrict)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, this->_framebufferColorSizeBytes, GL_MAP_READ_BIT); + ENDGL(); + } + + this->_renderNeedsFlushMain = true; + this->_renderNeedsFlush16 = true; + + return OGLERROR_NOERR; +} + Render3DError OpenGLRenderer_3_2::RenderPowerOff() { OGLRenderRef &OGLRef = *this->ref; diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 4d2d051c9..6f05c466b 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -31,6 +31,7 @@ class OpenGLRenderer_3_2 : public OpenGLRenderer_2_1 { protected: bool _is64kUBOSupported; + bool _isTBOSupported; bool _isDualSourceBlendingSupported; bool _isSampleShadingSupported; bool _isConservativeDepthSupported; @@ -39,6 +40,7 @@ protected: GLsync _syncBufferSetup; CACHE_ALIGN OGLPolyStates _pendingPolyStates[CLIPPED_POLYLIST_SIZE]; + virtual Render3DError CreatePBOs(); virtual Render3DError CreateFBOs(); virtual void DestroyFBOs(); virtual Render3DError CreateMultisampledFBO(GLsizei numSamples); @@ -82,6 +84,7 @@ public: ~OpenGLRenderer_3_2(); virtual Render3DError InitExtensions(); + virtual Render3DError RenderFinish(); virtual Render3DError RenderPowerOff(); }; From 384854f6e753774fbb70dc67558705dfe29135de Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 9 Jul 2024 01:18:50 -0700 Subject: [PATCH 44/49] OpenGL Renderer: More updates to the 3.2 Core Profile renderer to be more cross-compatible with OpenGL ES 3.0. - Add support for fixed locations in shaders for OpenGL 3.3 and later. - The fog density table texture is now a 2D texture instead of a 1D texture. - Fix a memory leak where the polygon state texture wasn't being deleted upon the destruction of the OpenGLRenderer object. --- desmume/src/OGLRender.cpp | 7 + desmume/src/OGLRender_3_2.cpp | 424 +++++++++++++++++++++++++--------- desmume/src/OGLRender_3_2.h | 4 +- 3 files changed, 330 insertions(+), 105 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 782dac4c3..515d55e93 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -3044,6 +3044,13 @@ void OpenGLRenderer_1_2::DestroyFBOs() OGLRef.fboClearImageID = 0; OGLRef.fboFramebufferFlipID = 0; OGLRef.fboRenderID = 0; + OGLRef.texCIColorID = 0; + OGLRef.texCIFogAttrID = 0; + OGLRef.texCIDepthStencilID = 0; + OGLRef.texGColorID = 0; + OGLRef.texGPolyID = 0; + OGLRef.texGFogAttrID = 0; + OGLRef.texGDepthStencilID = 0; this->isFBOSupported = false; } diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index ca1de48ea..31d9084cf 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -19,6 +19,7 @@ #include "OGLRender_3_2.h" +#include #include #include #include @@ -38,7 +39,9 @@ OGLEXT(PFNGLCLEARBUFFERFVPROC, glClearBufferfv) // Core in v3.0 and ES v3.0 OGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 and ES v3.0 // Shaders +#if defined(GL_VERSION_3_0) OGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES +#endif #if defined(GL_VERSION_3_3) || defined(GL_ARB_blend_func_extended) OGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3, not available in ES #endif @@ -61,7 +64,9 @@ OGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0 and ES v2. OGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 and ES v2.0 OGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 and ES v3.0 OGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 and ES v2.0 +#if defined(GL_VERSION_3_2) OGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2, not available in ES +#endif // UBO OGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 and ES v3.0 @@ -70,7 +75,9 @@ OGLEXT(PFNGLBINDBUFFERBASEPROC, glBindBufferBase) // Core in v3.0 and ES v3.0 OGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 and ES v3.0 // TBO +#if defined(GL_VERSION_3_1) || defined(GL_ES_VERSION_3_2) OGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 and ES v3.2 +#endif // Sync Objects OGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 and ES v3.0 @@ -85,7 +92,9 @@ void OGLLoadEntryPoints_3_2() INITOGLEXT(PFNGLCLEARBUFFERFIPROC, glClearBufferfi) // Core in v3.0 and ES v3.0 // Shaders +#if defined(GL_VERSION_3_0) INITOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0, not available in ES +#endif #if defined(GL_VERSION_3_3) || defined(GL_ARB_blend_func_extended) INITOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) // Core in v3.3, not available in ES #endif @@ -108,7 +117,9 @@ void OGLLoadEntryPoints_3_2() INITOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0 and ES v2.0 INITOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0 and ES v3.0 INITOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0 and ES v2.0 +#if defined(GL_VERSION_3_2) INITOGLEXT(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample) // Core in v3.2, not available in ES +#endif // UBO INITOGLEXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex) // Core in v3.1 and ES v3.0 @@ -117,7 +128,9 @@ void OGLLoadEntryPoints_3_2() INITOGLEXT(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv) // Core in v3.1 and ES v3.0 // TBO +#if defined(GL_VERSION_3_1) || defined(GL_ES_VERSION_3_2) INITOGLEXT(PFNGLTEXBUFFERPROC, glTexBuffer) // Core in v3.1 and ES v3.2 +#endif // Sync Objects INITOGLEXT(PFNGLFENCESYNCPROC, glFenceSync) // Core in v3.2 and ES v3.0 @@ -127,9 +140,9 @@ void OGLLoadEntryPoints_3_2() // Vertex shader for geometry, GLSL 1.50 static const char *GeometryVtxShader_150 = {"\ -in vec4 inPosition;\n\ -in vec2 inTexCoord0;\n\ -in vec3 inColor; \n\ +IN_VTX_POSITION vec4 inPosition;\n\ +IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ +IN_VTX_COLOR vec3 inColor; \n\ \n\ #if IS_USING_UBO_POLY_STATES\n\ layout (std140) uniform PolyStates\n\ @@ -227,19 +240,19 @@ uniform bool drawModeDepthEqualsTest;\n\ uniform bool polyDrawShadow;\n\ uniform float polyDepthOffset;\n\ \n\ +OUT_COLOR vec4 outFragColor;\n\ +\n\ #if DRAW_MODE_OPAQUE\n\ -out vec4 outDstBackFacing;\n\ +OUT_WORKING_BUFFER vec4 outDstBackFacing;\n\ #elif USE_DEPTH_LEQUAL_POLYGON_FACING\n\ uniform sampler2D inDstBackFacing;\n\ #endif\n\ \n\ -out vec4 outFragColor;\n\ -\n\ #if ENABLE_EDGE_MARK\n\ -out vec4 outPolyID;\n\ +OUT_POLY_ID vec4 outPolyID;\n\ #endif\n\ #if ENABLE_FOG\n\ -out vec4 outFogAttributes;\n\ +OUT_FOG_ATTRIBUTES vec4 outFogAttributes;\n\ #endif\n\ #if IS_CONSERVATIVE_DEPTH_SUPPORTED && (USE_NDS_DEPTH_CALCULATION || ENABLE_FOG) && !ENABLE_W_DEPTH\n\ layout (depth_less) out float gl_FragDepth;\n\ @@ -342,7 +355,7 @@ void main()\n\ // Vertex shader for determining which pixels have a zero alpha, GLSL 1.50 static const char *GeometryZeroDstAlphaPixelMaskVtxShader_150 = {"\ -in vec2 inPosition;\n\ +IN_VTX_POSITION vec2 inPosition;\n\ \n\ void main()\n\ {\n\ @@ -382,8 +395,8 @@ void main()\n\ // Vertex shader for applying edge marking, GLSL 1.50 static const char *EdgeMarkVtxShader_150 = {"\ -in vec2 inPosition;\n\ -in vec2 inTexCoord0;\n\ +IN_VTX_POSITION vec2 inPosition;\n\ +IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ \n\ out vec2 texCoord[5];\n\ \n\ @@ -423,7 +436,7 @@ layout (std140) uniform RenderStates\n\ uniform sampler2D texInFragDepth;\n\ uniform sampler2D texInPolyID;\n\ \n\ -out vec4 outEdgeColor;\n\ +OUT_COLOR vec4 outEdgeColor;\n\ \n\ void main()\n\ {\n\ @@ -512,7 +525,7 @@ void main()\n\ // Vertex shader for applying fog, GLSL 1.50 static const char *FogVtxShader_150 = {"\ -in vec2 inPosition;\n\ +IN_VTX_POSITION vec2 inPosition;\n\ \n\ void main()\n\ {\n\ @@ -539,14 +552,14 @@ layout (std140) uniform RenderStates\n\ \n\ uniform sampler2D texInFragDepth;\n\ uniform sampler2D texInFogAttributes;\n\ -uniform sampler1D texFogDensityTable;\n\ +uniform sampler2D texFogDensityTable;\n\ \n\ #if USE_DUAL_SOURCE_BLENDING\n\ -out vec4 outFogColor;\n\ -out vec4 outFogWeight;\n\ +OUT_FOG_COLOR vec4 outFogColor;\n\ +OUT_FOG_WEIGHT vec4 outFogWeight;\n\ #else\n\ uniform sampler2D texInFragColor;\n\ -out vec4 outFragColor;\n\ +OUT_COLOR vec4 outFragColor;\n\ #endif\n\ \n\ void main()\n\ @@ -565,11 +578,11 @@ void main()\n\ float fogMixWeight = 0.0;\n\ if (FOG_STEP == 0)\n\ {\n\ - fogMixWeight = texture( texFogDensityTable, (inFragDepth <= FOG_OFFSETF) ? 0.0 : 1.0 ).r;\n\ + fogMixWeight = texture( texFogDensityTable, vec2( (inFragDepth <= FOG_OFFSETF) ? 0.0 : 1.0, 0.0 ) ).r;\n\ }\n\ else\n\ {\n\ - fogMixWeight = texture( texFogDensityTable, (inFragDepth * (1024.0/float(FOG_STEP))) + (((-float(FOG_OFFSET)/float(FOG_STEP)) - 0.5) / 32.0) ).r;\n\ + fogMixWeight = texture( texFogDensityTable, vec2( (inFragDepth * (1024.0/float(FOG_STEP))) + (((-float(FOG_OFFSET)/float(FOG_STEP)) - 0.5) / 32.0), 0.0 ) ).r;\n\ }\n\ \n\ if (polyEnableFog)\n\ @@ -586,7 +599,7 @@ void main()\n\ // Vertex shader for the final framebuffer, GLSL 1.50 static const char *FramebufferOutputVtxShader_150 = {"\ -in vec2 inPosition;\n\ +IN_VTX_POSITION vec2 inPosition;\n\ \n\ void main()\n\ {\n\ @@ -594,11 +607,11 @@ void main()\n\ }\n\ "}; -// Fragment shader for the final framebuffer, GLSL 1.50 +// Fragment shader for the final RGBA6665 formatted framebuffer, GLSL 1.50 static const char *FramebufferOutput6665FragShader_150 = {"\ uniform sampler2D texInFragColor;\n\ \n\ -out vec4 outFragColor6665;\n\ +OUT_COLOR vec4 outFragColor6665;\n\ \n\ void main()\n\ {\n\ @@ -625,6 +638,7 @@ OpenGLRenderer_3_2::OpenGLRenderer_3_2() _variantID = OpenGLVariantID_CoreProfile_3_2; _is64kUBOSupported = false; _isTBOSupported = false; + _isShaderFixedLocationSupported = false; _isDualSourceBlendingSupported = false; _isSampleShadingSupported = false; _isConservativeDepthSupported = false; @@ -661,6 +675,9 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() // TBOs should always be supported in 3.2 Core Profile. this->_isTBOSupported = true; + // Fixed locations in shaders are only supported in v3.3 and later. + this->_isShaderFixedLocationSupported = IsOpenGLDriverVersionSupported(3, 3, 0); + GLfloat maxAnisotropyOGL = 1.0f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL); this->_deviceInfo.maxAnisotropy = (float)maxAnisotropyOGL; @@ -975,6 +992,13 @@ void OpenGLRenderer_3_2::DestroyFBOs() OGLRef.fboClearImageID = 0; OGLRef.fboRenderID = 0; + OGLRef.texCIColorID = 0; + OGLRef.texCIFogAttrID = 0; + OGLRef.texCIDepthStencilID = 0; + OGLRef.texGColorID = 0; + OGLRef.texGPolyID = 0; + OGLRef.texGFogAttrID = 0; + OGLRef.texGDepthStencilID = 0; this->isFBOSupported = false; } @@ -1099,9 +1123,9 @@ void OpenGLRenderer_3_2::ResizeMultisampledFBOs(GLsizei numSamples) GLsizei w = (GLsizei)this->_framebufferWidth; GLsizei h = (GLsizei)this->_framebufferHeight; - if ( !this->isMultisampledFBOSupported || - (numSamples == 1) || - (w < GPU_FRAMEBUFFER_NATIVE_WIDTH) || (h < GPU_FRAMEBUFFER_NATIVE_HEIGHT) ) + if (!this->isMultisampledFBOSupported || + (numSamples == 1) || + (w < GPU_FRAMEBUFFER_NATIVE_WIDTH) || (h < GPU_FRAMEBUFFER_NATIVE_HEIGHT) ) { return; } @@ -1113,6 +1137,7 @@ void OpenGLRenderer_3_2::ResizeMultisampledFBOs(GLsizei numSamples) numSamples = 2; } +#ifdef GL_VERSION_3_2 if (this->willUsePerSampleZeroDstPass) { glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); @@ -1122,6 +1147,7 @@ void OpenGLRenderer_3_2::ResizeMultisampledFBOs(GLsizei numSamples) glActiveTexture(GL_TEXTURE0); } else +#endif { glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA, w, h); @@ -1250,12 +1276,12 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() glGenTextures(1, &OGLRef.texFogDensityTableID); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); - glBindTexture(GL_TEXTURE_1D, OGLRef.texFogDensityTableID); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage1D(GL_TEXTURE_1D, 0, GL_R8, 32, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, OGLRef.texFogDensityTableID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 1, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); OGLGeometryFlags programFlags; @@ -1266,10 +1292,28 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() { vtxShaderHeader << "#version 400\n"; } + else if (this->_isShaderFixedLocationSupported) + { + vtxShaderHeader << "#version 330\n"; + } else { vtxShaderHeader << "#version 150\n"; } + + vtxShaderHeader << "\n"; + if (this->_isShaderFixedLocationSupported) + { + vtxShaderHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vtxShaderHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vtxShaderHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + } + else + { + vtxShaderHeader << "#define IN_VTX_POSITION in\n"; + vtxShaderHeader << "#define IN_VTX_TEXCOORD0 in\n"; + vtxShaderHeader << "#define IN_VTX_COLOR in\n"; + } vtxShaderHeader << "\n"; vtxShaderHeader << "#define IS_USING_UBO_POLY_STATES " << ((OGLRef.uboPolyStatesID != 0) ? 1 : 0) << "\n"; vtxShaderHeader << "#define IS_USING_TBO_POLY_STATES " << ((OGLRef.tboPolyStatesID != 0) ? 1 : 0) << "\n"; @@ -1287,6 +1331,10 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() // seem to have problems with GL_ARB_conservative_depth. fragShaderHeader << ((this->_isConservativeDepthAMDSupported) ? "#extension GL_AMD_conservative_depth : require\n" : "#extension GL_ARB_conservative_depth : require\n"); } + else if (this->_isShaderFixedLocationSupported) + { + fragShaderHeader << "#version 330\n"; + } else { fragShaderHeader << "#version 150\n"; @@ -1297,6 +1345,21 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() for (size_t flagsValue = 0; flagsValue < 128; flagsValue++, programFlags.value++) { std::stringstream shaderFlags; + if (this->_isShaderFixedLocationSupported) + { + shaderFlags << "#define OUT_COLOR layout (location = 0) out\n"; + shaderFlags << "#define OUT_WORKING_BUFFER layout (location = " << GeometryAttachmentWorkingBuffer[programFlags.DrawBuffersMode] << ") out\n"; + shaderFlags << "#define OUT_POLY_ID layout (location = " << GeometryAttachmentPolyID[programFlags.DrawBuffersMode] << ") out\n"; + shaderFlags << "#define OUT_FOG_ATTRIBUTES layout (location = " << GeometryAttachmentFogAttributes[programFlags.DrawBuffersMode] << ") out\n"; + } + else + { + shaderFlags << "#define OUT_COLOR out\n"; + shaderFlags << "#define OUT_WORKING_BUFFER out\n"; + shaderFlags << "#define OUT_POLY_ID out\n"; + shaderFlags << "#define OUT_FOG_ATTRIBUTES out\n"; + } + shaderFlags << "\n"; shaderFlags << "#define USE_TEXTURE_SMOOTHING " << ((this->_enableTextureSmoothing) ? 1 : 0) << "\n"; shaderFlags << "#define USE_NDS_DEPTH_CALCULATION " << ((this->_emulateNDSDepthCalculation) ? 1 : 0) << "\n"; shaderFlags << "#define USE_DEPTH_LEQUAL_POLYGON_FACING " << ((this->_emulateDepthLEqualPolygonFacing) ? 1 : 0) << "\n"; @@ -1325,25 +1388,30 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() return error; } - glBindAttribLocation(OGLRef.programGeometryID[flagsValue], OGLVertexAttributeID_Position, "inPosition"); - glBindAttribLocation(OGLRef.programGeometryID[flagsValue], OGLVertexAttributeID_TexCoord0, "inTexCoord0"); - glBindAttribLocation(OGLRef.programGeometryID[flagsValue], OGLVertexAttributeID_Color, "inColor"); - glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], 0, "outFragColor"); - - if (programFlags.EnableFog) +#if defined(GL_VERSION_3_0) + if (!this->_isShaderFixedLocationSupported) { - glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentFogAttributes[programFlags.DrawBuffersMode], "outFogAttributes"); - } - - if (programFlags.EnableEdgeMark) - { - glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentPolyID[programFlags.DrawBuffersMode], "outPolyID"); - } - - if (programFlags.OpaqueDrawMode) - { - glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentWorkingBuffer[programFlags.DrawBuffersMode], "outDstBackFacing"); + glBindAttribLocation(OGLRef.programGeometryID[flagsValue], OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(OGLRef.programGeometryID[flagsValue], OGLVertexAttributeID_TexCoord0, "inTexCoord0"); + glBindAttribLocation(OGLRef.programGeometryID[flagsValue], OGLVertexAttributeID_Color, "inColor"); + glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], 0, "outFragColor"); + + if (programFlags.EnableFog) + { + glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentFogAttributes[programFlags.DrawBuffersMode], "outFogAttributes"); + } + + if (programFlags.EnableEdgeMark) + { + glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentPolyID[programFlags.DrawBuffersMode], "outPolyID"); + } + + if (programFlags.OpaqueDrawMode) + { + glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentWorkingBuffer[programFlags.DrawBuffersMode], "outDstBackFacing"); + } } +#endif glLinkProgram(OGLRef.programGeometryID[flagsValue]); if (!this->ValidateShaderProgramLink(OGLRef.programGeometryID[flagsValue])) @@ -1409,10 +1477,12 @@ void OpenGLRenderer_3_2::DestroyGeometryPrograms() glDeleteBuffers(1, &OGLRef.uboRenderStatesID); glDeleteBuffers(1, &OGLRef.uboPolyStatesID); glDeleteBuffers(1, &OGLRef.tboPolyStatesID); + glDeleteTextures(1, &OGLRef.texPolyStatesID); OGLRef.uboRenderStatesID = 0; OGLRef.uboPolyStatesID = 0; OGLRef.tboPolyStatesID = 0; + OGLRef.texPolyStatesID = 0; OpenGLRenderer_2_1::DestroyGeometryPrograms(); } @@ -1428,10 +1498,31 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryZeroDstAlphaProgram(const char * } std::stringstream shaderHeader; - shaderHeader << "#version 150\n"; + if (this->_isShaderFixedLocationSupported) + { + shaderHeader << "#version 330\n"; + } + else + { + shaderHeader << "#version 150\n"; + } shaderHeader << "\n"; - std::string vtxShaderCode = shaderHeader.str() + std::string(vtxShaderCString); + std::stringstream vsHeader; + if (this->_isShaderFixedLocationSupported) + { + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + } + else + { + vsHeader << "#define IN_VTX_POSITION in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 in\n"; + vsHeader << "#define IN_VTX_COLOR in\n"; + } + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); std::string fragShaderCode = shaderHeader.str() + std::string(fragShaderCString); error = this->ShaderProgramCreate(OGLRef.vtxShaderGeometryZeroDstAlphaID, @@ -1447,7 +1538,12 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryZeroDstAlphaProgram(const char * return error; } - glBindAttribLocation(OGLRef.programGeometryZeroDstAlphaID, OGLVertexAttributeID_Position, "inPosition"); +#if defined(GL_VERSION_3_0) + if (!this->_isShaderFixedLocationSupported) + { + glBindAttribLocation(OGLRef.programGeometryZeroDstAlphaID, OGLVertexAttributeID_Position, "inPosition"); + } +#endif glLinkProgram(OGLRef.programGeometryZeroDstAlphaID); if (!this->ValidateShaderProgramLink(OGLRef.programGeometryZeroDstAlphaID)) @@ -1478,11 +1574,32 @@ Render3DError OpenGLRenderer_3_2::CreateMSGeometryZeroDstAlphaProgram(const char } std::stringstream shaderHeader; - shaderHeader << "#version 150\n"; + if (this->_isShaderFixedLocationSupported) + { + shaderHeader << "#version 330\n"; + } + else + { + shaderHeader << "#version 150\n"; + } shaderHeader << "#extension GL_ARB_sample_shading : require\n"; shaderHeader << "\n"; - std::string vtxShaderCode = shaderHeader.str() + std::string(vtxShaderCString); + std::stringstream vsHeader; + if (this->_isShaderFixedLocationSupported) + { + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + } + else + { + vsHeader << "#define IN_VTX_POSITION in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 in\n"; + vsHeader << "#define IN_VTX_COLOR in\n"; + } + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); std::string fragShaderCode = shaderHeader.str() + std::string(fragShaderCString); error = this->ShaderProgramCreate(OGLRef.vtxShaderMSGeometryZeroDstAlphaID, @@ -1498,7 +1615,12 @@ Render3DError OpenGLRenderer_3_2::CreateMSGeometryZeroDstAlphaProgram(const char return error; } - glBindAttribLocation(OGLRef.programMSGeometryZeroDstAlphaID, OGLVertexAttributeID_Position, "inPosition"); +#if defined(GL_VERSION_3_0) + if (!this->_isShaderFixedLocationSupported) + { + glBindAttribLocation(OGLRef.programMSGeometryZeroDstAlphaID, OGLVertexAttributeID_Position, "inPosition"); + } +#endif glLinkProgram(OGLRef.programMSGeometryZeroDstAlphaID); if (!this->ValidateShaderProgramLink(OGLRef.programMSGeometryZeroDstAlphaID)) @@ -1549,13 +1671,45 @@ Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const char *vtxShaderCSt } std::stringstream shaderHeader; - shaderHeader << "#version 150\n"; + if (this->_isShaderFixedLocationSupported) + { + shaderHeader << "#version 330\n"; + } + else + { + shaderHeader << "#version 150\n"; + } + shaderHeader << "\n"; shaderHeader << "#define FRAMEBUFFER_SIZE_X " << this->_framebufferWidth << ".0 \n"; shaderHeader << "#define FRAMEBUFFER_SIZE_Y " << this->_framebufferHeight << ".0 \n"; shaderHeader << "\n"; - std::string vtxShaderCode = shaderHeader.str() + std::string(vtxShaderCString); - std::string fragShaderCode = shaderHeader.str() + std::string(fragShaderCString); + std::stringstream vsHeader; + if (this->_isShaderFixedLocationSupported) + { + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + } + else + { + vsHeader << "#define IN_VTX_POSITION in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 in\n"; + vsHeader << "#define IN_VTX_COLOR in\n"; + } + + std::stringstream fsHeader; + if (this->_isShaderFixedLocationSupported) + { + fsHeader << "#define OUT_COLOR layout (location = 0) out\n"; + } + else + { + fsHeader << "#define OUT_COLOR out\n"; + } + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); + std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + std::string(fragShaderCString); error = this->ShaderProgramCreate(OGLRef.vertexEdgeMarkShaderID, OGLRef.fragmentEdgeMarkShaderID, @@ -1570,9 +1724,14 @@ Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const char *vtxShaderCSt return error; } - glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_Position, "inPosition"); - glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); - glBindFragDataLocation(OGLRef.programEdgeMarkID, 0, "outEdgeColor"); +#if defined(GL_VERSION_3_0) + if (!this->_isShaderFixedLocationSupported) + { + glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); + glBindFragDataLocation(OGLRef.programEdgeMarkID, 0, "outEdgeColor"); + } +#endif glLinkProgram(OGLRef.programEdgeMarkID); if (!this->ValidateShaderProgramLink(OGLRef.programEdgeMarkID)) @@ -1620,18 +1779,53 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro const s32 fogStep = 0x0400 >> fogProgramKey.shift; std::stringstream shaderHeader; - shaderHeader << "#version 150\n"; - shaderHeader << "#define USE_DUAL_SOURCE_BLENDING " << ((this->_isDualSourceBlendingSupported) ? 1 : 0) << "\n"; + if (this->_isShaderFixedLocationSupported) + { + shaderHeader << "#version 330\n"; + } + else + { + shaderHeader << "#version 150\n"; + } shaderHeader << "\n"; - std::stringstream fragDepthConstants; - fragDepthConstants << "#define FOG_OFFSET " << fogOffset << "\n"; - fragDepthConstants << "#define FOG_OFFSETF " << fogOffsetf << (((fogOffsetf == 0.0f) || (fogOffsetf == 1.0f)) ? ".0" : "") << "\n"; - fragDepthConstants << "#define FOG_STEP " << fogStep << "\n"; - fragDepthConstants << "\n"; + std::stringstream vsHeader; + if (this->_isShaderFixedLocationSupported) + { + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + } + else + { + vsHeader << "#define IN_VTX_POSITION in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 in\n"; + vsHeader << "#define IN_VTX_COLOR in\n"; + } - std::string vtxShaderCode = shaderHeader.str() + std::string(vtxShaderCString); - std::string fragShaderCode = shaderHeader.str() + fragDepthConstants.str() + std::string(fragShaderCString); + std::stringstream fsHeader; + fsHeader << "#define USE_DUAL_SOURCE_BLENDING " << ((this->_isDualSourceBlendingSupported) ? 1 : 0) << "\n"; + fsHeader << "\n"; + fsHeader << "#define FOG_OFFSET " << fogOffset << "\n"; + fsHeader << "#define FOG_OFFSETF " << fogOffsetf << (((fogOffsetf == 0.0f) || (fogOffsetf == 1.0f)) ? ".0" : "") << "\n"; + fsHeader << "#define FOG_STEP " << fogStep << "\n"; + fsHeader << "\n"; + + if (this->_isShaderFixedLocationSupported) + { + fsHeader << "#define OUT_FOG_COLOR layout (location = 0, index = 0) out\n"; + fsHeader << "#define OUT_FOG_WEIGHT layout (location = 0, index = 1) out\n"; + fsHeader << "#define OUT_COLOR layout (location = 0) out\n"; + } + else + { + fsHeader << "#define OUT_FOG_COLOR out\n"; + fsHeader << "#define OUT_FOG_WEIGHT out\n"; + fsHeader << "#define OUT_COLOR out\n"; + } + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); + std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + std::string(fragShaderCString); OGLFogShaderID shaderID; shaderID.program = 0; @@ -1653,19 +1847,24 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro return error; } - glBindAttribLocation(shaderID.program, OGLVertexAttributeID_Position, "inPosition"); +#if defined(GL_VERSION_3_0) + if (!this->_isShaderFixedLocationSupported) + { + glBindAttribLocation(shaderID.program, OGLVertexAttributeID_Position, "inPosition"); #ifdef GL_VERSION_3_3 - if (this->_isDualSourceBlendingSupported) - { - glBindFragDataLocationIndexed(shaderID.program, 0, 0, "outFogColor"); - glBindFragDataLocationIndexed(shaderID.program, 0, 1, "outFogWeight"); - } - else + if (this->_isDualSourceBlendingSupported) + { + glBindFragDataLocationIndexed(shaderID.program, 0, 0, "outFogColor"); + glBindFragDataLocationIndexed(shaderID.program, 0, 1, "outFogWeight"); + } + else #endif - { - glBindFragDataLocation(shaderID.program, 0, "outFragColor"); + { + glBindFragDataLocation(shaderID.program, 0, "outFragColor"); + } } +#endif glLinkProgram(shaderID.program); if (!this->ValidateShaderProgramLink(shaderID.program)) @@ -1691,7 +1890,7 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro if (!this->_isDualSourceBlendingSupported) { - const GLint uniformTexGColor = glGetUniformLocation(shaderID.program, "texInFragColor"); + const GLint uniformTexGColor = glGetUniformLocation(shaderID.program, "texInFragColor"); glUniform1i(uniformTexGColor, OGLTextureUnitID_GColor); } @@ -1709,13 +1908,45 @@ Render3DError OpenGLRenderer_3_2::CreateFramebufferOutput6665Program(const size_ } std::stringstream shaderHeader; - shaderHeader << "#version 150\n"; + if (this->_isShaderFixedLocationSupported) + { + shaderHeader << "#version 330\n"; + } + else + { + shaderHeader << "#version 150\n"; + } + shaderHeader << "\n"; shaderHeader << "#define FRAMEBUFFER_SIZE_X " << this->_framebufferWidth << ".0 \n"; shaderHeader << "#define FRAMEBUFFER_SIZE_Y " << this->_framebufferHeight << ".0 \n"; shaderHeader << "\n"; - std::string vtxShaderCode = shaderHeader.str() + std::string(vtxShaderCString); - std::string fragShaderCode = shaderHeader.str() + std::string(fragShaderCString); + std::stringstream vsHeader; + if (this->_isShaderFixedLocationSupported) + { + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + } + else + { + vsHeader << "#define IN_VTX_POSITION in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 in\n"; + vsHeader << "#define IN_VTX_COLOR in\n"; + } + + std::stringstream fsHeader; + if (this->_isShaderFixedLocationSupported) + { + fsHeader << "#define OUT_COLOR layout (location = 0) out\n"; + } + else + { + fsHeader << "#define OUT_COLOR out\n"; + } + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); + std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + std::string(fragShaderCString); error = this->ShaderProgramCreate(OGLRef.vertexFramebufferOutput6665ShaderID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID, @@ -1730,8 +1961,13 @@ Render3DError OpenGLRenderer_3_2::CreateFramebufferOutput6665Program(const size_ return error; } - glBindAttribLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], OGLVertexAttributeID_Position, "inPosition"); - glBindFragDataLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], 0, "outFragColor6665"); +#if defined(GL_VERSION_3_0) + if (!this->_isShaderFixedLocationSupported) + { + glBindAttribLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], OGLVertexAttributeID_Position, "inPosition"); + glBindFragDataLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], 0, "outFragColor6665"); + } +#endif glLinkProgram(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex]); if (!this->ValidateShaderProgramLink(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex])) @@ -1783,24 +2019,6 @@ void OpenGLRenderer_3_2::GetExtensionSet(std::set *oglExtensionSet) } } -Render3DError OpenGLRenderer_3_2::InitFinalRenderStates(const std::set *oglExtensionSet) -{ - Render3DError error = OpenGLRenderer_2_1::InitFinalRenderStates(oglExtensionSet); - if (error != OGLERROR_NOERR) - { - return error; - } - -#ifdef GL_VERSION_3_3 - if (this->_isDualSourceBlendingSupported) - { - INITOGLEXT(PFNGLBINDFRAGDATALOCATIONINDEXEDPROC, glBindFragDataLocationIndexed) - } -#endif - - return error; -} - void OpenGLRenderer_3_2::_SetupGeometryShaders(const OGLGeometryFlags flags) { const OGLRenderRef &OGLRef = *this->ref; @@ -2160,7 +2378,7 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co } glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RED, GL_UNSIGNED_BYTE, fogDensityTable); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 32, 1, GL_RED, GL_UNSIGNED_BYTE, fogDensityTable); } if (this->_enableEdgeMark) diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 6f05c466b..81e258fb0 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -32,6 +32,7 @@ class OpenGLRenderer_3_2 : public OpenGLRenderer_2_1 protected: bool _is64kUBOSupported; bool _isTBOSupported; + bool _isShaderFixedLocationSupported; bool _isDualSourceBlendingSupported; bool _isSampleShadingSupported; bool _isConservativeDepthSupported; @@ -60,7 +61,6 @@ protected: virtual Render3DError CreateFramebufferOutput8888Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); virtual void GetExtensionSet(std::set *oglExtensionSet); - virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); virtual void _SetupGeometryShaders(const OGLGeometryFlags flags); virtual Render3DError EnableVertexAttributes(); virtual Render3DError DisableVertexAttributes(); @@ -77,7 +77,6 @@ protected: virtual void SetPolygonIndex(const size_t index); virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing); virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); - virtual Render3DError SetFramebufferSize(size_t w, size_t h); public: OpenGLRenderer_3_2(); @@ -86,6 +85,7 @@ public: virtual Render3DError InitExtensions(); virtual Render3DError RenderFinish(); virtual Render3DError RenderPowerOff(); + virtual Render3DError SetFramebufferSize(size_t w, size_t h); }; #endif From 0e88f9aa94e4ee6a9ffdb190e4381e133ef97fcd Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 9 Jul 2024 22:03:33 -0700 Subject: [PATCH 45/49] OpenGL Renderer: Final changes for OpenGL ES compatibility. --- desmume/src/OGLRender.h | 4 +- desmume/src/OGLRender_3_2.cpp | 109 +++++++++++++++++----------------- desmume/src/OGLRender_3_2.h | 12 ++++ 3 files changed, 70 insertions(+), 55 deletions(-) diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index b86e34759..94243de01 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -266,7 +266,7 @@ EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) EXTERNOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) -#elif defined(GL_ARB_framebuffer_object) +#elif defined(GL_ARB_framebuffer_object) || defined(GL_ES_VERSION_3_0) // Most OpenGL variants don't have GL_EXT_framebuffer_object, so redeclare all the ARB versions // to their EXT versions to avoid compile time errors in OGLRender.cpp. // @@ -318,6 +318,7 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) #ifndef GL_VERSION_1_2 // These legacy functions can be promoted to later core equivalents without any further // modification. In other words, these are one-to-one drop-in replacements. + typedef GLclampf GLclampd; #define glClearDepth(depth) glClearDepthf(depth) #define glDrawBuffer(x) glDrawBuffers(1, ((GLenum[]){x})) @@ -689,6 +690,7 @@ class OpenGLRenderer; extern GPU3DInterface gpu3Dgl; extern GPU3DInterface gpu3DglOld; extern GPU3DInterface gpu3Dgl_3_2; +extern GPU3DInterface gpu3Dgl_ES_3_0; extern const GLenum GeometryDrawBuffersEnum[8][4]; extern const GLint GeometryAttachmentWorkingBuffer[8]; diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 31d9084cf..490c1fdce 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -139,7 +139,7 @@ void OGLLoadEntryPoints_3_2() } // Vertex shader for geometry, GLSL 1.50 -static const char *GeometryVtxShader_150 = {"\ +const char *GeometryVtxShader_150 = {"\ IN_VTX_POSITION vec4 inPosition;\n\ IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ IN_VTX_COLOR vec3 inColor; \n\ @@ -206,7 +206,7 @@ void main()\n\ "}; // Fragment shader for geometry, GLSL 1.50 -static const char *GeometryFragShader_150 = {"\ +const char *GeometryFragShader_150 = {"\ in vec2 vtxTexCoord;\n\ in vec4 vtxColor;\n\ flat in int polyEnableTexture;\n\ @@ -354,7 +354,7 @@ void main()\n\ "}; // Vertex shader for determining which pixels have a zero alpha, GLSL 1.50 -static const char *GeometryZeroDstAlphaPixelMaskVtxShader_150 = {"\ +const char *GeometryZeroDstAlphaPixelMaskVtxShader_150 = {"\ IN_VTX_POSITION vec2 inPosition;\n\ \n\ void main()\n\ @@ -364,7 +364,7 @@ void main()\n\ "}; // Fragment shader for determining which pixels have a zero alpha, GLSL 1.50 -static const char *GeometryZeroDstAlphaPixelMaskFragShader_150 = {"\ +const char *GeometryZeroDstAlphaPixelMaskFragShader_150 = {"\ uniform sampler2D texInFragColor;\n\ \n\ void main()\n\ @@ -379,7 +379,7 @@ void main()\n\ "}; // Fragment shader for determining which pixels have a zero alpha, GLSL 1.50 -static const char *MSGeometryZeroDstAlphaPixelMaskFragShader_150 = {"\ +const char *MSGeometryZeroDstAlphaPixelMaskFragShader_150 = {"\ uniform sampler2DMS texInFragColor;\n\ \n\ void main()\n\ @@ -394,7 +394,7 @@ void main()\n\ "}; // Vertex shader for applying edge marking, GLSL 1.50 -static const char *EdgeMarkVtxShader_150 = {"\ +const char *EdgeMarkVtxShader_150 = {"\ IN_VTX_POSITION vec2 inPosition;\n\ IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ \n\ @@ -415,7 +415,7 @@ void main()\n\ "}; // Fragment shader for applying edge marking, GLSL 1.50 -static const char *EdgeMarkFragShader_150 = {"\ +const char *EdgeMarkFragShader_150 = {"\ in vec2 texCoord[5];\n\ \n\ layout (std140) uniform RenderStates\n\ @@ -524,7 +524,7 @@ void main()\n\ "}; // Vertex shader for applying fog, GLSL 1.50 -static const char *FogVtxShader_150 = {"\ +const char *FogVtxShader_150 = {"\ IN_VTX_POSITION vec2 inPosition;\n\ \n\ void main()\n\ @@ -534,7 +534,7 @@ void main()\n\ "}; // Fragment shader for applying fog, GLSL 1.50 -static const char *FogFragShader_150 = {"\ +const char *FogFragShader_150 = {"\ layout (std140) uniform RenderStates\n\ {\n\ bool enableAntialiasing;\n\ @@ -598,7 +598,7 @@ void main()\n\ "}; // Vertex shader for the final framebuffer, GLSL 1.50 -static const char *FramebufferOutputVtxShader_150 = {"\ +const char *FramebufferOutputVtxShader_150 = {"\ IN_VTX_POSITION vec2 inPosition;\n\ \n\ void main()\n\ @@ -608,7 +608,7 @@ void main()\n\ "}; // Fragment shader for the final RGBA6665 formatted framebuffer, GLSL 1.50 -static const char *FramebufferOutput6665FragShader_150 = {"\ +const char *FramebufferOutput6665FragShader_150 = {"\ uniform sampler2D texInFragColor;\n\ \n\ OUT_COLOR vec4 outFragColor6665;\n\ @@ -1012,6 +1012,7 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) glGenRenderbuffers(1, &OGLRef.rboMSGFogAttrID); glGenRenderbuffers(1, &OGLRef.rboMSGDepthStencilID); +#ifdef GL_VERSION_3_2 if (this->willUsePerSampleZeroDstPass) { glGenTextures(1, &OGLRef.texMSGColorID); @@ -1036,6 +1037,7 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) glActiveTexture(GL_TEXTURE0); } else +#endif { glGenRenderbuffers(1, &OGLRef.rboMSGColorID); glGenRenderbuffers(1, &OGLRef.rboMSGWorkingID); @@ -1057,12 +1059,14 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) glGenFramebuffers(1, &OGLRef.fboMSIntermediateRenderID); glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); +#ifdef GL_VERSION_3_2 if (this->willUsePerSampleZeroDstPass) { glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGWorkingID, 0); } else +#endif { glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGColorID); glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); @@ -1239,6 +1243,7 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() glBindBufferBase(GL_UNIFORM_BUFFER, OGLBindingPointID_PolyStates, OGLRef.uboPolyStatesID); } } +#if defined(GL_VERSION_3_1) || defined(GL_ES_VERSION_3_2) else if (this->_isTBOSupported) { // Older GPUs that support 3.2 Core Profile but not 64k UBOs can transfer the polygon @@ -1258,6 +1263,7 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() glActiveTexture(GL_TEXTURE0); } } +#endif else { // For compatibility reasons, we can transfer the polygon states through a plain old @@ -1287,60 +1293,49 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() OGLGeometryFlags programFlags; programFlags.value = 0; - std::stringstream vtxShaderHeader; + std::stringstream shaderHeader; if (this->_isConservativeDepthSupported || this->_isConservativeDepthAMDSupported) { - vtxShaderHeader << "#version 400\n"; - } - else if (this->_isShaderFixedLocationSupported) - { - vtxShaderHeader << "#version 330\n"; - } - else - { - vtxShaderHeader << "#version 150\n"; - } - - vtxShaderHeader << "\n"; - if (this->_isShaderFixedLocationSupported) - { - vtxShaderHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; - vtxShaderHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; - vtxShaderHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; - } - else - { - vtxShaderHeader << "#define IN_VTX_POSITION in\n"; - vtxShaderHeader << "#define IN_VTX_TEXCOORD0 in\n"; - vtxShaderHeader << "#define IN_VTX_COLOR in\n"; - } - vtxShaderHeader << "\n"; - vtxShaderHeader << "#define IS_USING_UBO_POLY_STATES " << ((OGLRef.uboPolyStatesID != 0) ? 1 : 0) << "\n"; - vtxShaderHeader << "#define IS_USING_TBO_POLY_STATES " << ((OGLRef.tboPolyStatesID != 0) ? 1 : 0) << "\n"; - vtxShaderHeader << "#define DEPTH_EQUALS_TEST_TOLERANCE " << DEPTH_EQUALS_TEST_TOLERANCE << ".0\n"; - vtxShaderHeader << "\n"; - - std::string vtxShaderCode = vtxShaderHeader.str() + std::string(GeometryVtxShader_150); - - std::stringstream fragShaderHeader; - if (this->_isConservativeDepthSupported || this->_isConservativeDepthAMDSupported) - { - fragShaderHeader << "#version 400\n"; + shaderHeader << "#version 400\n"; // Prioritize using GL_AMD_conservative_depth over GL_ARB_conservative_depth, since AMD drivers // seem to have problems with GL_ARB_conservative_depth. - fragShaderHeader << ((this->_isConservativeDepthAMDSupported) ? "#extension GL_AMD_conservative_depth : require\n" : "#extension GL_ARB_conservative_depth : require\n"); + shaderHeader << ((this->_isConservativeDepthAMDSupported) ? "#extension GL_AMD_conservative_depth : require\n" : "#extension GL_ARB_conservative_depth : require\n"); } else if (this->_isShaderFixedLocationSupported) { - fragShaderHeader << "#version 330\n"; + shaderHeader << "#version 330\n"; } else { - fragShaderHeader << "#version 150\n"; + shaderHeader << "#version 150\n"; } - fragShaderHeader << "#define IS_CONSERVATIVE_DEPTH_SUPPORTED " << ((this->_isConservativeDepthSupported || this->_isConservativeDepthAMDSupported) ? 1 : 0) << "\n"; - fragShaderHeader << "\n"; + shaderHeader << "\n"; + + std::stringstream vsHeader; + if (this->_isShaderFixedLocationSupported) + { + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + } + else + { + vsHeader << "#define IN_VTX_POSITION in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 in\n"; + vsHeader << "#define IN_VTX_COLOR in\n"; + } + vsHeader << "\n"; + vsHeader << "#define IS_USING_UBO_POLY_STATES " << ((OGLRef.uboPolyStatesID != 0) ? 1 : 0) << "\n"; + vsHeader << "#define IS_USING_TBO_POLY_STATES " << ((OGLRef.tboPolyStatesID != 0) ? 1 : 0) << "\n"; + vsHeader << "#define DEPTH_EQUALS_TEST_TOLERANCE " << DEPTH_EQUALS_TEST_TOLERANCE << ".0\n"; + vsHeader << "\n"; + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(GeometryVtxShader_150); + + std::stringstream fsHeader; + fsHeader << "#define IS_CONSERVATIVE_DEPTH_SUPPORTED " << ((this->_isConservativeDepthSupported || this->_isConservativeDepthAMDSupported) ? 1 : 0) << "\n"; + fsHeader << "\n"; for (size_t flagsValue = 0; flagsValue < 128; flagsValue++, programFlags.value++) { @@ -1373,7 +1368,7 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() shaderFlags << "#define DRAW_MODE_OPAQUE " << ((programFlags.OpaqueDrawMode) ? 1 : 0) << "\n"; shaderFlags << "\n"; - std::string fragShaderCode = fragShaderHeader.str() + shaderFlags.str() + std::string(GeometryFragShader_150); + std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + shaderFlags.str() + std::string(GeometryFragShader_150); error = this->ShaderProgramCreate(OGLRef.vertexGeometryShaderID, OGLRef.fragmentGeometryShaderID[flagsValue], @@ -1473,7 +1468,9 @@ void OpenGLRenderer_3_2::DestroyGeometryPrograms() OGLRenderRef &OGLRef = *this->ref; glBindBuffer(GL_UNIFORM_BUFFER, 0); +#if defined(GL_VERSION_3_1) || defined(GL_ES_VERSION_3_2) glBindBuffer(GL_TEXTURE_BUFFER, 0); +#endif glDeleteBuffers(1, &OGLRef.uboRenderStatesID); glDeleteBuffers(1, &OGLRef.uboPolyStatesID); glDeleteBuffers(1, &OGLRef.tboPolyStatesID); @@ -2398,6 +2395,7 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co OGLPolyStates *polyStates = this->_pendingPolyStates; +#if defined(GL_VERSION_3_1) || defined(GL_ES_VERSION_3_2) if (OGLRef.tboPolyStatesID != 0) { // Some drivers seem to have problems with GL_TEXTURE_BUFFER used as the target for @@ -2406,6 +2404,7 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co // to prevent these glitches from happening. polyStates = (OGLPolyStates *)glMapBuffer(GL_TEXTURE_BUFFER, GL_WRITE_ONLY); } +#endif for (size_t i = 0; i < this->_clippedPolyCount; i++) { @@ -2437,10 +2436,12 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboPolyStatesID); glBufferSubData(GL_UNIFORM_BUFFER, 0, MAX_CLIPPED_POLY_COUNT_FOR_UBO * sizeof(OGLPolyStates), this->_pendingPolyStates); } +#if defined(GL_VERSION_3_1) || defined(GL_ES_VERSION_3_2) else if (OGLRef.tboPolyStatesID != 0) { glUnmapBuffer(GL_TEXTURE_BUFFER); } +#endif else { const GLsizei texH = (GLsizei)((this->_clippedPolyCount >> 8) & 0x007F) + 1; diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 81e258fb0..4c3384a82 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -24,6 +24,18 @@ #define MAX_CLIPPED_POLY_COUNT_FOR_UBO 16384 +extern const char *GeometryVtxShader_150; +extern const char *GeometryFragShader_150; +extern const char *GeometryZeroDstAlphaPixelMaskVtxShader_150; +extern const char *GeometryZeroDstAlphaPixelMaskFragShader_150; +extern const char *MSGeometryZeroDstAlphaPixelMaskFragShader_150; +extern const char *EdgeMarkVtxShader_150; +extern const char *EdgeMarkFragShader_150; +extern const char *FogVtxShader_150; +extern const char *FogFragShader_150; +extern const char *FramebufferOutputVtxShader_150; +extern const char *FramebufferOutput6665FragShader_150; + void OGLLoadEntryPoints_3_2(); void OGLCreateRenderer_3_2(OpenGLRenderer **rendererPtr); From 3a6f2f6dc51918a521968c98c50c4f22333c7820 Mon Sep 17 00:00:00 2001 From: rogerman Date: Tue, 9 Jul 2024 23:00:27 -0700 Subject: [PATCH 46/49] OpenGL ES Renderer: Add a new OpenGL ES 3.0 renderer. --- desmume/src/OGLRender_3_2.h | 19 + desmume/src/OGLRender_ES3.cpp | 889 ++++++++++++++++++++++++++++++++++ desmume/src/OGLRender_ES3.h | 58 +++ 3 files changed, 966 insertions(+) create mode 100644 desmume/src/OGLRender_ES3.cpp create mode 100644 desmume/src/OGLRender_ES3.h diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 4c3384a82..700b9497c 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -36,6 +36,25 @@ extern const char *FogFragShader_150; extern const char *FramebufferOutputVtxShader_150; extern const char *FramebufferOutput6665FragShader_150; +// A port that wants to use the OpenGL 3.2 renderer must assign the two following functions +// to OGLLoadEntryPoints_3_2_Func and OGLCreateRenderer_3_2_Func, respectively. +// +// In addition, the port must add the following GPU3DInterface objects to core3DList: +// - gpu3Dgl: Automatically selects the most fully featured version of standard OpenGL that +// is available on the host system, prefering OpenGL 3.2 Core Profile. +// - gpu3Dgl_3_2: Selects the OpenGL 3.2 Core Profile renderer, and returns an error if it +// is not available on the host system. +// +// Finally, the port must call GPU->Set3DRendererByID() and pass in the index where +// gpu3Dgl_3_2 exists in core3DList so that the emulator can create the appropriate +// OpenGLRenderer object. +// +// Example code: +// OGLLoadEntryPoints_3_2_Func = &OGLLoadEntryPoints_3_2; +// OGLCreateRenderer_3_2_Func = &OGLCreateRenderer_3_2; +// GPU3DInterface *core3DList[] = { &gpu3DNull, &gpu3DRasterize, &gpu3Dgl_3_2, NULL }; +// GPU->Set3DRendererByID(2); + void OGLLoadEntryPoints_3_2(); void OGLCreateRenderer_3_2(OpenGLRenderer **rendererPtr); diff --git a/desmume/src/OGLRender_ES3.cpp b/desmume/src/OGLRender_ES3.cpp new file mode 100644 index 000000000..374518238 --- /dev/null +++ b/desmume/src/OGLRender_ES3.cpp @@ -0,0 +1,889 @@ +/* + Copyright (C) 2024 DeSmuME team + + This file 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 file 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 the this software. If not, see . +*/ + +#include "OGLRender_ES3.h" + +#include +#include +#include +#include +#include +#include + +#include "utils/bits.h" +#include "common.h" +#include "debug.h" +#include "NDSSystem.h" + + +// Vertex shader for geometry, GLSL ES 3.00 +static const char *GeometryVtxShader_ES300 = {"\ +IN_VTX_POSITION vec4 inPosition;\n\ +IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ +IN_VTX_COLOR vec3 inColor; \n\ +\n\ +#if IS_USING_UBO_POLY_STATES\n\ +layout (std140) uniform PolyStates\n\ +{\n\ + ivec4 value[4096];\n\ +} polyState;\n\ +#elif IS_USING_TBO_POLY_STATES\n\ +uniform highp isamplerBuffer PolyStates;\n\ +#else\n\ +uniform highp isampler2D PolyStates;\n\ +#endif\n\ +uniform mediump int polyIndex;\n\ +uniform bool polyDrawShadow;\n\ +\n\ +out vec2 vtxTexCoord;\n\ +out vec4 vtxColor;\n\ +flat out lowp int polyID;\n\ +flat out lowp int polyMode;\n\ +flat out lowp int polyIsWireframe;\n\ +flat out lowp int polyEnableFog;\n\ +flat out lowp int polySetNewDepthForTranslucent;\n\ +flat out lowp int polyEnableTexture;\n\ +flat out lowp int texSingleBitAlpha;\n\ +flat out lowp int polyIsBackFacing;\n\ +flat out lowp int isPolyDrawable;\n\ +\n\ +void main()\n\ +{\n\ +#if IS_USING_UBO_POLY_STATES\n\ + ivec4 polyStateVec = polyState.value[polyIndex >> 2];\n\ + int polyStateBits = polyStateVec[polyIndex & 0x03];\n\ +#elif IS_USING_TBO_POLY_STATES\n\ + int polyStateBits = texelFetch(PolyStates, polyIndex).r;\n\ +#else\n\ + int polyStateBits = texelFetch(PolyStates, ivec2(polyIndex & 0x00FF, (polyIndex >> 8) & 0x007F), 0).r;\n\ +#endif\n\ + int texSizeShiftS = (polyStateBits >> 18) & 0x07;\n\ + int texSizeShiftT = (polyStateBits >> 21) & 0x07;\n\ + \n\ + float polyAlpha = float((polyStateBits >> 8) & 0x1F) / 31.0;\n\ + vec2 polyTexScale = vec2(1.0 / float(8 << texSizeShiftS), 1.0 / float(8 << texSizeShiftT));\n\ + \n\ + polyID = (polyStateBits >> 0) & 0x3F;\n\ + polyMode = (polyStateBits >> 6) & 0x03;\n\ + polyIsWireframe = (polyStateBits >> 13) & 0x01;\n\ + polyEnableFog = (polyStateBits >> 14) & 0x01;\n\ + polySetNewDepthForTranslucent = (polyStateBits >> 15) & 0x01;\n\ + polyEnableTexture = (polyStateBits >> 16) & 0x01;\n\ + texSingleBitAlpha = (polyStateBits >> 17) & 0x01;\n\ + polyIsBackFacing = (polyStateBits >> 24) & 0x01;\n\ + \n\ + isPolyDrawable = int((polyMode != 3) || polyDrawShadow);\n\ + \n\ + mat2 texScaleMtx = mat2( vec2(polyTexScale.x, 0.0), \n\ + vec2( 0.0, polyTexScale.y)); \n\ + \n\ + vtxTexCoord = (texScaleMtx * inTexCoord0) / 16.0;\n\ + vtxColor = vec4(inColor / 63.0, polyAlpha);\n\ + gl_Position = inPosition / 4096.0;\n\ +}\n\ +"}; + +// Fragment shader for geometry, GLSL ES 3.00 +static const char *GeometryFragShader_ES300 = {"\ +in vec2 vtxTexCoord;\n\ +in vec4 vtxColor;\n\ +flat in lowp int polyID;\n\ +flat in lowp int polyMode;\n\ +flat in lowp int polyIsWireframe;\n\ +flat in lowp int polyEnableFog;\n\ +flat in lowp int polySetNewDepthForTranslucent;\n\ +flat in lowp int polyEnableTexture;\n\ +flat in lowp int texSingleBitAlpha;\n\ +flat in lowp int polyIsBackFacing;\n\ +flat in lowp int isPolyDrawable;\n\ +\n\ +layout (std140) uniform RenderStates\n\ +{\n\ + bool enableAntialiasing;\n\ + bool enableFogAlphaOnly;\n\ + int clearPolyID;\n\ + float clearDepth;\n\ + float alphaTestRef;\n\ + float fogOffset;\n\ + float fogStep;\n\ + float pad_0;\n\ + vec4 fogColor;\n\ + vec4 edgeColor[8];\n\ + vec4 toonColor[32];\n\ +} state;\n\ +\n\ +uniform sampler2D texRenderObject;\n\ +uniform bool texDrawOpaque;\n\ +uniform bool drawModeDepthEqualsTest;\n\ +uniform bool polyDrawShadow;\n\ +uniform float polyDepthOffset;\n\ +\n\ +OUT_COLOR vec4 outFragColor;\n\ +\n\ +#if DRAW_MODE_OPAQUE\n\ +OUT_WORKING_BUFFER vec4 outDstBackFacing;\n\ +#elif USE_DEPTH_LEQUAL_POLYGON_FACING\n\ +uniform sampler2D inDstBackFacing;\n\ +#endif\n\ +\n\ +#if ENABLE_EDGE_MARK\n\ +OUT_POLY_ID vec4 outPolyID;\n\ +#endif\n\ +#if ENABLE_FOG\n\ +OUT_FOG_ATTRIBUTES vec4 outFogAttributes;\n\ +#endif\n\ +\n\ +void main()\n\ +{\n\ +#if USE_DEPTH_LEQUAL_POLYGON_FACING && !DRAW_MODE_OPAQUE\n\ + bool isOpaqueDstBackFacing = bool( texelFetch(inDstBackFacing, ivec2(gl_FragCoord.xy), 0).r );\n\ + if ( drawModeDepthEqualsTest && (bool(polyIsBackFacing) || !isOpaqueDstBackFacing) )\n\ + {\n\ + discard;\n\ + }\n\ +#endif\n\ + \n\ + vec4 mainTexColor = (ENABLE_TEXTURE_SAMPLING && bool(polyEnableTexture)) ? texture(texRenderObject, vtxTexCoord) : vec4(1.0, 1.0, 1.0, 1.0);\n\ + \n\ + if (!bool(texSingleBitAlpha))\n\ + {\n\ + if (texDrawOpaque)\n\ + {\n\ + if ( (polyMode != 1) && (mainTexColor.a <= 0.999) )\n\ + {\n\ + discard;\n\ + }\n\ + }\n\ + else\n\ + {\n\ + if ( ((polyMode != 1) && (mainTexColor.a * vtxColor.a > 0.999)) || ((polyMode == 1) && (vtxColor.a > 0.999)) )\n\ + {\n\ + discard;\n\ + }\n\ + }\n\ + }\n\ +#if USE_TEXTURE_SMOOTHING\n\ + else\n\ + {\n\ + if (mainTexColor.a < 0.500)\n\ + {\n\ + mainTexColor.a = 0.0;\n\ + }\n\ + else\n\ + {\n\ + mainTexColor.rgb = mainTexColor.rgb / mainTexColor.a;\n\ + mainTexColor.a = 1.0;\n\ + }\n\ + }\n\ +#endif\n\ + \n\ + outFragColor = mainTexColor * vtxColor;\n\ + \n\ + if (polyMode == 1)\n\ + {\n\ + outFragColor.rgb = (ENABLE_TEXTURE_SAMPLING && bool(polyEnableTexture)) ? mix(vtxColor.rgb, mainTexColor.rgb, mainTexColor.a) : vtxColor.rgb;\n\ + outFragColor.a = vtxColor.a;\n\ + }\n\ + else if (polyMode == 2)\n\ + {\n\ + vec3 newToonColor = state.toonColor[int((vtxColor.r * 31.0) + 0.5)].rgb;\n\ +#if TOON_SHADING_MODE\n\ + outFragColor.rgb = min((mainTexColor.rgb * vtxColor.r) + newToonColor.rgb, 1.0);\n\ +#else\n\ + outFragColor.rgb = mainTexColor.rgb * newToonColor.rgb;\n\ +#endif\n\ + }\n\ + else if ((polyMode == 3) && polyDrawShadow)\n\ + {\n\ + outFragColor = vtxColor;\n\ + }\n\ + \n\ + if ( (isPolyDrawable != 0) && ((outFragColor.a < 0.001) || (ENABLE_ALPHA_TEST && outFragColor.a < state.alphaTestRef)) )\n\ + {\n\ + discard;\n\ + }\n\ +#if ENABLE_EDGE_MARK\n\ + outPolyID = (isPolyDrawable != 0) ? vec4( float(polyID)/63.0, float(polyIsWireframe == 1), 0.0, float(outFragColor.a > 0.999) ) : vec4(0.0, 0.0, 0.0, 0.0);\n\ +#endif\n\ +#if ENABLE_FOG\n\ + outFogAttributes = (isPolyDrawable != 0) ? vec4( float(polyEnableFog), 0.0, 0.0, float((outFragColor.a > 0.999) ? 1.0 : 0.5) ) : vec4(0.0, 0.0, 0.0, 0.0);\n\ +#endif\n\ +#if DRAW_MODE_OPAQUE\n\ + outDstBackFacing = vec4(float(polyIsBackFacing), 0.0, 0.0, 1.0);\n\ +#endif\n\ + \n\ +#if USE_NDS_DEPTH_CALCULATION || ENABLE_FOG\n\ + // It is tempting to perform the NDS depth calculation in the vertex shader rather than in the fragment shader.\n\ + // Resist this temptation! It is much more reliable to do the depth calculation in the fragment shader due to\n\ + // subtle interpolation differences between various GPUs and/or drivers. If the depth calculation is not done\n\ + // here, then it is very possible for the user to experience Z-fighting in certain rendering situations.\n\ + \n\ + #if ENABLE_W_DEPTH\n\ + gl_FragDepth = clamp( ((1.0/gl_FragCoord.w) * (4096.0/16777215.0)) + polyDepthOffset, 0.0, 1.0 );\n\ + #else\n\ + // hack: when using z-depth, drop some LSBs so that the overworld map in Dragon Quest IV shows up correctly\n\ + gl_FragDepth = clamp( (floor(gl_FragCoord.z * 4194303.0) * (4.0/16777215.0)) + polyDepthOffset, 0.0, 1.0 );\n\ + #endif\n\ +#endif\n\ +}\n\ +"}; + +void OGLLoadEntryPoints_ES_3_0() +{ + OGLLoadEntryPoints_3_2(); +} + +void OGLCreateRenderer_ES_3_0(OpenGLRenderer **rendererPtr) +{ + if (IsOpenGLDriverVersionSupported(3, 0, 0)) + { + *rendererPtr = new OpenGLESRenderer_3_0; + (*rendererPtr)->SetVersion(3, 0, 0); + } +} + +OpenGLESRenderer_3_0::OpenGLESRenderer_3_0() +{ + _variantID = OpenGLVariantID_ES_3_0; +} + +Render3DError OpenGLESRenderer_3_0::InitExtensions() +{ + OGLRenderRef &OGLRef = *this->ref; + Render3DError error = OGLERROR_NOERR; + + // Get OpenGL extensions + std::set oglExtensionSet; + this->GetExtensionSet(&oglExtensionSet); + + // Get host GPU device properties + GLint maxUBOSize = 0; + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUBOSize); + this->_is64kUBOSupported = (maxUBOSize >= 65536); + + // TBOs are only supported in ES 3.2. + this->_isTBOSupported = IsOpenGLDriverVersionSupported(3, 2, 0); + + GLfloat maxAnisotropyOGL = 1.0f; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL); + this->_deviceInfo.maxAnisotropy = (float)maxAnisotropyOGL; + + // OpenGL ES 3.0 needs to look up the best format and data type for glReadPixels. + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &OGLRef.readPixelsBestFormat); + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &OGLRef.readPixelsBestDataType); + + this->_deviceInfo.isEdgeMarkSupported = true; + this->_deviceInfo.isFogSupported = true; + + // Need to generate this texture first because FBO creation needs it. + // This texture is only required by shaders, and so if shader creation + // fails, then we can immediately delete this texture if an error occurs. + glGenTextures(1, &OGLRef.texFinalColorID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); + glBindTexture(GL_TEXTURE_2D, OGLRef.texFinalColorID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glActiveTexture(GL_TEXTURE0); + + // OpenGL ES v3.0 should have all the necessary features to be able to flip and convert the framebuffer. + this->willFlipOnlyFramebufferOnGPU = true; + this->willFlipAndConvertFramebufferOnGPU = true; + + this->_enableTextureSmoothing = CommonSettings.GFX3D_Renderer_TextureSmoothing; + this->_emulateShadowPolygon = CommonSettings.OpenGL_Emulation_ShadowPolygon; + this->_emulateSpecialZeroAlphaBlending = CommonSettings.OpenGL_Emulation_SpecialZeroAlphaBlending; + this->_emulateNDSDepthCalculation = CommonSettings.OpenGL_Emulation_NDSDepthCalculation; + this->_emulateDepthLEqualPolygonFacing = CommonSettings.OpenGL_Emulation_DepthLEqualPolygonFacing; + + // Load and create shaders. Return on any error, since ES 3.0 makes shaders mandatory. + this->isShaderSupported = true; + + error = this->CreateGeometryPrograms(); + if (error != OGLERROR_NOERR) + { + glUseProgram(0); + this->DestroyGeometryPrograms(); + this->isShaderSupported = false; + + return error; + } + + error = this->CreateGeometryZeroDstAlphaProgram(GeometryZeroDstAlphaPixelMaskVtxShader_150, GeometryZeroDstAlphaPixelMaskFragShader_150); + if (error != OGLERROR_NOERR) + { + glUseProgram(0); + this->DestroyGeometryPrograms(); + this->isShaderSupported = false; + + return error; + } + + INFO("OpenGL: Successfully created geometry shaders.\n"); + error = this->InitPostprocessingPrograms(EdgeMarkVtxShader_150, + EdgeMarkFragShader_150, + FramebufferOutputVtxShader_150, + FramebufferOutput6665FragShader_150, + NULL); + if (error != OGLERROR_NOERR) + { + glUseProgram(0); + this->DestroyGeometryPrograms(); + this->DestroyGeometryZeroDstAlphaProgram(); + this->isShaderSupported = false; + + return error; + } + + this->isVBOSupported = true; + this->CreateVBOs(); + + this->isPBOSupported = true; + this->CreatePBOs(); + + this->isVAOSupported = true; + this->CreateVAOs(); + + // Load and create FBOs. Return on any error, since v3.2 Core Profile makes FBOs mandatory. + this->isFBOSupported = true; + error = this->CreateFBOs(); + if (error != OGLERROR_NOERR) + { + this->isFBOSupported = false; + return error; + } + + this->isMultisampledFBOSupported = true; + this->_selectedMultisampleSize = CommonSettings.GFX3D_Renderer_MultisampleSize; + + GLint maxSamplesOGL = 0; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamplesOGL); + this->_deviceInfo.maxSamples = (u8)maxSamplesOGL; + + if (this->_deviceInfo.maxSamples >= 2) + { + // Try and initialize the multisampled FBOs with the GFX3D_Renderer_MultisampleSize. + // However, if the client has this set to 0, then set sampleSize to 2 in order to + // force the generation and the attachments of the buffers at a meaningful sample + // size. If GFX3D_Renderer_MultisampleSize is 0, then we can deallocate the buffer + // memory afterwards. + GLsizei sampleSize = this->GetLimitedMultisampleSize(); + if (sampleSize == 0) + { + sampleSize = 2; + } + + error = this->CreateMultisampledFBO(sampleSize); + if (error != OGLERROR_NOERR) + { + this->isMultisampledFBOSupported = false; + } + + // If GFX3D_Renderer_MultisampleSize is 0, then we can deallocate the buffers now + // in order to save some memory. + if (this->_selectedMultisampleSize == 0) + { + this->ResizeMultisampledFBOs(0); + } + } + else + { + this->isMultisampledFBOSupported = false; + INFO("OpenGL: Driver does not support at least 2x multisampled FBOs.\n"); + } + + this->_isDepthLEqualPolygonFacingSupported = true; + this->_enableMultisampledRendering = ((this->_selectedMultisampleSize >= 2) && this->isMultisampledFBOSupported); + + this->InitFinalRenderStates(&oglExtensionSet); // This must be done last + + return OGLERROR_NOERR; +} + +Render3DError OpenGLESRenderer_3_0::CreateGeometryPrograms() +{ + Render3DError error = OGLERROR_NOERR; + OGLRenderRef &OGLRef = *this->ref; + + // Create shader resources. + if (OGLRef.uboRenderStatesID == 0) + { + glGenBuffers(1, &OGLRef.uboRenderStatesID); + glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboRenderStatesID); + glBufferData(GL_UNIFORM_BUFFER, sizeof(OGLRenderStates), NULL, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, OGLBindingPointID_RenderStates, OGLRef.uboRenderStatesID); + } + + if (this->_is64kUBOSupported) + { + // Try transferring the polygon states through a UBO first. This is the fastest method, + // but requires a GPU that supports 64k UBO transfers. + if (OGLRef.uboPolyStatesID == 0) + { + glGenBuffers(1, &OGLRef.uboPolyStatesID); + glBindBuffer(GL_UNIFORM_BUFFER, OGLRef.uboPolyStatesID); + glBufferData(GL_UNIFORM_BUFFER, MAX_CLIPPED_POLY_COUNT_FOR_UBO * sizeof(OGLPolyStates), NULL, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, OGLBindingPointID_PolyStates, OGLRef.uboPolyStatesID); + } + } +#ifdef GL_ES_VERSION_3_2 + else if (this->_isTBOSupported) + { + // If for some reason the GPU doesn't support 64k UBOs but still supports OpenGL ES 3.2, + // then use a TBO as the second fastest method. + if (OGLRef.tboPolyStatesID == 0) + { + // Set up poly states TBO + glGenBuffers(1, &OGLRef.tboPolyStatesID); + glBindBuffer(GL_TEXTURE_BUFFER, OGLRef.tboPolyStatesID); + glBufferData(GL_TEXTURE_BUFFER, CLIPPED_POLYLIST_SIZE * sizeof(OGLPolyStates), NULL, GL_DYNAMIC_DRAW); + + glGenTextures(1, &OGLRef.texPolyStatesID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates); + glBindTexture(GL_TEXTURE_BUFFER, OGLRef.texPolyStatesID); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, OGLRef.tboPolyStatesID); + glActiveTexture(GL_TEXTURE0); + } + } +#endif + else + { + // For compatibility reasons, we can transfer the polygon states through a plain old + // integer texture. + glGenTextures(1, &OGLRef.texPolyStatesID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_PolyStates); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPolyStatesID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, 256, 128, 0, GL_RED_INTEGER, GL_INT, NULL); + glActiveTexture(GL_TEXTURE0); + } + + glGenTextures(1, &OGLRef.texFogDensityTableID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_LookupTable); + glBindTexture(GL_TEXTURE_2D, OGLRef.texFogDensityTableID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 1, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + glActiveTexture(GL_TEXTURE0); + + OGLGeometryFlags programFlags; + programFlags.value = 0; + + std::stringstream shaderHeader; + shaderHeader << "#version 300 es\n"; + shaderHeader << "precision highp float;\n"; + shaderHeader << "precision highp int;\n"; + shaderHeader << "\n"; + + std::stringstream vsHeader; + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + vsHeader << "\n"; + vsHeader << "#define IS_USING_UBO_POLY_STATES " << ((OGLRef.uboPolyStatesID != 0) ? 1 : 0) << "\n"; + vsHeader << "#define IS_USING_TBO_POLY_STATES " << ((OGLRef.tboPolyStatesID != 0) ? 1 : 0) << "\n"; + vsHeader << "#define DEPTH_EQUALS_TEST_TOLERANCE " << DEPTH_EQUALS_TEST_TOLERANCE << ".0\n"; + vsHeader << "\n"; + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(GeometryVtxShader_ES300); + + for (size_t flagsValue = 0; flagsValue < 128; flagsValue++, programFlags.value++) + { + std::stringstream shaderFlags; + if (this->_isShaderFixedLocationSupported) + { + shaderFlags << "#define OUT_COLOR layout (location = 0) out\n"; + shaderFlags << "#define OUT_WORKING_BUFFER layout (location = " << GeometryAttachmentWorkingBuffer[programFlags.DrawBuffersMode] << ") out\n"; + shaderFlags << "#define OUT_POLY_ID layout (location = " << GeometryAttachmentPolyID[programFlags.DrawBuffersMode] << ") out\n"; + shaderFlags << "#define OUT_FOG_ATTRIBUTES layout (location = " << GeometryAttachmentFogAttributes[programFlags.DrawBuffersMode] << ") out\n"; + } + else + { + shaderFlags << "#define OUT_COLOR out\n"; + shaderFlags << "#define OUT_WORKING_BUFFER out\n"; + shaderFlags << "#define OUT_POLY_ID out\n"; + shaderFlags << "#define OUT_FOG_ATTRIBUTES out\n"; + } + shaderFlags << "\n"; + shaderFlags << "#define USE_TEXTURE_SMOOTHING " << ((this->_enableTextureSmoothing) ? 1 : 0) << "\n"; + shaderFlags << "#define USE_NDS_DEPTH_CALCULATION " << ((this->_emulateNDSDepthCalculation) ? 1 : 0) << "\n"; + shaderFlags << "#define USE_DEPTH_LEQUAL_POLYGON_FACING " << ((this->_emulateDepthLEqualPolygonFacing) ? 1 : 0) << "\n"; + shaderFlags << "\n"; + shaderFlags << "#define ENABLE_W_DEPTH " << ((programFlags.EnableWDepth) ? 1 : 0) << "\n"; + shaderFlags << "#define ENABLE_ALPHA_TEST " << ((programFlags.EnableAlphaTest) ? "true\n" : "false\n"); + shaderFlags << "#define ENABLE_TEXTURE_SAMPLING " << ((programFlags.EnableTextureSampling) ? "true\n" : "false\n"); + shaderFlags << "#define TOON_SHADING_MODE " << ((programFlags.ToonShadingMode) ? 1 : 0) << "\n"; + shaderFlags << "#define ENABLE_FOG " << ((programFlags.EnableFog) ? 1 : 0) << "\n"; + shaderFlags << "#define ENABLE_EDGE_MARK " << ((programFlags.EnableEdgeMark) ? 1 : 0) << "\n"; + shaderFlags << "#define DRAW_MODE_OPAQUE " << ((programFlags.OpaqueDrawMode) ? 1 : 0) << "\n"; + shaderFlags << "\n"; + + std::string fragShaderCode = shaderHeader.str() + shaderFlags.str() + std::string(GeometryFragShader_ES300); + + error = this->ShaderProgramCreate(OGLRef.vertexGeometryShaderID, + OGLRef.fragmentGeometryShaderID[flagsValue], + OGLRef.programGeometryID[flagsValue], + vtxShaderCode.c_str(), + fragShaderCode.c_str()); + if (error != OGLERROR_NOERR) + { + INFO("OpenGL: Failed to create the GEOMETRY shader program.\n"); + glUseProgram(0); + this->DestroyGeometryPrograms(); + return error; + } + + glLinkProgram(OGLRef.programGeometryID[flagsValue]); + if (!this->ValidateShaderProgramLink(OGLRef.programGeometryID[flagsValue])) + { + INFO("OpenGL: Failed to link the GEOMETRY shader program.\n"); + glUseProgram(0); + this->DestroyGeometryPrograms(); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glValidateProgram(OGLRef.programGeometryID[flagsValue]); + glUseProgram(OGLRef.programGeometryID[flagsValue]); + + // Set up render states UBO + const GLuint uniformBlockRenderStates = glGetUniformBlockIndex(OGLRef.programGeometryID[flagsValue], "RenderStates"); + glUniformBlockBinding(OGLRef.programGeometryID[flagsValue], uniformBlockRenderStates, OGLBindingPointID_RenderStates); + + GLint uboSize = 0; + glGetActiveUniformBlockiv(OGLRef.programGeometryID[flagsValue], uniformBlockRenderStates, GL_UNIFORM_BLOCK_DATA_SIZE, &uboSize); + assert(uboSize == sizeof(OGLRenderStates)); + + const GLint uniformTexRenderObject = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "texRenderObject"); + glUniform1i(uniformTexRenderObject, 0); + + if (OGLRef.uboPolyStatesID != 0) + { + const GLuint uniformBlockPolyStates = glGetUniformBlockIndex(OGLRef.programGeometryID[flagsValue], "PolyStates"); + glUniformBlockBinding(OGLRef.programGeometryID[flagsValue], uniformBlockPolyStates, OGLBindingPointID_PolyStates); + } + else + { + const GLint uniformTexBufferPolyStates = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "PolyStates"); + glUniform1i(uniformTexBufferPolyStates, OGLTextureUnitID_PolyStates); + } + + if (this->_emulateDepthLEqualPolygonFacing && !programFlags.OpaqueDrawMode) + { + const GLint uniformTexBackfacing = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "inDstBackFacing"); + glUniform1i(uniformTexBackfacing, OGLTextureUnitID_FinalColor); + } + + OGLRef.uniformTexDrawOpaque[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "texDrawOpaque"); + OGLRef.uniformDrawModeDepthEqualsTest[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "drawModeDepthEqualsTest"); + OGLRef.uniformPolyDrawShadow[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDrawShadow"); + OGLRef.uniformPolyStateIndex[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyIndex"); + OGLRef.uniformPolyDepthOffset[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDepthOffset"); + } + + return error; +} + +Render3DError OpenGLESRenderer_3_0::CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString) +{ + Render3DError error = OGLERROR_NOERR; + OGLRenderRef &OGLRef = *this->ref; + + if ( (vtxShaderCString == NULL) || (fragShaderCString == NULL) ) + { + return error; + } + + std::stringstream shaderHeader; + shaderHeader << "#version 300 es\n"; + shaderHeader << "precision highp float;\n"; + shaderHeader << "precision highp int;\n"; + shaderHeader << "\n"; + + std::stringstream vsHeader; + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); + std::string fragShaderCode = shaderHeader.str() + std::string(fragShaderCString); + + error = this->ShaderProgramCreate(OGLRef.vtxShaderGeometryZeroDstAlphaID, + OGLRef.fragShaderGeometryZeroDstAlphaID, + OGLRef.programGeometryZeroDstAlphaID, + vtxShaderCode.c_str(), + fragShaderCode.c_str()); + if (error != OGLERROR_NOERR) + { + INFO("OpenGL: Failed to create the GEOMETRY ZERO DST ALPHA shader program.\n"); + glUseProgram(0); + this->DestroyGeometryZeroDstAlphaProgram(); + return error; + } + + glLinkProgram(OGLRef.programGeometryZeroDstAlphaID); + if (!this->ValidateShaderProgramLink(OGLRef.programGeometryZeroDstAlphaID)) + { + INFO("OpenGL: Failed to link the GEOMETRY ZERO DST ALPHA shader program.\n"); + glUseProgram(0); + this->DestroyGeometryZeroDstAlphaProgram(); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glValidateProgram(OGLRef.programGeometryZeroDstAlphaID); + glUseProgram(OGLRef.programGeometryZeroDstAlphaID); + + const GLint uniformTexGColor = glGetUniformLocation(OGLRef.programGeometryZeroDstAlphaID, "texInFragColor"); + glUniform1i(uniformTexGColor, OGLTextureUnitID_GColor); + + return OGLERROR_NOERR; +} + +Render3DError OpenGLESRenderer_3_0::CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString) +{ + Render3DError error = OGLERROR_NOERR; + OGLRenderRef &OGLRef = *this->ref; + + if ( (vtxShaderCString == NULL) || (fragShaderCString == NULL) ) + { + return error; + } + + std::stringstream shaderHeader; + shaderHeader << "#version 300 es\n"; + shaderHeader << "precision highp float;\n"; + shaderHeader << "precision highp int;\n"; + shaderHeader << "\n"; + shaderHeader << "#define FRAMEBUFFER_SIZE_X " << this->_framebufferWidth << ".0 \n"; + shaderHeader << "#define FRAMEBUFFER_SIZE_Y " << this->_framebufferHeight << ".0 \n"; + shaderHeader << "\n"; + + std::stringstream vsHeader; + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + + std::stringstream fsHeader; + fsHeader << "#define OUT_COLOR layout (location = 0) out\n"; + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); + std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + std::string(fragShaderCString); + + error = this->ShaderProgramCreate(OGLRef.vertexEdgeMarkShaderID, + OGLRef.fragmentEdgeMarkShaderID, + OGLRef.programEdgeMarkID, + vtxShaderCode.c_str(), + fragShaderCode.c_str()); + if (error != OGLERROR_NOERR) + { + INFO("OpenGL: Failed to create the EDGE MARK shader program.\n"); + glUseProgram(0); + this->DestroyEdgeMarkProgram(); + return error; + } + + glLinkProgram(OGLRef.programEdgeMarkID); + if (!this->ValidateShaderProgramLink(OGLRef.programEdgeMarkID)) + { + INFO("OpenGL: Failed to link the EDGE MARK shader program.\n"); + glUseProgram(0); + this->DestroyEdgeMarkProgram(); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glValidateProgram(OGLRef.programEdgeMarkID); + glUseProgram(OGLRef.programEdgeMarkID); + + const GLuint uniformBlockRenderStates = glGetUniformBlockIndex(OGLRef.programEdgeMarkID, "RenderStates"); + glUniformBlockBinding(OGLRef.programEdgeMarkID, uniformBlockRenderStates, OGLBindingPointID_RenderStates); + + const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInFragDepth"); + const GLint uniformTexGPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInPolyID"); + glUniform1i(uniformTexGDepth, OGLTextureUnitID_DepthStencil); + glUniform1i(uniformTexGPolyID, OGLTextureUnitID_GPolyID); + + return OGLERROR_NOERR; +} + +Render3DError OpenGLESRenderer_3_0::CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString) +{ + Render3DError error = OGLERROR_NOERR; + OGLRenderRef &OGLRef = *this->ref; + + if (vtxShaderCString == NULL) + { + INFO("OpenGL: The FOG vertex shader is unavailable.\n"); + error = OGLERROR_VERTEX_SHADER_PROGRAM_LOAD_ERROR; + return error; + } + else if (fragShaderCString == NULL) + { + INFO("OpenGL: The FOG fragment shader is unavailable.\n"); + error = OGLERROR_FRAGMENT_SHADER_PROGRAM_LOAD_ERROR; + return error; + } + + const s32 fogOffset = fogProgramKey.offset; + const GLfloat fogOffsetf = (GLfloat)fogOffset / 32767.0f; + const s32 fogStep = 0x0400 >> fogProgramKey.shift; + + std::stringstream shaderHeader; + shaderHeader << "#version 300 es\n"; + shaderHeader << "precision highp float;\n"; + shaderHeader << "precision highp int;\n"; + shaderHeader << "\n"; + + std::stringstream vsHeader; + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + + std::stringstream fsHeader; + fsHeader << "#define USE_DUAL_SOURCE_BLENDING " << ((this->_isDualSourceBlendingSupported) ? 1 : 0) << "\n"; + fsHeader << "\n"; + fsHeader << "#define FOG_OFFSET " << fogOffset << "\n"; + fsHeader << "#define FOG_OFFSETF " << fogOffsetf << (((fogOffsetf == 0.0f) || (fogOffsetf == 1.0f)) ? ".0" : "") << "\n"; + fsHeader << "#define FOG_STEP " << fogStep << "\n"; + fsHeader << "\n"; + fsHeader << "#define OUT_FOG_COLOR layout (location = 0, index = 0) out\n"; + fsHeader << "#define OUT_FOG_WEIGHT layout (location = 0, index = 1) out\n"; + fsHeader << "#define OUT_COLOR layout (location = 0) out\n"; + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); + std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + std::string(fragShaderCString); + + OGLFogShaderID shaderID; + shaderID.program = 0; + shaderID.fragShader = 0; + + error = this->ShaderProgramCreate(OGLRef.vertexFogShaderID, + shaderID.fragShader, + shaderID.program, + vtxShaderCode.c_str(), + fragShaderCode.c_str()); + + this->_fogProgramMap[fogProgramKey.key] = shaderID; + + if (error != OGLERROR_NOERR) + { + INFO("OpenGL: Failed to create the FOG shader program.\n"); + glUseProgram(0); + this->DestroyFogProgram(fogProgramKey); + return error; + } + + glLinkProgram(shaderID.program); + if (!this->ValidateShaderProgramLink(shaderID.program)) + { + INFO("OpenGL: Failed to link the FOG shader program.\n"); + glUseProgram(0); + this->DestroyFogProgram(fogProgramKey); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glValidateProgram(shaderID.program); + glUseProgram(shaderID.program); + + const GLuint uniformBlockRenderStates = glGetUniformBlockIndex(shaderID.program, "RenderStates"); + glUniformBlockBinding(shaderID.program, uniformBlockRenderStates, OGLBindingPointID_RenderStates); + + const GLint uniformTexGDepth = glGetUniformLocation(shaderID.program, "texInFragDepth"); + const GLint uniformTexGFog = glGetUniformLocation(shaderID.program, "texInFogAttributes"); + const GLint uniformTexFogDensityTable = glGetUniformLocation(shaderID.program, "texFogDensityTable"); + glUniform1i(uniformTexGDepth, OGLTextureUnitID_DepthStencil); + glUniform1i(uniformTexGFog, OGLTextureUnitID_FogAttr); + glUniform1i(uniformTexFogDensityTable, OGLTextureUnitID_LookupTable); + + const GLint uniformTexGColor = glGetUniformLocation(shaderID.program, "texInFragColor"); + glUniform1i(uniformTexGColor, OGLTextureUnitID_GColor); + + return OGLERROR_NOERR; +} + +Render3DError OpenGLESRenderer_3_0::CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString) +{ + Render3DError error = OGLERROR_NOERR; + OGLRenderRef &OGLRef = *this->ref; + + if ( (vtxShaderCString == NULL) || (fragShaderCString == NULL) ) + { + return error; + } + + std::stringstream shaderHeader; + shaderHeader << "#version 300 es\n"; + shaderHeader << "precision highp float;\n"; + shaderHeader << "precision highp int;\n"; + shaderHeader << "\n"; + shaderHeader << "#define FRAMEBUFFER_SIZE_X " << this->_framebufferWidth << ".0 \n"; + shaderHeader << "#define FRAMEBUFFER_SIZE_Y " << this->_framebufferHeight << ".0 \n"; + shaderHeader << "\n"; + + std::stringstream vsHeader; + vsHeader << "#define IN_VTX_POSITION layout (location = " << OGLVertexAttributeID_Position << ") in\n"; + vsHeader << "#define IN_VTX_TEXCOORD0 layout (location = " << OGLVertexAttributeID_TexCoord0 << ") in\n"; + vsHeader << "#define IN_VTX_COLOR layout (location = " << OGLVertexAttributeID_Color << ") in\n"; + + std::stringstream fsHeader; + fsHeader << "#define OUT_COLOR layout (location = 0) out\n"; + + std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); + std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + std::string(fragShaderCString); + + error = this->ShaderProgramCreate(OGLRef.vertexFramebufferOutput6665ShaderID, + OGLRef.fragmentFramebufferRGBA6665OutputShaderID, + OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], + vtxShaderCode.c_str(), + fragShaderCode.c_str()); + if (error != OGLERROR_NOERR) + { + INFO("OpenGL: Failed to create the FRAMEBUFFER OUTPUT RGBA6665 shader program.\n"); + glUseProgram(0); + this->DestroyFramebufferOutput6665Programs(); + return error; + } + + glLinkProgram(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex]); + if (!this->ValidateShaderProgramLink(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex])) + { + INFO("OpenGL: Failed to link the FRAMEBUFFER OUTPUT RGBA6665 shader program.\n"); + glUseProgram(0); + this->DestroyFramebufferOutput6665Programs(); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glValidateProgram(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex]); + glUseProgram(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex]); + + const GLint uniformTexGColor = glGetUniformLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], "texInFragColor"); + if (outColorIndex == 0) + { + glUniform1i(uniformTexGColor, OGLTextureUnitID_FinalColor); + } + else + { + glUniform1i(uniformTexGColor, OGLTextureUnitID_GColor); + } + + return OGLERROR_NOERR; +} diff --git a/desmume/src/OGLRender_ES3.h b/desmume/src/OGLRender_ES3.h new file mode 100644 index 000000000..86c05933a --- /dev/null +++ b/desmume/src/OGLRender_ES3.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2024 DeSmuME team + + This file 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 file 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 the this software. If not, see . +*/ + +#ifndef OGLRENDER_ES3_H +#define OGLRENDER_ES3_H + +#include "OGLRender_3_2.h" + +// A port that wants to use the OpenGL ES renderer must assign the two following functions +// to OGLLoadEntryPoints_ES_3_0_Func and OGLCreateRenderer_ES_3_0_Func, respectively. +// +// In addition, the port must add the following GPU3DInterface objects to core3DList: +// - gpu3Dgl_ES_3_0: Selects the OpenGL ES 3.0 renderer, and returns an error if it is +// not available on the host system. +// +// Finally, the port must call GPU->Set3DRendererByID() and pass in the index where +// gpu3Dgl_ES_3_0 exists in core3DList so that the emulator can create the appropriate +// OpenGLRenderer object. +// +// Example code: +// OGLLoadEntryPoints_ES_3_0_Func = &OGLLoadEntryPoints_ES_3_0; +// OGLCreateRenderer_ES_3_0_Func = &OGLCreateRenderer_ES_3_0; +// GPU3DInterface *core3DList[] = { &gpu3DNull, &gpu3DRasterize, &gpu3Dgl_ES_3_0, NULL }; +// GPU->Set3DRendererByID(2); + +void OGLLoadEntryPoints_ES_3_0(); +void OGLCreateRenderer_ES_3_0(OpenGLRenderer **rendererPtr); + +class OpenGLESRenderer_3_0 : public OpenGLRenderer_3_2 +{ +protected: + virtual Render3DError CreateGeometryPrograms(); + virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); + +public: + OpenGLESRenderer_3_0(); + + virtual Render3DError InitExtensions(); +}; + +#endif // OGLRENDER_ES3_H From 86a29d768a1888b5f600bf0cc0d8e0bfa69ba6b6 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 10 Jul 2024 13:59:02 -0700 Subject: [PATCH 47/49] OpenGL ES Renderer: Do some minor changes/fixes. - Fix a bug where _isShaderFixedLocationSupported wasn't being set to true, causing shaders to fail. - OpenGL version checks now account for non-compliant ES drivers that contain text before the version number. - Manually set the default read/draw buffers for all FBOs upon creation. We shouldn't need to do this, since they should always be set later, but just in case... - Add missing GL_BGRA macro. - Tidy up the OpenGL naming in some error strings. --- desmume/src/OGLRender.cpp | 63 ++++++++++++++++++++++++----------- desmume/src/OGLRender.h | 6 ++++ desmume/src/OGLRender_3_2.cpp | 8 +++++ desmume/src/OGLRender_ES3.cpp | 3 ++ 4 files changed, 61 insertions(+), 19 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 515d55e93..1ce3b26b2 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -754,30 +754,46 @@ static void OGLGetDriverVersion(const char *oglVersionString, // First, check for the dot in the revision string. There should be at // least one present. - const char *versionStrEnd = strstr(oglVersionString, "."); - if (versionStrEnd == NULL) + const char *versionStrDot = strstr(oglVersionString, "."); + if (versionStrDot == NULL) { return; } - // Next, check for the space before the vendor-specific info (if present). - versionStrEnd = strstr(oglVersionString, " "); - if (versionStrEnd == NULL) + // Next, check for a space that is after the dot, but before the vendor-specific info (if present). + versionStringLength = strlen(oglVersionString); // Set our default string length here + const size_t endCheckLength = versionStringLength - (versionStrDot - oglVersionString); // Maximum possible length to check + const char *checkStringLimit = (endCheckLength < 10) ? versionStrDot + endCheckLength : versionStrDot + 10; // But we're going to limit ourselves to checking only the first 10 characters + + char *versionStrEnd = (char *)versionStrDot; + while (versionStrEnd < checkStringLimit) { - // If a space was not found, then the vendor-specific info is not present, - // and therefore the entire string must be the version number. - versionStringLength = strlen(oglVersionString); + versionStrEnd++; + if (*versionStrEnd == ' ') + { + versionStringLength = versionStrEnd - oglVersionString; + break; + } } - else + + // Check for any spaces before the dot. There shouldn't be any text before the version number, so + // this step shouldn't be necessary. However, some drivers can defy the OpenGL spec and include + // text before the version number, and so we need to handle such non-compliant drivers just in case. + char *versionStrStart = (char *)versionStrDot; + while (versionStrStart > oglVersionString) { - // If a space was found, then the vendor-specific info is present, - // and therefore the version number is everything before the space. - versionStringLength = versionStrEnd - oglVersionString; + versionStrStart--; + if (*versionStrStart == ' ') + { + versionStrStart++; // Don't include the space we just checked. + versionStringLength -= versionStrStart - oglVersionString; + break; + } } // Copy the version substring and parse it. char *versionSubstring = (char *)malloc(versionStringLength * sizeof(char)); - strncpy(versionSubstring, oglVersionString, versionStringLength); + strncpy(versionSubstring, versionStrStart, versionStringLength); unsigned int major = 0; unsigned int minor = 0; @@ -977,28 +993,28 @@ static Render3D* OpenGLRendererCreate() switch (VARIANTID) { case OpenGLVariantID_Legacy_1_2: - strncpy(variantString, "Open GL 1.2 (forced)", sizeof(variantString)); + strncpy(variantString, "OpenGL 1.2 (forced)", sizeof(variantString)); break; case OpenGLVariantID_Legacy_2_0: - strncpy(variantString, "Open GL 2.0 (forced)", sizeof(variantString)); + strncpy(variantString, "OpenGL 2.0 (forced)", sizeof(variantString)); break; case OpenGLVariantID_Legacy_2_1: - strncpy(variantString, "Open GL 2.1 (forced)", sizeof(variantString)); + strncpy(variantString, "OpenGL 2.1 (forced)", sizeof(variantString)); break; case OpenGLVariantID_CoreProfile_3_2: - strncpy(variantString, "Open GL 3.2 (forced)", sizeof(variantString)); + strncpy(variantString, "OpenGL 3.2 (forced)", sizeof(variantString)); break; case OpenGLVariantID_LegacyAuto: case OpenGLVariantID_StandardAuto: - strncpy(variantString, "Open GL (auto)", sizeof(variantString)); + strncpy(variantString, "OpenGL (auto)", sizeof(variantString)); break; case OpenGLVariantID_ES_3_0: - strncpy(variantString, "Open GL ES 3.0", sizeof(variantString)); + strncpy(variantString, "OpenGL ES 3.0", sizeof(variantString)); break; default: @@ -2983,6 +2999,10 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() return OGLERROR_FBO_CREATE_ERROR; } + // Assign the default read/draw buffers. + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboFramebufferFlipID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); @@ -2995,6 +3015,10 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() return OGLERROR_FBO_CREATE_ERROR; } + // Assign the default read/draw buffers. + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, OGL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); @@ -3011,6 +3035,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() return OGLERROR_FBO_CREATE_ERROR; } + // Assign the default read/draw buffers. glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index 94243de01..8928fdf9f 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -306,6 +306,12 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) #endif // GL_EXT_framebuffer_object +// Some headers, such as the OpenGL ES headers, may not include this macro. +// Add it manually to avoid compiling issues. +#ifndef GL_BGRA +#define GL_BGRA 0x80E1 +#endif + // OPENGL CORE EQUIVALENTS FOR LEGACY FUNCTIONS // Some OpenGL variants, such as OpenGL ES, do not include certain legacy functions in their // API. The loss of these functions will cause compile time errors when referenced, and so diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 490c1fdce..3ff077fb7 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -949,6 +949,10 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() return OGLERROR_FBO_CREATE_ERROR; } + // Assign the default read/draw buffers. + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); @@ -964,6 +968,10 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() return OGLERROR_FBO_CREATE_ERROR; } + // Assign the default read/draw buffers. + glReadBuffer(OGL_COLOROUT_ATTACHMENT_ID); + glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); + OGLRef.selectedRenderingFBO = OGLRef.fboRenderID; INFO("OpenGL: Successfully created FBOs.\n"); diff --git a/desmume/src/OGLRender_ES3.cpp b/desmume/src/OGLRender_ES3.cpp index 374518238..152009574 100644 --- a/desmume/src/OGLRender_ES3.cpp +++ b/desmume/src/OGLRender_ES3.cpp @@ -278,6 +278,9 @@ Render3DError OpenGLESRenderer_3_0::InitExtensions() // TBOs are only supported in ES 3.2. this->_isTBOSupported = IsOpenGLDriverVersionSupported(3, 2, 0); + // Fixed locations in shaders are supported in ES 3.0 by default. + this->_isShaderFixedLocationSupported = true; + GLfloat maxAnisotropyOGL = 1.0f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyOGL); this->_deviceInfo.maxAnisotropy = (float)maxAnisotropyOGL; From bb3011c262e29708b06e55ddd8cb1a0ee113ae94 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 10 Jul 2024 16:01:13 -0700 Subject: [PATCH 48/49] OpenGL Renderer: Return to a more traditional method of doing texture reads in shaders, effectively removing dependent texture reads where appropriate. - This change won't affect standard OpenGL on a desktop PC, but may improve performance on lesser GPUs trying to run OpenGL ES. --- desmume/src/OGLRender.cpp | 2 +- desmume/src/OGLRender_3_2.cpp | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 1ce3b26b2..cd58bf4c1 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -688,7 +688,7 @@ varying vec2 texCoord;\n\ \n\ void main()\n\ {\n\ - texCoord = vec2(inTexCoord0.x, (FRAMEBUFFER_SIZE_Y - (FRAMEBUFFER_SIZE_Y * inTexCoord0.y)) / FRAMEBUFFER_SIZE_Y);\n\ + texCoord = vec2(inTexCoord0.x, 1.0 - inTexCoord0.y);\n\ gl_Position = vec4(inPosition, 0.0, 1.0);\n\ }\n\ "}; diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 3ff077fb7..56904c8a6 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -526,9 +526,12 @@ void main()\n\ // Vertex shader for applying fog, GLSL 1.50 const char *FogVtxShader_150 = {"\ IN_VTX_POSITION vec2 inPosition;\n\ +IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ +out vec2 texCoord;\n\ \n\ void main()\n\ {\n\ + texCoord = inTexCoord0;\n\ gl_Position = vec4(inPosition, 0.0, 1.0);\n\ }\n\ "}; @@ -550,6 +553,8 @@ layout (std140) uniform RenderStates\n\ vec4 toonColor[32];\n\ } state;\n\ \n\ +in vec2 texCoord;\n\ +\n\ uniform sampler2D texInFragDepth;\n\ uniform sampler2D texInFogAttributes;\n\ uniform sampler2D texFogDensityTable;\n\ @@ -568,11 +573,11 @@ void main()\n\ outFogColor = state.fogColor;\n\ outFogWeight = vec4(0.0);\n\ #else\n\ - outFragColor = texelFetch(texInFragColor, ivec2(gl_FragCoord.xy), 0);\n\ + outFragColor = texture(texInFragColor, texCoord);\n\ #endif\n\ \n\ - float inFragDepth = texelFetch(texInFragDepth, ivec2(gl_FragCoord.xy), 0).r;\n\ - vec4 inFogAttributes = texelFetch(texInFogAttributes, ivec2(gl_FragCoord.xy), 0);\n\ + float inFragDepth = texture(texInFragDepth, texCoord).r;\n\ + vec4 inFogAttributes = texture(texInFogAttributes, texCoord);\n\ bool polyEnableFog = (inFogAttributes.r > 0.999);\n\ \n\ float fogMixWeight = 0.0;\n\ @@ -600,22 +605,27 @@ void main()\n\ // Vertex shader for the final framebuffer, GLSL 1.50 const char *FramebufferOutputVtxShader_150 = {"\ IN_VTX_POSITION vec2 inPosition;\n\ +IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ +out vec2 texCoord;\n\ \n\ void main()\n\ {\n\ + texCoord = vec2(inTexCoord0.x, 1.0 - inTexCoord0.y);\n\ gl_Position = vec4(inPosition, 0.0, 1.0);\n\ }\n\ "}; // Fragment shader for the final RGBA6665 formatted framebuffer, GLSL 1.50 const char *FramebufferOutput6665FragShader_150 = {"\ +in vec2 texCoord;\n\ +\n\ uniform sampler2D texInFragColor;\n\ \n\ OUT_COLOR vec4 outFragColor6665;\n\ \n\ void main()\n\ {\n\ - outFragColor6665 = texelFetch(texInFragColor, ivec2(gl_FragCoord.x, FRAMEBUFFER_SIZE_Y - gl_FragCoord.y), 0);\n\ + outFragColor6665 = texture(texInFragColor, texCoord);\n\ outFragColor6665 = floor((outFragColor6665 * 255.0) + 0.5);\n\ outFragColor6665.rgb = floor(outFragColor6665.rgb / 4.0);\n\ outFragColor6665.a = floor(outFragColor6665.a / 8.0);\n\ @@ -1856,6 +1866,7 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro if (!this->_isShaderFixedLocationSupported) { glBindAttribLocation(shaderID.program, OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(shaderID.program, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); #ifdef GL_VERSION_3_3 if (this->_isDualSourceBlendingSupported) @@ -1970,6 +1981,7 @@ Render3DError OpenGLRenderer_3_2::CreateFramebufferOutput6665Program(const size_ if (!this->_isShaderFixedLocationSupported) { glBindAttribLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], OGLVertexAttributeID_TexCoord0, "inTexCoord0"); glBindFragDataLocation(OGLRef.programFramebufferRGBA6665OutputID[outColorIndex], 0, "outFragColor6665"); } #endif From 00dd6fb97aef22f39571df2fee842bc50fea9f66 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 10 Jul 2024 21:53:49 -0700 Subject: [PATCH 49/49] OpenGL ES Renderer: Use the proper ES extension header, and also avoid double #defining some of the tokens. --- desmume/src/OGLRender.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) mode change 100755 => 100644 desmume/src/OGLRender.h diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h old mode 100755 new mode 100644 index 8928fdf9f..f0e319461 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -32,9 +32,9 @@ #define OPENGL_VARIANT_ES #define _NO_SDL_TYPES #include - #include + #define __gles2_gl2_h_ // Guard against including the gl2.h file. + #include // "gl3ext.h" is just a stub file. The real extension header is "gl2ext.h". #include - //#include "opengl.h" // Ignore dynamic linking #define OGLEXT(procPtr, func) @@ -273,7 +273,18 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) // In practice, class objects for more modern variants like 3.2 Core Profile and ES 3.0 should // override all the methods that would use FBOs so that only the ARB versions are actually used. +#ifndef GL_EXT_draw_buffers #define GL_MAX_COLOR_ATTACHMENTS_EXT GL_MAX_COLOR_ATTACHMENTS +#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 +#define GL_COLOR_ATTACHMENT1_EXT GL_COLOR_ATTACHMENT1 +#define GL_COLOR_ATTACHMENT2_EXT GL_COLOR_ATTACHMENT2 +#define GL_COLOR_ATTACHMENT3_EXT GL_COLOR_ATTACHMENT3 +#endif + +#ifndef GL_EXT_multisampled_render_to_texture +#define GL_MAX_SAMPLES_EXT GL_MAX_SAMPLES +#endif + #define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8 #define GL_DEPTH_STENCIL_EXT GL_DEPTH_STENCIL #define GL_UNSIGNED_INT_24_8_EXT GL_UNSIGNED_INT_24_8 @@ -284,11 +295,6 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) #define GL_RENDERBUFFER_EXT GL_RENDERBUFFER #define GL_DRAW_FRAMEBUFFER_EXT GL_DRAW_FRAMEBUFFER #define GL_READ_FRAMEBUFFER_EXT GL_READ_FRAMEBUFFER -#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0 -#define GL_COLOR_ATTACHMENT1_EXT GL_COLOR_ATTACHMENT1 -#define GL_COLOR_ATTACHMENT2_EXT GL_COLOR_ATTACHMENT2 -#define GL_COLOR_ATTACHMENT3_EXT GL_COLOR_ATTACHMENT3 -#define GL_MAX_SAMPLES_EXT GL_MAX_SAMPLES #define glGenFramebuffersEXT(n, framebuffers) glGenFramebuffers(n, framebuffers) #define glBindFramebufferEXT(target, framebuffer) glBindFramebuffer(target, framebuffer) @@ -309,7 +315,7 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) // Some headers, such as the OpenGL ES headers, may not include this macro. // Add it manually to avoid compiling issues. #ifndef GL_BGRA -#define GL_BGRA 0x80E1 +#define GL_BGRA GL_BGRA_EXT #endif // OPENGL CORE EQUIVALENTS FOR LEGACY FUNCTIONS