From 79b2e7bac8a28612f76de9a11a66dab6e7f01c4e Mon Sep 17 00:00:00 2001 From: friol Date: Sun, 17 Mar 2024 23:10:38 +0100 Subject: [PATCH] Now you can play all the games in the world --- apu.cpp | 23 +- audioSystem.cpp | 94 +-- audioSystem.h | 17 +- example_win32_opengl3.vcxproj | 1 + imfilebrowser.h | 1068 +++++++++++++++++++++++++++++++++ imgui.ini | 302 +++++++++- main.cpp | 222 ++----- ppu.cpp | 4 +- romLoader.cpp | 76 ++- romLoader.h | 3 +- 10 files changed, 1504 insertions(+), 306 deletions(-) create mode 100644 imfilebrowser.h diff --git a/apu.cpp b/apu.cpp index bb92b3e..a00fa4c 100644 --- a/apu.cpp +++ b/apu.cpp @@ -720,7 +720,7 @@ void apu::dspDecodeBrr(int ch) case 3: s += 2 * old + ((13 * -old) >> 6) - older + ((3 * older) >> 4); break; } - channels[ch].decodeBuffer[bOff + i] = clamp16(s) * 2; + channels[ch].decodeBuffer[bOff + i] = (signed short int)(clamp16(s) * 2); older = old; old = channels[ch].decodeBuffer[bOff + i] >> 1; } @@ -795,7 +795,7 @@ void apu::dspHandleGain(int ch) } // store new value - if (dspCheckCounter(rate)) channels[ch].gain = newGain; + if (dspCheckCounter(rate)) channels[ch].gain = (unsigned short int)newGain; } static const int rateValues[32] = { @@ -920,15 +920,15 @@ void apu::dspCycle(signed short int& sampleOutL, signed short int& sampleOutR, f // update pitch counter channels[ch].pitchCounter &= 0x3fff; - channels[ch].pitchCounter += pitch; + channels[ch].pitchCounter += (unsigned short)pitch; if (channels[ch].pitchCounter > 0x7fff) channels[ch].pitchCounter = 0x7fff; // set outputs - dspRam[(ch << 4) | 8] = channels[ch].gain >> 4; - dspRam[(ch << 4) | 9] = sample >> 8; + dspRam[(ch << 4) | 8] = (unsigned char)(channels[ch].gain >> 4); + dspRam[(ch << 4) | 9] = (unsigned char)(sample >> 8); - sampleOutL = clamp16(sampleOutL + ((sample * channels[ch].leftVol) >> 7)); - sampleOutR = clamp16(sampleOutR + ((sample * channels[ch].rightVol) >> 7)); + sampleOutL = (signed short)clamp16(sampleOutL + ((sample * channels[ch].leftVol) >> 7)); + sampleOutR = (signed short)clamp16(sampleOutR + ((sample * channels[ch].rightVol) >> 7)); //if (dsp->channel[ch].echoEnable) { // dsp->echoOutL = clamp16(dsp->echoOutL + ((sample * dsp->channel[ch].volumeL) >> 7)); @@ -2652,7 +2652,7 @@ int apu::stepOne() val0 ^= 0xff; int result = val1 + val0 + 1; flagC = result > 0xff; - doFlagsNZ(result); + doFlagsNZ((unsigned char)result); regPC += 3; cycles = 6; @@ -2900,15 +2900,14 @@ int apu::stepOne() if (flagP) adr1 |= 0x100; unsigned char val0 = (this->*read8)(adr0); - unsigned char val1 = (this->*read8)(adr1); unsigned char applyOn = (this->*read8)(adr1); int result = applyOn + val0 + (flagC?1:0); flagV = (applyOn & 0x80) == (val0 & 0x80) && (val0 & 0x80) != (result & 0x80); flagH = ((applyOn & 0xf) + (val0 & 0xf) + (flagC ? 1 : 0)) > 0xf; flagC = result > 0xff; - (this->*write8)(adr1,result); - doFlagsNZ(result); + (this->*write8)(adr1,(unsigned char)result); + doFlagsNZ((unsigned char)result); regPC += 3; cycles = 6; @@ -3157,7 +3156,7 @@ int apu::stepOne() val1 = (unsigned char)result; doFlagsNZ(val1); - (this->*write8)(adr1, result); + (this->*write8)(adr1, (unsigned char)result); regPC += 3; cycles = 6; diff --git a/audioSystem.cpp b/audioSystem.cpp index 2058494..dfbd7a6 100644 --- a/audioSystem.cpp +++ b/audioSystem.cpp @@ -62,39 +62,8 @@ audioSystem::audioSystem() BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, 0.25); BASS_ChannelPlay(stream, FALSE); - //loadTestSamples(); - - outwavbuf = new float[outwavdim * 2]; - audioSystemInited = true; - glbTheLogger.logMsg("Audio system inited; sample rate:"+std::to_string(sampleRate)); -} - -void audioSystem::loadTestSamples() -{ - for (unsigned int ins = 0;ins < 0x14;ins++) - { - AudioFile audioFile; - std::string smpName = "../../spcsamples/02 Title_"; - - std::stringstream strr; - strr << std::hex << std::setw(2) << std::setfill('0') << ins; - - smpName += strr.str(); - smpName += ".wav"; - - audioFile.load(smpName.c_str()); - int numSamples = audioFile.getNumSamplesPerChannel(); - - glbTheLogger.logMsg("Loaded sample "+strr.str() + " of len " + std::to_string(numSamples)); - - insArray[ins].len = numSamples; - insArray[ins].data = new float[numSamples]; - for (unsigned int s = 0;s < numSamples;s++) - { - insArray[ins].data[s]= audioFile.samples[0][s]; - } - } + glbTheLogger.logMsg("Audio system inited; sample rate:"+std::to_string((int)sampleRate)); } void audioSystem::feedAudiobuf(float l, float r) @@ -102,70 +71,13 @@ void audioSystem::feedAudiobuf(float l, float r) audioVector.push_back(l); audioVector.push_back(r); - audioBuf[bufPos] = l; + /*audioBuf[bufPos] = l; audioBuf[bufPos+1] = r; bufPos += 2; - if (bufPos >= (audioBufLen*2)) bufPos = 0; - - /*if (outwavpos == -1) return; - - if ((outwavpos / 2) < outwavdim) - { - outwavbuf[outwavpos] = l; - outwavbuf[outwavpos + 1] = r; - outwavpos += 2; - } - else - { - AudioFile a; - a.setNumChannels(2); - a.setNumSamplesPerChannel(44100); - a.samples[0].resize(outwavdim); - a.samples[1].resize(outwavdim); - - for (unsigned long int k = 0;k < outwavdim;k++) - { - a.samples[0][k] = outwavbuf[k * 2]; - a.samples[1][k] = outwavbuf[(k * 2)+1]; - } - - a.save("d:\\prova\\mar10.wav", AudioFileFormat::Wave); - - outwavpos = -1; - }*/ -} - -void audioSystem::updateStream(apu& theAPU) -{ - /*float res = 0.0; - for (unsigned int channel = 0;channel < 8;channel++) - { - if ((theAPU.channels[channel].keyOn)&& (!theAPU.channels[channel].keyOff)) - { - int sampleNum = theAPU.channels[channel].sampleSourceEntry; - if (sampleNum < 0x14) - { - if (theAPU.channels[channel].playingPos < insArray[sampleNum].len) - { - res += insArray[sampleNum].data[(unsigned int)theAPU.channels[channel].playingPos]; - - float finc = ((float)theAPU.channels[channel].samplePitch) / (65536.0/8.0); - - theAPU.channels[channel].playingPos += finc; - } - } - } - } - - res /= 8.0; - - audioBuf[bufPos] = res; - bufPos += 1; - if (bufPos >= 1024) bufPos = 0;*/ + if (bufPos >= (audioBufLen*2)) bufPos = 0;*/ } audioSystem::~audioSystem() { BASS_Free(); - delete(outwavbuf); } diff --git a/audioSystem.h b/audioSystem.h index 8ad911a..91e48d6 100644 --- a/audioSystem.h +++ b/audioSystem.h @@ -8,16 +8,10 @@ #include "bass/bass.h" #include "apu.h" #include "logger.h" -#include "include/AudioFile.h" +//#include "include/AudioFile.h" class apu; -struct spcInstrument -{ - float* data; - unsigned int len = 0; -}; - class audioSystem { private: @@ -27,23 +21,14 @@ class audioSystem const unsigned int audioBufLen = 1024; float audioBuf[1024*2]; - float* outwavbuf; - signed long int outwavpos = 0; - const unsigned long int outwavdim = 65536*2; - std::vector audioStream; - spcInstrument insArray[0x14]; - - void loadTestSamples(); - public: bool audioSystemInited = false; float sampleRate = 0; audioSystem(); - void updateStream(apu& theAPU); void feedAudiobuf(float l, float r); ~audioSystem(); }; diff --git a/example_win32_opengl3.vcxproj b/example_win32_opengl3.vcxproj index ecfe2a1..ddee142 100644 --- a/example_win32_opengl3.vcxproj +++ b/example_win32_opengl3.vcxproj @@ -139,6 +139,7 @@ ..\..;..\..\backends; false /utf-8 %(AdditionalOptions) + stdcpp17 true diff --git a/imfilebrowser.h b/imfilebrowser.h new file mode 100644 index 0000000..aeeaec7 --- /dev/null +++ b/imfilebrowser.h @@ -0,0 +1,1068 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef IMGUI_VERSION +# error "include imgui.h before this header" +#endif + +using ImGuiFileBrowserFlags = int; + +enum ImGuiFileBrowserFlags_ +{ + ImGuiFileBrowserFlags_SelectDirectory = 1 << 0, // select directory instead of regular file + ImGuiFileBrowserFlags_EnterNewFilename = 1 << 1, // allow user to enter new filename when selecting regular file + ImGuiFileBrowserFlags_NoModal = 1 << 2, // file browsing window is modal by default. specify this to use a popup window + ImGuiFileBrowserFlags_NoTitleBar = 1 << 3, // hide window title bar + ImGuiFileBrowserFlags_NoStatusBar = 1 << 4, // hide status bar at the bottom of browsing window + ImGuiFileBrowserFlags_CloseOnEsc = 1 << 5, // close file browser when pressing 'ESC' + ImGuiFileBrowserFlags_CreateNewDir = 1 << 6, // allow user to create new directory + ImGuiFileBrowserFlags_MultipleSelection = 1 << 7, // allow user to select multiple files. this will hide ImGuiFileBrowserFlags_EnterNewFilename + ImGuiFileBrowserFlags_HideRegularFiles = 1 << 8, // hide regular files when ImGuiFileBrowserFlags_SelectDirectory is enabled + ImGuiFileBrowserFlags_ConfirmOnEnter = 1 << 9, // confirm selection when pressnig 'ENTER' +}; + +namespace ImGui +{ + class FileBrowser + { + public: + + // pwd is set to current working directory by default + explicit FileBrowser(ImGuiFileBrowserFlags flags = 0); + + FileBrowser(const FileBrowser ©From); + + FileBrowser &operator=(const FileBrowser ©From); + + // set the window position (in pixels) + // default is centered + void SetWindowPos(int posx, int posy) noexcept; + + // set the window size (in pixels) + // default is (700, 450) + void SetWindowSize(int width, int height) noexcept; + + // set the window title text + void SetTitle(std::string title); + + // open the browsing window + void Open(); + + // close the browsing window + void Close(); + + // the browsing window is opened or not + bool IsOpened() const noexcept; + + // display the browsing window if opened + void Display(); + + // returns true when there is a selected filename + bool HasSelected() const noexcept; + + // set current browsing directory + bool SetPwd(const std::filesystem::path &pwd = + std::filesystem::current_path()); + + // get current browsing directory + const std::filesystem::path &GetPwd() const noexcept; + + // returns selected filename. make sense only when HasSelected returns true + // when ImGuiFileBrowserFlags_MultipleSelection is enabled, only one of + // selected filename will be returned + std::filesystem::path GetSelected() const; + + // returns all selected filenames. + // when ImGuiFileBrowserFlags_MultipleSelection is enabled, use this + // instead of GetSelected + std::vector GetMultiSelected() const; + + // set selected filename to empty + void ClearSelected(); + + // (optional) set file type filters. eg. { ".h", ".cpp", ".hpp" } + // ".*" matches any file types + void SetTypeFilters(const std::vector &typeFilters); + + // set currently applied type filter + // default value is 0 (the first type filter) + void SetCurrentTypeFilterIndex(int index); + + // when ImGuiFileBrowserFlags_EnterNewFilename is set + // this function will pre-fill the input dialog with a filename. + void SetInputName(std::string_view input); + + private: + + template + struct ScopeGuard + { + ScopeGuard(Functor&& t) : func(std::move(t)) { } + + ~ScopeGuard() { func(); } + + private: + + Functor func; + }; + + struct FileRecord + { + bool isDir = false; + std::filesystem::path name; + std::string showName; + std::filesystem::path extension; + }; + + static std::string ToLower(const std::string &s); + + void UpdateFileRecords(); + + void SetPwdUncatched(const std::filesystem::path &pwd); + + bool IsExtensionMatched(const std::filesystem::path &extension) const; + + void ClearRangeSelectionState(); + +#ifdef _WIN32 + static std::uint32_t GetDrivesBitMask(); +#endif + + // for c++17 compatibility + +#if defined(__cpp_lib_char8_t) + static std::string u8StrToStr(std::u8string s); +#endif + static std::string u8StrToStr(std::string s); + + int width_; + int height_; + int posX_; + int posY_; + ImGuiFileBrowserFlags flags_; + + std::string title_; + std::string openLabel_; + + bool openFlag_; + bool closeFlag_; + bool isOpened_; + bool ok_; + bool posIsSet_; + + std::string statusStr_; + + std::vector typeFilters_; + unsigned int typeFilterIndex_; + bool hasAllFilter_; + + std::filesystem::path pwd_; + std::set selectedFilenames_; + unsigned int rangeSelectionStart_; // enable range selection when shift is pressed + + std::vector fileRecords_; + + // IMPROVE: truncate when selectedFilename_.length() > inputNameBuf_.size() - 1 + static constexpr size_t INPUT_NAME_BUF_SIZE = 512; + std::unique_ptr> inputNameBuf_; + + std::string openNewDirLabel_; + std::unique_ptr> newDirNameBuf_; + +#ifdef _WIN32 + uint32_t drives_; +#endif + }; +} // namespace ImGui + +inline ImGui::FileBrowser::FileBrowser(ImGuiFileBrowserFlags flags) + : width_(700), height_(450), posX_(0), posY_(0), flags_(flags), + openFlag_(false), closeFlag_(false), isOpened_(false), ok_(false), posIsSet_(false), + rangeSelectionStart_(0), inputNameBuf_(std::make_unique>()) +{ + if(flags_ & ImGuiFileBrowserFlags_CreateNewDir) + { + newDirNameBuf_ = + std::make_unique>(); + } + + inputNameBuf_->front() = '\0'; + inputNameBuf_->back() = '\0'; + SetTitle("file browser"); + SetPwd(std::filesystem::current_path()); + + typeFilters_.clear(); + typeFilterIndex_ = 0; + hasAllFilter_ = false; + +#ifdef _WIN32 + drives_ = GetDrivesBitMask(); +#endif +} + +inline ImGui::FileBrowser::FileBrowser(const FileBrowser ©From) + : FileBrowser() +{ + *this = copyFrom; +} + +inline ImGui::FileBrowser &ImGui::FileBrowser::operator=( + const FileBrowser ©From) +{ + width_ = copyFrom.width_; + height_ = copyFrom.height_; + + posX_ = copyFrom.posX_; + posY_ = copyFrom.posY_; + + flags_ = copyFrom.flags_; + SetTitle(copyFrom.title_); + + openFlag_ = copyFrom.openFlag_; + closeFlag_ = copyFrom.closeFlag_; + isOpened_ = copyFrom.isOpened_; + ok_ = copyFrom.ok_; + posIsSet_ = copyFrom.posIsSet_; + + statusStr_ = ""; + + typeFilters_ = copyFrom.typeFilters_; + typeFilterIndex_ = copyFrom.typeFilterIndex_; + hasAllFilter_ = copyFrom.hasAllFilter_; + + pwd_ = copyFrom.pwd_; + selectedFilenames_ = copyFrom.selectedFilenames_; + rangeSelectionStart_ = copyFrom.rangeSelectionStart_; + + fileRecords_ = copyFrom.fileRecords_; + + *inputNameBuf_ = *copyFrom.inputNameBuf_; + + openNewDirLabel_ = copyFrom.openNewDirLabel_; + if(flags_ & ImGuiFileBrowserFlags_CreateNewDir) + { + newDirNameBuf_ = std::make_unique< + std::array>(); + *newDirNameBuf_ = *copyFrom.newDirNameBuf_; + } + +#ifdef _WIN32 + drives_ = copyFrom.drives_; +#endif + + return *this; +} + +inline void ImGui::FileBrowser::SetWindowPos(int posx, int posy) noexcept +{ + posX_ = posx; + posY_ = posy; + posIsSet_ = true; +} + +inline void ImGui::FileBrowser::SetWindowSize(int width, int height) noexcept +{ + assert(width > 0 && height > 0); + width_ = width; + height_ = height; +} + +inline void ImGui::FileBrowser::SetTitle(std::string title) +{ + title_ = std::move(title); + openLabel_ = title_ + "##filebrowser_" + + std::to_string(reinterpret_cast(this)); + openNewDirLabel_ = "new dir##new_dir_" + + std::to_string(reinterpret_cast(this)); +} + +inline void ImGui::FileBrowser::Open() +{ + UpdateFileRecords(); + ClearSelected(); + statusStr_ = std::string(); + openFlag_ = true; + closeFlag_ = false; +} + +inline void ImGui::FileBrowser::Close() +{ + ClearSelected(); + statusStr_ = std::string(); + closeFlag_ = true; + openFlag_ = false; +} + +inline bool ImGui::FileBrowser::IsOpened() const noexcept +{ + return isOpened_; +} + +inline void ImGui::FileBrowser::Display() +{ + PushID(this); + ScopeGuard exitThis([this] + { + openFlag_ = false; + closeFlag_ = false; + PopID(); + }); + + if(openFlag_) + { + OpenPopup(openLabel_.c_str()); + } + isOpened_ = false; + + // open the popup window + + if(openFlag_ && (flags_ & ImGuiFileBrowserFlags_NoModal)) + { + if(posIsSet_) + { + SetNextWindowPos( + ImVec2(static_cast(posX_), static_cast(posY_))); + } + SetNextWindowSize( + ImVec2(static_cast(width_), static_cast(height_))); + } + else + { + if(posIsSet_) + { + SetNextWindowPos( + ImVec2(static_cast(posX_), static_cast(posY_)), + ImGuiCond_FirstUseEver); + } + SetNextWindowSize( + ImVec2(static_cast(width_), static_cast(height_)), + ImGuiCond_FirstUseEver); + } + if(flags_ & ImGuiFileBrowserFlags_NoModal) + { + if(!BeginPopup(openLabel_.c_str())) + { + return; + } + } + else if(!BeginPopupModal(openLabel_.c_str(), nullptr, + flags_ & ImGuiFileBrowserFlags_NoTitleBar ? + ImGuiWindowFlags_NoTitleBar : 0)) + { + return; + } + + isOpened_ = true; + ScopeGuard endPopup([] { EndPopup(); }); + + // display elements in pwd + +#ifdef _WIN32 + char currentDrive = static_cast(pwd_.c_str()[0]); + char driveStr[] = { currentDrive, ':', '\0' }; + + PushItemWidth(4 * GetFontSize()); + if(BeginCombo("##select_drive", driveStr)) + { + ScopeGuard guard([&] { EndCombo(); }); + + for(int i = 0; i < 26; ++i) + { + if(!(drives_ & (1 << i))) + { + continue; + } + + char driveCh = static_cast('A' + i); + char selectableStr[] = { driveCh, ':', '\0' }; + bool selected = currentDrive == driveCh; + + if(Selectable(selectableStr, selected) && !selected) + { + char newPwd[] = { driveCh, ':', '\\', '\0' }; + SetPwd(newPwd); + } + } + } + PopItemWidth(); + + SameLine(); +#endif + + int secIdx = 0, newPwdLastSecIdx = -1; + for(const auto &sec : pwd_) + { +#ifdef _WIN32 + if(secIdx == 1) + { + ++secIdx; + continue; + } +#endif + + PushID(secIdx); + if(secIdx > 0) + { + SameLine(); + } + if(SmallButton(u8StrToStr(sec.u8string()).c_str())) + { + newPwdLastSecIdx = secIdx; + } + PopID(); + + ++secIdx; + } + + if(newPwdLastSecIdx >= 0) + { + int i = 0; + std::filesystem::path newPwd; + for(const auto &sec : pwd_) + { + if(i++ > newPwdLastSecIdx) + { + break; + } + newPwd /= sec; + } + +#ifdef _WIN32 + if(newPwdLastSecIdx == 0) + { + newPwd /= "\\"; + } +#endif + + SetPwd(newPwd); + } + + SameLine(); + + if(SmallButton("*")) + { + UpdateFileRecords(); + + std::set newSelectedFilenames; + for(auto &name : selectedFilenames_) + { + auto it = std::find_if( + fileRecords_.begin(), fileRecords_.end(), + [&](const FileRecord &record) + { + return name == record.name; + }); + if(it != fileRecords_.end()) + { + newSelectedFilenames.insert(name); + } + } + + if(inputNameBuf_ && (*inputNameBuf_)[0]) + { + newSelectedFilenames.insert(inputNameBuf_->data()); + } + } + + bool focusOnInputText = false; + if(newDirNameBuf_) + { + SameLine(); + if(SmallButton("+")) + { + OpenPopup(openNewDirLabel_.c_str()); + (*newDirNameBuf_)[0] = '\0'; + } + + if(BeginPopup(openNewDirLabel_.c_str())) + { + ScopeGuard endNewDirPopup([] { EndPopup(); }); + + InputText("name", newDirNameBuf_->data(), newDirNameBuf_->size()); + focusOnInputText |= IsItemFocused(); + SameLine(); + + if(Button("ok") && (*newDirNameBuf_)[0] != '\0') + { + ScopeGuard closeNewDirPopup([] { CloseCurrentPopup(); }); + if(create_directory(pwd_ / newDirNameBuf_->data())) + { + UpdateFileRecords(); + } + else + { + statusStr_ = "failed to create " + + std::string(newDirNameBuf_->data()); + } + } + } + } + + // browse files in a child window + + float reserveHeight = GetFrameHeightWithSpacing(); + std::filesystem::path newPwd; bool setNewPwd = false; + if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) && + (flags_ & ImGuiFileBrowserFlags_EnterNewFilename)) + reserveHeight += GetFrameHeightWithSpacing(); + + { + BeginChild("ch", ImVec2(0, -reserveHeight), true, + (flags_ & ImGuiFileBrowserFlags_NoModal) ? + ImGuiWindowFlags_AlwaysHorizontalScrollbar : 0); + ScopeGuard endChild([] { EndChild(); }); + + const bool shouldHideRegularFiles = + (flags_ & ImGuiFileBrowserFlags_HideRegularFiles) && + (flags_ & ImGuiFileBrowserFlags_SelectDirectory); + + for(unsigned int rscIndex = 0; rscIndex < fileRecords_.size(); ++rscIndex) + { + auto &rsc = fileRecords_[rscIndex]; + if(!rsc.isDir && shouldHideRegularFiles) + { + continue; + } + if(!rsc.isDir && !IsExtensionMatched(rsc.extension)) + { + continue; + } + if(!rsc.name.empty() && rsc.name.c_str()[0] == '$') + { + continue; + } + + const bool selected = selectedFilenames_.find(rsc.name) + != selectedFilenames_.end(); + if(Selectable(rsc.showName.c_str(), selected, + ImGuiSelectableFlags_DontClosePopups)) + { + const bool wantDir = flags_ & ImGuiFileBrowserFlags_SelectDirectory; + const bool canSelect = rsc.name != ".." && rsc.isDir == wantDir; + const bool rangeSelect = + canSelect && GetIO().KeyShift && + rangeSelectionStart_ < fileRecords_.size() && + (flags_ & ImGuiFileBrowserFlags_MultipleSelection) && + IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); + const bool multiSelect = + !rangeSelect && GetIO().KeyCtrl && + (flags_ & ImGuiFileBrowserFlags_MultipleSelection) && + IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); + + if(rangeSelect) + { + const unsigned int first = (std::min)(rangeSelectionStart_, rscIndex); + const unsigned int last = (std::max)(rangeSelectionStart_, rscIndex); + selectedFilenames_.clear(); + for(unsigned int i = first; i <= last; ++i) + { + if(fileRecords_[i].isDir != wantDir) + { + continue; + } + if(!wantDir && !IsExtensionMatched(fileRecords_[i].extension)) + { + continue; + } + selectedFilenames_.insert(fileRecords_[i].name); + } + } + else if(selected) + { + if(!multiSelect) + { + selectedFilenames_ = { rsc.name }; + rangeSelectionStart_ = rscIndex; + } + else + { + selectedFilenames_.erase(rsc.name); + } + (*inputNameBuf_)[0] = '\0'; + } + else if(canSelect) + { + if(multiSelect) + { + selectedFilenames_.insert(rsc.name); + } + else + { + selectedFilenames_ = { rsc.name }; + } + if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory)) + { +#ifdef _MSC_VER + strcpy_s( + inputNameBuf_->data(), inputNameBuf_->size(), + u8StrToStr(rsc.name.u8string()).c_str()); +#else + std::strncpy(inputNameBuf_->data(), + u8StrToStr(rsc.name.u8string()).c_str(), + inputNameBuf_->size() - 1); +#endif + } + rangeSelectionStart_ = rscIndex; + } + else + { + if(!multiSelect) + { + selectedFilenames_.clear(); + } + } + } + + if(IsItemClicked(0) && IsMouseDoubleClicked(0)) + { + if(rsc.isDir) + { + setNewPwd = true; + newPwd = (rsc.name != "..") ? (pwd_ / rsc.name) : + pwd_.parent_path(); + } + else if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory)) + { + selectedFilenames_ = { rsc.name }; + ok_ = true; + CloseCurrentPopup(); + } + } + } + } + + if(setNewPwd) + { + SetPwd(newPwd); + } + + if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) && + (flags_ & ImGuiFileBrowserFlags_EnterNewFilename)) + { + PushID(this); + ScopeGuard popTextID([] { PopID(); }); + + PushItemWidth(-1); + if(InputText("", inputNameBuf_->data(), inputNameBuf_->size()) && + inputNameBuf_->at(0) != '\0') + { + selectedFilenames_ = { inputNameBuf_->data() }; + } + focusOnInputText |= IsItemFocused(); + PopItemWidth(); + } + + if(!focusOnInputText) + { + const bool selectAll = (flags_ & ImGuiFileBrowserFlags_MultipleSelection) && + IsKeyPressed(ImGuiKey_A) && (IsKeyDown(ImGuiKey_LeftCtrl) || + IsKeyDown(ImGuiKey_RightCtrl)); + if(selectAll) + { + const bool needDir = flags_ & ImGuiFileBrowserFlags_SelectDirectory; + selectedFilenames_.clear(); + for(size_t i = 1; i < fileRecords_.size(); ++i) + { + auto &record = fileRecords_[i]; + if(record.isDir == needDir && + (needDir || IsExtensionMatched(record.extension))) + { + selectedFilenames_.insert(record.name); + } + } + } + } + + const bool enter = + (flags_ & ImGuiFileBrowserFlags_ConfirmOnEnter) && + IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && + IsKeyPressed(ImGuiKey_Enter); + if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory)) + { + if((Button(" ok ") || enter) && !selectedFilenames_.empty()) + { + ok_ = true; + CloseCurrentPopup(); + } + } + else + { + if(Button(" ok ") || enter) + { + ok_ = true; + CloseCurrentPopup(); + } + } + + SameLine(); + + bool shouldExit = + Button("cancel") || closeFlag_ || + ((flags_ & ImGuiFileBrowserFlags_CloseOnEsc) && + IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && + IsKeyPressed(ImGuiKey_Escape)); + if(shouldExit) + { + CloseCurrentPopup(); + } + + if(!statusStr_.empty() && !(flags_ & ImGuiFileBrowserFlags_NoStatusBar)) + { + SameLine(); + Text("%s", statusStr_.c_str()); + } + + if(!typeFilters_.empty()) + { + SameLine(); + PushItemWidth(8 * GetFontSize()); + if(BeginCombo( + "##type_filters", typeFilters_[typeFilterIndex_].c_str())) + { + ScopeGuard guard([&] { EndCombo(); }); + + for(size_t i = 0; i < typeFilters_.size(); ++i) + { + bool selected = i == typeFilterIndex_; + if(Selectable(typeFilters_[i].c_str(), selected) && !selected) + { + typeFilterIndex_ = static_cast(i); + } + } + } + PopItemWidth(); + } +} + +inline bool ImGui::FileBrowser::HasSelected() const noexcept +{ + return ok_; +} + +inline bool ImGui::FileBrowser::SetPwd(const std::filesystem::path &pwd) +{ + try + { + SetPwdUncatched(pwd); + return true; + } + catch(const std::exception &err) + { + statusStr_ = std::string("last error: ") + err.what(); + } + catch(...) + { + statusStr_ = "last error: unknown"; + } + + SetPwdUncatched(std::filesystem::current_path()); + return false; +} + +inline const class std::filesystem::path &ImGui::FileBrowser::GetPwd() const noexcept +{ + return pwd_; +} + +inline std::filesystem::path ImGui::FileBrowser::GetSelected() const +{ + // when ok_ is true, selectedFilenames_ may be empty if SelectDirectory + // is enabled. return pwd in that case. + if(selectedFilenames_.empty()) + { + return pwd_; + } + return pwd_ / *selectedFilenames_.begin(); +} + +inline std::vector + ImGui::FileBrowser::GetMultiSelected() const +{ + if(selectedFilenames_.empty()) + { + return { pwd_ }; + } + + std::vector ret; + ret.reserve(selectedFilenames_.size()); + for(auto &s : selectedFilenames_) + { + ret.push_back(pwd_ / s); + } + + return ret; +} + +inline void ImGui::FileBrowser::ClearSelected() +{ + selectedFilenames_.clear(); + (*inputNameBuf_)[0] = '\0'; + ok_ = false; +} + +inline void ImGui::FileBrowser::SetTypeFilters( + const std::vector &_typeFilters) +{ + typeFilters_.clear(); + + // remove duplicate filter names due to case unsensitivity on windows + +#ifdef _WIN32 + + std::vector typeFilters; + for(auto &rawFilter : _typeFilters) + { + std::string lowerFilter = ToLower(rawFilter); + auto it = std::find(typeFilters.begin(), typeFilters.end(), lowerFilter); + if(it == typeFilters.end()) + { + typeFilters.push_back(std::move(lowerFilter)); + } + } + +#else + + auto &typeFilters = _typeFilters; + +#endif + + // insert auto-generated filter + hasAllFilter_ = false; + if(typeFilters.size() > 1) + { + hasAllFilter_ = true; + std::string allFiltersName = std::string(); + for(size_t i = 0; i < typeFilters.size(); ++i) + { + if(typeFilters[i] == std::string_view(".*")) + { + hasAllFilter_ = false; + break; + } + + if(i > 0) + { + allFiltersName += ","; + } + allFiltersName += typeFilters[i]; + } + + if(hasAllFilter_) + { + typeFilters_.push_back(std::move(allFiltersName)); + } + } + + std::copy( + typeFilters.begin(), typeFilters.end(), + std::back_inserter(typeFilters_)); + + typeFilterIndex_ = 0; +} + +inline void ImGui::FileBrowser::SetCurrentTypeFilterIndex(int index) +{ + typeFilterIndex_ = static_cast(index); +} + +inline void ImGui::FileBrowser::SetInputName(std::string_view input) +{ + if(flags_ & ImGuiFileBrowserFlags_EnterNewFilename) + { + if(input.size() >= static_cast(INPUT_NAME_BUF_SIZE)) + { + // If input doesn't fit trim off characters + input = input.substr(0, INPUT_NAME_BUF_SIZE - 1); + } + std::copy(input.begin(), input.end(), inputNameBuf_->begin()); + inputNameBuf_->at(input.size()) = '\0'; + selectedFilenames_ = { inputNameBuf_->data() }; + } +} + +inline std::string ImGui::FileBrowser::ToLower(const std::string &s) +{ + std::string ret = s; + for(char &c : ret) + { + c = static_cast(std::tolower(c)); + } + return ret; +} + +inline void ImGui::FileBrowser::UpdateFileRecords() +{ + fileRecords_ = { FileRecord{ true, "..", "[D] ..", "" } }; + + for(auto &p : std::filesystem::directory_iterator(pwd_)) + { + FileRecord rcd; + + if(p.is_regular_file()) + { + rcd.isDir = false; + } + else if(p.is_directory()) + { + rcd.isDir = true; + } + else + { + continue; + } + + rcd.name = p.path().filename(); + if(rcd.name.empty()) + { + continue; + } + + rcd.extension = p.path().filename().extension(); + + rcd.showName = (rcd.isDir ? "[D] " : "[F] ") + + u8StrToStr(p.path().filename().u8string()); + fileRecords_.push_back(rcd); + } + + std::sort(fileRecords_.begin(), fileRecords_.end(), + [](const FileRecord &L, const FileRecord &R) + { + return (L.isDir ^ R.isDir) ? L.isDir : (L.name < R.name); + }); + + ClearRangeSelectionState(); +} + +inline void ImGui::FileBrowser::SetPwdUncatched(const std::filesystem::path &pwd) +{ + pwd_ = absolute(pwd); + UpdateFileRecords(); + selectedFilenames_.clear(); + (*inputNameBuf_)[0] = '\0'; +} + +inline bool ImGui::FileBrowser::IsExtensionMatched( + const std::filesystem::path &_extension) const +{ +#ifdef _WIN32 + std::filesystem::path extension = ToLower(u8StrToStr(_extension.u8string())); +#else + auto &extension = _extension; +#endif + + // no type filters + if(typeFilters_.empty()) + { + return true; + } + + // invalid type filter index + if(static_cast(typeFilterIndex_) >= typeFilters_.size()) + { + return true; + } + + // all type filters + if(hasAllFilter_ && typeFilterIndex_ == 0) + { + for(size_t i = 1; i < typeFilters_.size(); ++i) + { + if(extension == typeFilters_[i]) + { + return true; + } + } + return false; + } + + // universal filter + if(typeFilters_[typeFilterIndex_] == std::string_view(".*")) + { + return true; + } + + // regular filter + return extension == typeFilters_[typeFilterIndex_]; +} + +inline void ImGui::FileBrowser::ClearRangeSelectionState() +{ + rangeSelectionStart_ = 9999999; + const bool dir = flags_ & ImGuiFileBrowserFlags_SelectDirectory; + for(unsigned int i = 1; i < fileRecords_.size(); ++i) + { + if(fileRecords_[i].isDir == dir) + { + if(!dir && !IsExtensionMatched(fileRecords_[i].extension)) + { + continue; + } + rangeSelectionStart_ = i; + break; + } + } +} + +#if defined(__cpp_lib_char8_t) +inline std::string ImGui::FileBrowser::u8StrToStr(std::u8string s) +{ + return std::string(s.begin(), s.end()); +} +#endif + +inline std::string ImGui::FileBrowser::u8StrToStr(std::string s) +{ + return s; +} + +#ifdef _WIN32 + +#ifndef _INC_WINDOWS + +#ifndef WIN32_LEAN_AND_MEAN + +#define IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN + +#endif // #ifndef WIN32_LEAN_AND_MEAN + +#include + +#ifdef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN +#undef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#endif // #ifdef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN + +#endif // #ifdef _INC_WINDOWS + +inline std::uint32_t ImGui::FileBrowser::GetDrivesBitMask() +{ + DWORD mask = GetLogicalDrives(); + uint32_t ret = 0; + for(int i = 0; i < 26; ++i) + { + if(!(mask & (1 << i))) + { + continue; + } + char rootName[4] = { static_cast('A' + i), ':', '\\', '\0' }; + UINT type = GetDriveTypeA(rootName); + if(type == DRIVE_REMOVABLE || type == DRIVE_FIXED || type == DRIVE_REMOTE) + { + ret |= (1 << i); + } + } + return ret; +} + +#endif diff --git a/imgui.ini b/imgui.ini index 1b78adf..0f397d5 100644 --- a/imgui.ini +++ b/imgui.ini @@ -27,8 +27,8 @@ Pos=99,123 Size=191,48 [Window][ROM loading log window] -Pos=533,648 -Size=460,99 +Pos=513,606 +Size=533,147 [Window][5A22 Debuggah] Pos=19,174 @@ -55,8 +55,8 @@ Pos=1069,530 Size=487,189 [Window][Palette Window] -Pos=494,622 -Size=525,194 +Pos=6,722 +Size=472,194 Collapsed=1 [Window][VRAM viewer] @@ -65,12 +65,12 @@ Size=528,154 Collapsed=1 [Window][SNES TV Output] -Pos=492,113 +Pos=509,113 Size=535,489 [Window][Memory viewer] -Pos=494,608 -Size=527,482 +Pos=7,699 +Size=474,482 Collapsed=1 [Window][Appo and tests window] @@ -85,6 +85,294 @@ Size=486,336 Pos=1068,5 Size=488,172 +[Window][Load SNES ROM##filebrowser_459392919632] +Pos=400,220 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_316933318080] +Pos=407,268 +Size=700,450 + +[Window][file browser##filebrowser_201428218688] +Pos=432,155 +Size=700,450 + +[Window][file browser##filebrowser_948727426544] +Pos=432,155 +Size=700,450 + +[Window][file browser##filebrowser_136099835792] +Pos=432,155 +Size=700,450 + +[Window][file browser##filebrowser_884246229344] +Pos=432,155 +Size=700,450 + +[Window][file browser##filebrowser_152140952112] +Pos=432,155 +Size=700,450 + +[Window][file browser##filebrowser_575386070224] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_159915093888] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_664544391104] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_49278463600] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_93160649424] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_157144756000] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_784329519120] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_482438263808] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_825111195264] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_86334616448] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_330036063984] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_1018126840464] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_1098569724032] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_285928762800] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_766182862016] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_44957611056] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_594415629152] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_128906997856] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_1097883104208] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_286952238560] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_468484206368] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_655694409040] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_387987648656] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_912119475536] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_764708564256] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_753060983328] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_684145028848] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_614185480192] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_199457550752] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_894200034272] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_1072369939504] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_570589884944] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_116773532064] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_806511357152] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_771851726144] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_338886702176] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_284597071984] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_251745185200] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_231652372160] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_907407831344] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_691383743296] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_1040704254480] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_13621965088] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_752732384768] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_928072511872] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_777874485312] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_704134426176] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_602802532384] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_677517374352] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_1043481932048] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_767814446448] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_636167827456] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_77689958848] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_937715216256] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_356205179136] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_108862877232] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_1026793846272] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_373068378416] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_838945649872] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_442877521824] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_603320332832] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_133784580832] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_901344637472] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_776909795488] +Pos=432,155 +Size=700,450 + +[Window][Load SNES ROM##filebrowser_54785389840] +Pos=432,155 +Size=700,450 + [Table][0x64418101,3] RefScale=13 Column 0 Width=63 diff --git a/main.cpp b/main.cpp index 6305481..7ed23d7 100644 --- a/main.cpp +++ b/main.cpp @@ -21,6 +21,8 @@ #include #include +#include "imfilebrowser.h" + #include "audioSystem.h" #include "romLoader.h" #include "mmu.h" @@ -668,7 +670,7 @@ void displayMemoryWindow(mmu& theMMU,ppu& thePPU,int& baseAddress) ImGui::End(); } -void displayAppoWindow(ppu& thePPU, mmu& ourMMU, debugger5a22& theDebugger5a22, debuggerSPC700& theDebuggerSPC) +void displayAppoWindow(cpu5a22& theCPU,ppu& thePPU, mmu& ourMMU, debugger5a22& theDebugger5a22, debuggerSPC700& theDebuggerSPC, ImGui::FileBrowser& fileDialog, std::vector& romLoadingLog,int& emustatus) { ImGui::Begin("Appo and tests window"); ImGui::Text("surFami emu: Super Nintendo lives"); @@ -685,11 +687,52 @@ void displayAppoWindow(ppu& thePPU, mmu& ourMMU, debugger5a22& theDebugger5a22, std::vector* pOpcodeList = theDebugger5a22.getOpcodesList(); std::vector* pSPCOpcodeList = theDebuggerSPC.getOpcodesList(); + // (optional) set browser properties + fileDialog.SetTitle("Load SNES ROM"); + fileDialog.SetTypeFilters({ ".smc", ".sfc" }); + //fileDialog.SetPwd("d:\\prova\\snes\\"); + fileDialog.SetPwd("D:\\romz\\nintendo\\snes\\USA\\"); + if (ImGui::Button("Load rom!")) { + fileDialog.Open(); } ImGui::SameLine(); + fileDialog.Display(); + + if (fileDialog.HasSelected()) + { + std::string romName = fileDialog.GetSelected().string(); + glbTheLogger.logMsg("Ok, trying to load rom:" + romName); + + bool isHiRom = false; + int snesStandard = 0; + romLoader theRomLoader; + if (theRomLoader.loadRom(romName, ourMMU, romLoadingLog, isHiRom, snesStandard)==0) + { + ourMMU.setStandard(snesStandard); + ourMMU.setHiRom(isHiRom); + ourMMU.setStandard(snesStandard); + + theCPU.reset(); + ourMMU.setCPU(theCPU); + } + + // a little help from my friends nop + /*if (romName == "d:\\prova\\snes\\Mickey Mania (E).smc") + { + theMMU.write8(0xb3fab2, 0xea); + theMMU.write8(0xb3fab3, 0xea); + theMMU.write8(0xb3fabf, 0xea); + theMMU.write8(0xb3fac0, 0xea); + }*/ + + emustatus = 1; + + fileDialog.ClearSelected(); + } + if (ImGui::Button("Start 65816 test")) { for (auto& testCase : *pOpcodeList) @@ -796,7 +839,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR lpCmdLine, // - int snesStandard = 0; ppu thePPU; apu theAPU; if (!theAPU.isBootRomLoaded()) @@ -816,183 +858,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR lpCmdLine, mmu theMMU(thePPU,theAPU); std::vector romLoadingLog; - bool isHiRom = false; - - romLoader theRomLoader; - //std::string romName = "d:\\prova\\snes\\HelloWorld.sfc"; - //std::string romName = "d:\\prova\\snes\\BANKWRAM.sfc"; - //std::string romName = "d:\\prova\\snes\\CPUMOV.sfc"; - //std::string romName = "d:\\prova\\snes\\CPUDEC.sfc"; - //std::string romName = "d:\\prova\\snes\\CPUAND.sfc"; // 33 - //std::string romName = "d:\\prova\\snes\\CPUASL.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\ADC\\CPUADC.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\BIT\\CPUBIT.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\BRA\\CPUBRA.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\JMP\\CPUJMP.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\CMP\\CPUCMP.sfc"; // c1 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\EOR\\CPUEOR.sfc"; // 52 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\INC\\CPUINC.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\LDR\\CPULDR.sfc"; // a1 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\LSR\\CPULSR.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\MSC\\CPUMSC.sfc"; // 42 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\ORA\\CPUORA.sfc"; // 01 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\PHL\\CPUPHL.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\PSR\\CPUPSR.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\RET\\CPURET.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\ROL\\CPUROL.sfc"; // 36 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\ROR\\CPUROR.sfc"; // 76 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\SBC\\CPUSBC.sfc"; // f2 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\STR\\CPUSTR.sfc"; // 81 - //std::string romName = "D:\\prova\\snes\\SNES-master\\CPUTest\\CPU\\TRN\\CPUTRN.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\BANK\\HiROMFastROM\\BANKHiROMFastROM.sfc"; isHiRom = true; - //std::string romName = "D:\\prova\\snes\\SNES-master\\SPC700\\Twinkle\\Twinkle.sfc"; - - //std::string romName = "D:\\prova\\snes\\SNES-master\\Compress\\LZ77\\LZ77WRAMGFX\\LZ77WRAMGFX.sfc"; // mode 5 - - //std::string romName = "d:\\prova\\snes\\8x8BG1Map2BPP32x328PAL.sfc"; // mode0 - //std::string romName = "d:\\prova\\snes\\8x8BGMap4BPP32x328PAL.sfc"; // mode3 - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\BGMAP\\8x8\\2BPP\\8x8BG2Map2BPP32x328PAL\\8x8BG2Map2BPP32x328PAL.sfc"; // mode0 - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\BGMAP\\8x8\\8BPP\\TileFlip\\8x8BGMapTileFlip.sfc"; // mode3 - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\BGMAP\\8x8\\8BPP\\32x32\\8x8BGMap8BPP32x32.sfc"; // bg scrolling - //std::string romName = "d:\\prova\\snes\\Rings.sfc"; // mode0 - //std::string romName = "d:\\prova\\snes\\MosaicMode3.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\HDMA\\RedSpaceHDMA\\RedSpaceHDMA.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\HDMA\\HiColor64PerTileRow\\HiColor64PerTileRow.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\HDMA\\WaveHDMA\\WaveHDMA.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\HDMA\\RedSpaceIndirectHDMA\\RedSpaceIndirectHDMA.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\Mode7\\RotZoom\\RotZoom.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\Mode7\\StarWars\\StarWars.sfc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\PPU\\Mode7\\Perspective\\Perspective.sfc"; - //std::string romName = "d:\\prova\\snes\\ctrltest_auto.sfc"; - - //std::string romName = "d:\\prova\\snes\\Ms. Pac-Man (U).smc"; - std::string romName = "d:\\prova\\snes\\Super Mario World (USA).sfc"; - //std::string romName = "d:\\prova\\snes\\Super Mario World (J) [!].sfc"; - //std::string romName = "d:\\prova\\snes\\Ninjawarriors (USA).sfc"; - //std::string romName = "d:\\prova\\snes\\Mario Paint (E) [!].smc"; - //std::string romName = "d:\\prova\\snes\\Mickey Mania (E).smc"; // stuck without patching the code - //std::string romName = "d:\\prova\\snes\\Gradius III (U) [!].smc"; - //std::string romName = "d:\\prova\\snes\\Parodius (Europe).sfc"; // sprites disappear later in the level - //std::string romName = "d:\\prova\\snes\\Parodius Da! - Shinwa kara Owarai e (Japan).sfc"; - //std::string romName = "d:\\prova\\snes\\Mr. Do! (U).smc"; // very slow - //std::string romName = "d:\\prova\\snes\\Tetris & Dr Mario (E) [!].smc"; snesStandard = 1; - //std::string romName = "d:\\prova\\snes\\Arkanoid - Doh it Again (E) [!].smc"; - //std::string romName = "d:\\prova\\snes\\Pac Attack (E).smc"; snesStandard = 1; - //std::string romName = "d:\\prova\\snes\\International Superstar Soccer (U) [!].smc"; - //std::string romName = "d:\\prova\\snes\\Kick Off (E).smc"; - //std::string romName = "d:\\prova\\snes\\Tetris Attack (E).smc"; snesStandard = 1; // slow, maybe opt? - //std::string romName = "d:\\prova\\snes\\Prince of Persia (E) [!].smc"; - //std::string romName = "d:\\prova\\snes\\James Pond's Crazy Sports (E).smc"; - //std::string romName = "d:\\prova\\snes\\Yoshi's Cookie (E).smc"; // SPC 35 - //std::string romName = "d:\\prova\\snes\\Blues Brothers, The (E) [a1].smc"; - //std::string romName = "d:\\prova\\snes\\Incredible Crash Dummies, The (U).smc"; - //std::string romName = "d:\\prova\\snes\\Sim City (E) [!].smc"; - //std::string romName = "d:\\prova\\snes\\Gun Force (E).smc"; snesStandard = 1; // a tad slow - //std::string romName = "d:\\prova\\snes\\Space Invaders (U).smc"; - //std::string romName = "d:\\prova\\snes\\Lawnmower Man, The (E).smc"; // SPC e9 - //std::string romName = "D:\\prova\\snes\\HiRom\\Earthworm Jim (U).smc"; isHiRom = true; - //std::string romName = "d:\\prova\\snes\\Final Fight (U).smc"; // SPC 57 - //std::string romName = "D:\\prova\\snes\\HiRom\\Super Bomberman (U).smc"; isHiRom = true; - //std::string romName = "D:\\prova\\snes\\HiRom\\Wolfenstein 3D (U).smc"; isHiRom = true; - //std::string romName = "d:\\prova\\snes\\F-Zero (U).smc"; snesStandard = 1; - //std::string romName = "d:\\prova\\snes\\Micro Machines (U).smc"; - //std::string romName = "d:\\prova\\snes\\Robocop 3 (U).smc"; - //std::string romName = "d:\\prova\\snes\\Race Drivin' (U).smc"; // SPC 49 - //std::string romName = "d:\\prova\\snes\\Final Fantasy IV (J).smc"; // SPC 0d - //std::string romName = "d:\\prova\\snes\\Final Fantasy 4 (tr).sfc"; - //std::string romName = "d:\\prova\\snes\\Addams Family, The (E).smc"; - //std::string romName = "D:\\prova\\snes\\HiRom\\Donkey Kong Country (V1.1) (E).smc"; isHiRom = true; snesStandard = 1; // missing bg on title screen - //std::string romName = "D:\\prova\\snes\\HiRom\\Donkey Kong Country (USA) (Rev 2).sfc"; isHiRom = true; // missing bg - //std::string romName = "D:\\prova\\snes\\HiRom\\Flashback - The Quest for Identity (U) [!].smc"; isHiRom = true; // a tad slow - //std::string romName = "d:\\prova\\snes\\The Legend Of Zelda - A Link To The Past.smc"; // black floor - //std::string romName = "D:\\romz\\nintendo\\snes\\Earthbound (U).smc"; isHiRom = true; // anti-piracy screen - //std::string romName = "d:\\prova\\snes\\Williams Arcade's Greatest Hits (E) [!].smc"; // a1, SPC a9 - //std::string romName = "d:\\prova\\snes\\Super Back to the Future 2 (J).sfc"; - //std::string romName = "d:\\prova\\snes\\Unirally (E) [!].smc"; - //std::string romName = "d:\\prova\\snes\\Super Turrican (USA).sfc"; - //std::string romName = "d:\\prova\\snes\\Pinball Dreams (E).smc"; - //std::string romName = "d:\\prova\\snes\\Lemmings (E).sfc"; // hdma/irq problems? - //std::string romName = "d:\\prova\\snes\\Chessmaster, The (U).smc"; - //std::string romName = "d:\\prova\\snes\\Super Tennis (V1.1) (E) [!].smc"; - //std::string romName = "D:\\prova\\snes\\HiRom\\Supercooked! (J) (v1.2).sfc"; isHiRom = true; - //std::string romName = "D:\\prova\\snes\\HiRom\\Chrono Trigger (U) [!].smc"; isHiRom = true; - //std::string romName = "d:\\prova\\snes\\Pocky & Rocky (U).smc"; // bad logo screen - //std::string romName = "d:\\prova\\snes\\Animaniacs (U) [!].smc"; // mode 3 missing bg - - // HDMA/HIRQ problems - //std::string romName = "d:\\prova\\snes\\Frogger (U).smc"; snesStandard = 1; // cars are not moving - //std::string romName = "d:\\prova\\snes\\Puzzle Bobble (E).smc"; // mode4, HDMA/HIRQ not working - //std::string romName = "d:\\prova\\snes\\Street Fighter II - The World Warrior (U).smc"; // background problems if HDMA enabled - //std::string romName = "d:\\prova\\snes\\Super Ghouls 'N Ghosts (E).sfc"; // gameplay garbage, HDMA problems - - //std::string romName = "d:\\prova\\snes\\Super Off Road (E) [!].smc"; // 34, a bg remains uncleared, SPC 5b - //std::string romName = "d:\\prova\\snes\\Rock N' Roll Racing (U).smc"; // no bg mode3, corrupted graphics - //std::string romName = "d:\\prova\\snes\\Spectre (E) [!].smc"; - //std::string romName = "D:\\prova\\snes\\SNES-master\\Games\\MonsterFarmJump\\MonsterFarmJump.sfc"; - //std::string romName = "d:\\prova\\snes\\Super Mario All-Stars + Super Mario World (USA).sfc"; // controls don't work - //std::string romName = "d:\\prova\\snes\\Super Mario All-Stars (U) [!].smc"; // no input - //std::string romName = "d:\\prova\\snes\\Tiny Toons - Wild and Wacky Sports (U).smc"; // stuck after player select 0x2137 - //std::string romName = "d:\\prova\\snes\\Monopoly (V1.1) (U).smc"; // wrong controls, sprite at the start - //std::string romName = "d:\\prova\\snes\\R-Type 3 (U).smc"; // better but gets stuck - //std::string romName = "d:\\prova\\snes\\Super Double Dragon (U).smc"; // no input - //std::string romName = "d:\\prova\\snes\\Home Alone (E) [!].smc"; // resets - //std::string romName = "d:\\prova\\snes\\SNES Test Program (U).smc"; // mode 5 - //std::string romName = "d:\\prova\\snes\\SHVC-AGING.sfc"; - //std::string romName = "d:\\prova\\snes\\Spanky's Quest (E).smc"; // sub mode 1,stuck - //std::string romName = "d:\\prova\\snes\\petsciirobotsdemo.sfc"; // stuck - //std::string romName = "d:\\prova\\snes\\Another World (Europe).sfc"; // SPC 38, stuck - //std::string romName = "d:\\prova\\snes\\Out of This World (U).smc"; // jumps to nowhere after introduction of VIRQ - //std::string romName = "d:\\prova\\snes\\Sensible Soccer - International Edition (E).smc"; // blank screen, stuck - - // hiroms - //std::string romName = "D:\\prova\\snes\\HiRom\\Final Fantasy III (USA).sfc"; isHiRom = true; // stuck - //std::string romName = "D:\\prova\\snes\\HiRom\\Diddy's Kong Quest (E).smc"; isHiRom = true; snesStandard = 1; - //std::string romName = "D:\\prova\\snes\\HiRom\\Secret of Mana (Europe).sfc"; isHiRom = true; snesStandard = 1; // stuck 4212, SPC ca - //std::string romName = "D:\\prova\\snes\\HiRom\\Michael Jordan - Chaos in the Windy City (USA).sfc"; isHiRom = true; // missing/bad bg, 13 - - // demos - //std::string romName = "d:\\prova\\snes\\desire_d-zero_snes_pal_revision_2021_oldschool_compo.sfc"; snesStandard = 1; // reads from CGRAM - //std::string romName = "d:\\prova\\snes\\elix-smashit-pal.sfc"; snesStandard = 1; // mode6 - //std::string romName = "D:\\prova\\snes\\demos\\elix-nu-pal.sfc"; snesStandard = 1; - //std::string romName = "D:\\prova\\snes\\demos\\2.68 MHz Demo (PD).sfc"; snesStandard = 1; - //std::string romName = "D:\\prova\\snes\\demos\\DSR_STNICCC_NOFX_SNES_PAL.sfc"; snesStandard = 1; // jumps to nowhere, no mode7 graphics - //std::string romName = "D:\\prova\\snes\\demos\\rse-intro.sfc"; snesStandard = 1; // 42, HDMA wrong palette if bAdr is reloaded, SPC 01 - //std::string romName = "d:\\prova\\snes\\demo_mode3.smc"; isHiRom = true; - - theMMU.setStandard(snesStandard); - theMMU.setHiRom(isHiRom); - thePPU.setStandard(snesStandard); - - if (theRomLoader.loadRom(romName,theMMU,romLoadingLog,isHiRom) != 0) - { - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplWin32_Shutdown(); - ImGui::DestroyContext(); - - CleanupDeviceWGL(hwnd, &g_MainWindow); - wglDeleteContext(g_hRC); - ::DestroyWindow(hwnd); - ::UnregisterClassW(wc.lpszClassName, wc.hInstance); - - return 1; - } - - // a little help from my friends nop - if (romName == "d:\\prova\\snes\\Mickey Mania (E).smc") - { - theMMU.write8(0xb3fab2, 0xea); - theMMU.write8(0xb3fab3, 0xea); - theMMU.write8(0xb3fabf, 0xea); - theMMU.write8(0xb3fac0, 0xea); - } // debugger5a22 theDebugger5a22; debuggerSPC700 theDebuggerSPC700; cpu5a22 theCPU(&theMMU,false); - theCPU.reset(); - theMMU.setCPU(theCPU); audioSystem theAudioSys; if (!theAudioSys.audioSystemInited) @@ -1027,7 +898,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR lpCmdLine, jumpToAppoBuf[0] = '\0'; int baseMemoryAddress = 0x800; unsigned long int totCPUCycles = 0; - int emustatus = 0; // 0 debugging, 1 running, -1 no rom loaded + int emustatus = -1; // 0 debugging, 1 running, -1 no rom loaded + ImGui::FileBrowser fileDialog; while (!done) { @@ -1181,7 +1053,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR lpCmdLine, bool rushSPC = false; unsigned short int rushToSPCAddress = 0; - displayAppoWindow(thePPU, theMMU, theDebugger5a22,theDebuggerSPC700); + displayAppoWindow(theCPU,thePPU, theMMU, theDebugger5a22,theDebuggerSPC700, fileDialog,romLoadingLog, emustatus); displayRomLoadingLogWindow(romLoadingLog); displayDebugWindow(theCPU, theDebugger5a22,theMMU,isDebugWindowFocused,rush,rushToAddress,jumpToAppoBuf,totCPUCycles,emustatus,thePPU); displaySPCDebugWindow(thePPU, theMMU, theCPU,theAPU, theDebuggerSPC700,rushSPC,rushToSPCAddress,emustatus,theAudioSys); diff --git a/ppu.cpp b/ppu.cpp index ac6c0f2..ea0d78a 100644 --- a/ppu.cpp +++ b/ppu.cpp @@ -1233,8 +1233,8 @@ void ppu::calculateMode7Starts(int y) unsigned char ppu::getPixelForMode7(int x, int layer, bool priority) { - priority++; - layer++; + //priority++; + //layer++; unsigned char rx = (unsigned char)(m7xFlip ? 255 - x : x); int xPos = (m7startX + m7matrix[0] * rx) >> 8; diff --git a/romLoader.cpp b/romLoader.cpp index a0fc34e..a2b18bb 100644 --- a/romLoader.cpp +++ b/romLoader.cpp @@ -23,7 +23,8 @@ std::vector romLoader::readFile(std::string& filename,int& error) file.seekg(0, std::ios::end); fileSize = file.tellg(); - if (strstr(filename.c_str(), ".smc")) + if ((fileSize%1024)!=0) + //if (strstr(filename.c_str(), ".smc")) { file.seekg(512, std::ios::beg); } @@ -39,7 +40,74 @@ std::vector romLoader::readFile(std::string& filename,int& error) return vec; } -int romLoader::loadRom(std::string& romPath,mmu& theMMU,std::vector& loadLog,bool isHirom) +/* +Country (also implies PAL/NTSC) (FFD9h) + 00h - International (eg. SGB) (any) + 00h J Japan (NTSC) + 01h E USA and Canada (NTSC) + 02h P Europe, Oceania, Asia (PAL) + 03h W Sweden/Scandinavia (PAL) + 04h - Finland (PAL) + 05h - Denmark (PAL) + 06h F France (SECAM, PAL-like 50Hz) + 07h H Holland (PAL) + 08h S Spain (PAL) + 09h D Germany, Austria, Switz (PAL) + 0Ah I Italy (PAL) + 0Bh C China, Hong Kong (PAL) + 0Ch - Indonesia (PAL) + 0Dh K South Korea (NTSC) (North Korea would be PAL) + 0Eh A Common (?) (?) + 0Fh N Canada (NTSC) + 10h B Brazil (PAL-M, NTSC-like 60Hz) + 11h U Australia (PAL) +*/ + +void romLoader::checkRomType(std::vector* romContents, bool& isHirom, int& standard, std::vector& loadLog) +{ + int romAdder = 0; + const int listOfPALCountries[] = {2,3,4,5,7,8,9,0x0a,0x0b,0x0c}; //? + + // check header with sophisticated heuristics + std::string romnameFromHeader; + int numAlnumLorom = 0, numAlnumHirom = 0; + for (unsigned int rampos = 0;rampos < 21;rampos++) + { + unsigned char charHi=(*romContents)[0xffc0 + rampos]; + unsigned char charLo=(*romContents)[0xffc0-0x8000 + rampos]; + if (std::isalnum(charHi)) numAlnumHirom += 1; + if (std::isalnum(charLo)) numAlnumLorom += 1; + } + + if (numAlnumHirom > numAlnumLorom) + { + loadLog.push_back("ROM seems HiRom"); + isHirom = true; + } + else + { + loadLog.push_back("ROM seems LoRom"); + romAdder = -0x8000; + } + + // 0 lorom, 1 hirom + unsigned char speedMemMap = (*romContents)[0xffd5+ romAdder]; + loadLog.push_back("Map mode:" + (speedMemMap & 0x0f)==0?"LoROM":"HiROM"); + + // rom country + unsigned char romCountry = (*romContents)[0xffd9+ romAdder]; + loadLog.push_back("Standard/Country:" + std::to_string(romCountry)); + + for (auto ccode: listOfPALCountries) + { + if (romCountry == ccode) + { + standard = 1; + } + } +} + +int romLoader::loadRom(std::string& romPath,mmu& theMMU,std::vector& loadLog,bool& isHirom,int& videoStandard) { std::vector romContents; @@ -55,6 +123,10 @@ int romLoader::loadRom(std::string& romPath,mmu& theMMU,std::vector loadLog.push_back("ROM was read correctly. Size is " + std::to_string(romContents.size()/1024) + "kb. HiRom: "+std::to_string(isHirom)); + checkRomType(&romContents, isHirom, videoStandard, loadLog); + + // + unsigned char* pSnesRAM = theMMU.getInternalRAMPtr(); unsigned short int filesizeInKb = (unsigned short int)(romContents.size() / 1024); diff --git a/romLoader.h b/romLoader.h index e068a59..888828d 100644 --- a/romLoader.h +++ b/romLoader.h @@ -14,12 +14,13 @@ class romLoader { private: + void checkRomType(std::vector* romContents, bool& isHirom, int& standard, std::vector& loadLog); std::vector readFile(std::string& filename,int& error); public: romLoader(); - int loadRom(std::string& romPath,mmu& theMMU,std::vector& loadLog,bool isHirom=false); + int loadRom(std::string& romPath,mmu& theMMU,std::vector& loadLog, bool& isHirom, int& videoStandard); }; #endif