diff --git a/src/engine/export.h b/src/engine/export.h index 4911217c8..49b96dd62 100644 --- a/src/engine/export.h +++ b/src/engine/export.h @@ -54,18 +54,21 @@ struct DivROMExportProgress { class DivROMExport { protected: - std::vector exportLog; + DivConfig conf; std::vector output; - std::mutex logLock; void logAppend(String what); public: + std::vector exportLog; + std::mutex logLock; + + void setConf(DivConfig& c); virtual bool go(DivEngine* eng); virtual void abort(); virtual void wait(); std::vector& getResult(); virtual bool hasFailed(); virtual bool isRunning(); - virtual DivROMExportProgress getProgress(); + virtual DivROMExportProgress getProgress(int index=0); virtual ~DivROMExport() {} }; diff --git a/src/engine/export/abstract.cpp b/src/engine/export/abstract.cpp index c33c38502..c6d0ec799 100644 --- a/src/engine/export/abstract.cpp +++ b/src/engine/export/abstract.cpp @@ -36,9 +36,9 @@ bool DivROMExport::hasFailed() { return true; } -DivROMExportProgress DivROMExport::getProgress() { +DivROMExportProgress DivROMExport::getProgress(int index) { DivROMExportProgress ret; - ret.name="Test"; + ret.name=""; ret.amount=0.0f; return ret; } @@ -55,3 +55,7 @@ void DivROMExport::wait() { bool DivROMExport::isRunning() { return false; } + +void DivROMExport::setConf(DivConfig& c) { + conf=c; +} diff --git a/src/engine/export/amigaValidation.cpp b/src/engine/export/amigaValidation.cpp index e9a8a8b84..5fce7a920 100644 --- a/src/engine/export/amigaValidation.cpp +++ b/src/engine/export/amigaValidation.cpp @@ -70,6 +70,7 @@ void DivExportAmigaValidation::run() { bool done=false; // sample.bin + logAppend("writing samples..."); SafeWriter* sample=new SafeWriter; sample->init(); for (int i=0; i<256; i++) { @@ -79,6 +80,7 @@ void DivExportAmigaValidation::run() { if (sample->tell()&1) sample->writeC(0); // seq.bin + logAppend("making sequence..."); SafeWriter* seq=new SafeWriter; seq->init(); @@ -239,6 +241,7 @@ void DivExportAmigaValidation::run() { EXTERN_BUSY_END; // wave.bin + logAppend("writing wavetables..."); SafeWriter* wave=new SafeWriter; wave->init(); for (WaveEntry& i: waves) { @@ -246,6 +249,7 @@ void DivExportAmigaValidation::run() { } // sbook.bin + logAppend("writing sample book..."); SafeWriter* sbook=new SafeWriter; sbook->init(); for (SampleBookEntry& i: sampleBook) { @@ -255,6 +259,7 @@ void DivExportAmigaValidation::run() { } // wbook.bin + logAppend("writing wavetable book..."); SafeWriter* wbook=new SafeWriter; wbook->init(); for (WaveEntry& i: waves) { @@ -272,6 +277,8 @@ void DivExportAmigaValidation::run() { output.push_back(DivROMExportOutput("wave.bin",wave)); output.push_back(DivROMExportOutput("seq.bin",seq)); + logAppend("finished!"); + running=false; } @@ -296,3 +303,7 @@ void DivExportAmigaValidation::abort() { bool DivExportAmigaValidation::isRunning() { return running; } + +bool DivExportAmigaValidation::hasFailed() { + return false; +} diff --git a/src/engine/export/amigaValidation.h b/src/engine/export/amigaValidation.h index 42703a36e..df8131652 100644 --- a/src/engine/export/amigaValidation.h +++ b/src/engine/export/amigaValidation.h @@ -29,6 +29,7 @@ class DivExportAmigaValidation: public DivROMExport { public: bool go(DivEngine* e); bool isRunning(); + bool hasFailed(); void abort(); void wait(); ~DivExportAmigaValidation() {} diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index c943779eb..615873391 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -251,6 +251,7 @@ void FurnaceGUI::drawExportROM(bool onWindow) { if (newDef!=NULL) { if (ImGui::Selectable(newDef->name)) { romTarget=(DivROMExportOptions)i; + romMultiFile=newDef->multiOutput; } } } @@ -346,53 +347,6 @@ void FurnaceGUI::drawExportTiuna(bool onWindow) { } } -void FurnaceGUI::drawExportAmigaVal(bool onWindow) { - exitDisabledTimer=1; - - ImGui::Text(_( - "this is NOT ROM export! only use for making sure the\n" - "Furnace Amiga emulator is working properly by\n" - "comparing it with real Amiga output." - )); - ImGui::AlignTextToFramePadding(); - ImGui::Text(_("Directory")); - ImGui::SameLine(); - ImGui::InputText("##AVDPath",&workingDirROMExport); - if (onWindow) { - ImGui::Separator(); - if (ImGui::Button(_("Cancel"),ImVec2(200.0f*dpiScale,0))) ImGui::CloseCurrentPopup(); - ImGui::SameLine(); - } - if (ImGui::Button(_("Bake Data"),ImVec2(200.0f*dpiScale,0))) { - DivROMExport* ex=e->buildROM(DIV_ROM_AMIGA_VALIDATION); - if (ex->go(e)) { - ex->wait(); - if (ex->hasFailed()) { - showError("error!"); - } else { - if (workingDirROMExport.size()>0) { - if (workingDirROMExport[workingDirROMExport.size()-1]!=DIR_SEPARATOR) workingDirROMExport+=DIR_SEPARATOR_STR; - } - for (DivROMExportOutput& i: ex->getResult()) { - String path=workingDirROMExport+i.name; - FILE* outFile=ps_fopen(path.c_str(),"wb"); - if (outFile!=NULL) { - fwrite(i.data->getFinalBuf(),1,i.data->size(),outFile); - fclose(outFile); - } - i.data->finish(); - delete i.data; - } - showError(fmt::sprintf(_("Done! Baked %d files."),(int)ex->getResult().size())); - } - } else { - showError("error!"); - } - delete ex; - ImGui::CloseCurrentPopup(); - } -} - void FurnaceGUI::drawExportText(bool onWindow) { exitDisabledTimer=1; @@ -496,16 +450,6 @@ void FurnaceGUI::drawExport() { ImGui::EndTabItem(); } } - int numAmiga=0; - for (int i=0; isong.systemLen; i++) { - if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++; - } - if (numAmiga && settings.iCannotWait) { - if (ImGui::BeginTabItem(_("Amiga Validation"))) { - drawExportAmigaVal(true); - ImGui::EndTabItem(); - } - } if (ImGui::BeginTabItem(_("Text"))) { drawExportText(true); ImGui::EndTabItem(); @@ -536,9 +480,6 @@ void FurnaceGUI::drawExport() { case GUI_EXPORT_TIUNA: drawExportTiuna(true); break; - case GUI_EXPORT_AMIGA_VAL: - drawExportAmigaVal(true); - break; case GUI_EXPORT_TEXT: drawExportText(true); break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index e17d5c345..f950b69fe 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1980,7 +1980,22 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { ); break; case GUI_FILE_EXPORT_ROM: - showError(_("Coming soon!")); + if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir(); + if (romMultiFile) { + hasOpened=fileDialog->openSelectDir( + _("Export ROM"), + workingDirROMExport, + dpiScale + ); + } else { + hasOpened=fileDialog->openSave( + _("Export ROM"), + {romFilterName, romFilterExt}, + workingDirROMExport, + dpiScale, + (settings.autoFillSave)?shortName:"" + ); + } break; case GUI_FILE_LOAD_MAIN_FONT: if (!dirExists(workingDirFont)) workingDirFont=getHomeDir(); @@ -4322,16 +4337,6 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } } - int numAmiga=0; - for (int i=0; isong.systemLen; i++) { - if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++; - } - if (numAmiga && settings.iCannotWait) { - if (ImGui::BeginMenu(_("export Amiga validation data..."))) { - drawExportAmigaVal(); - ImGui::EndMenu(); - } - } if (ImGui::BeginMenu(_("export text..."))) { drawExportText(); ImGui::EndMenu(); @@ -4380,16 +4385,6 @@ bool FurnaceGUI::loop() { displayExport=true; } } - int numAmiga=0; - for (int i=0; isong.systemLen; i++) { - if (e->song.system[i]==DIV_SYSTEM_AMIGA) numAmiga++; - } - if (numAmiga && settings.iCannotWait) { - if (ImGui::MenuItem(_("export Amiga validation data..."))) { - curExportType=GUI_EXPORT_AMIGA_VAL; - displayExport=true; - } - } if (ImGui::MenuItem(_("export text..."))) { curExportType=GUI_EXPORT_TEXT; displayExport=true; @@ -5069,6 +5064,9 @@ bool FurnaceGUI::loop() { if (curFileDialog==GUI_FILE_EXPORT_VGM) { checkExtension(".vgm"); } + if (curFileDialog==GUI_FILE_EXPORT_ROM) { + checkExtension(romFilterExt.c_str()); + } if (curFileDialog==GUI_FILE_EXPORT_ZSM) { checkExtension(".zsm"); } @@ -5551,7 +5549,19 @@ bool FurnaceGUI::loop() { break; } case GUI_FILE_EXPORT_ROM: - showError(_("Coming soon!")); + romExportPath=copyOfName; + pendingExport=e->buildROM(romTarget); + if (pendingExport==NULL) { + showError("could not create exporter! you may want to report this issue..."); + } else { + pendingExport->setConf(romConfig); + if (pendingExport->go(e)) { + displayExportingROM=true; + romExportSave=true; + } else { + showError("could not begin exporting process! TODO: elaborate"); + } + } break; case GUI_FILE_EXPORT_TEXT: { SafeWriter* w=e->saveText(false); @@ -5718,6 +5728,11 @@ bool FurnaceGUI::loop() { ImGui::OpenPopup(_("Rendering...")); } + if (displayExportingROM) { + displayExportingROM=false; + ImGui::OpenPopup(_("ROM Export Progress")); + } + if (displayNew) { newSongQuery=""; newSongFirstFrame=true; @@ -5783,6 +5798,83 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } + centerNextWindow(_("ROM Export Progress"),canvasW,canvasH); + if (ImGui::BeginPopupModal(_("ROM Export Progress"),NULL)) { + if (pendingExport==NULL) { + ImGui::TextUnformatted(_("...ooooor you could try asking me a new ROM export?")); + if (ImGui::Button(_("Erm what the sigma???"))) { + ImGui::CloseCurrentPopup(); + } + } else { + int progIndex=0; + while (true) { + DivROMExportProgress p=pendingExport->getProgress(progIndex); + if (p.name.empty()) break; + ImGui::Text("%s: %d%%",p.name.c_str(),(int)round(p.amount*100.0f)); + ImGui::ProgressBar(p.amount,ImVec2(-FLT_MIN,0)); + progIndex++; + } + ImVec2 romLogSize=ImGui::GetContentRegionAvail(); + romLogSize.y-=ImGui::GetFrameHeightWithSpacing(); + if (romLogSize.y<60.0f*dpiScale) romLogSize.y=60.0f*dpiScale; + if (ImGui::BeginChild("Export Log",romLogSize,true)) { + pendingExport->logLock.lock(); + for (String& i: pendingExport->exportLog) { + ImGui::TextUnformatted(i.c_str()); + } + if (romExportSave) { + ImGui::SetScrollY(ImGui::GetScrollMaxY()); + } + pendingExport->logLock.unlock(); + } + ImGui::EndChild(); + if (pendingExport->isRunning()) { + if (ImGui::Button(_("Abort"))) { + pendingExport->abort(); + delete pendingExport; + pendingExport=NULL; + ImGui::CloseCurrentPopup(); + } + } else { + if (romExportSave) { + pendingExport->wait(); + if (!pendingExport->hasFailed()) { + // save files here (romExportPath) + for (DivROMExportOutput& i: pendingExport->getResult()) { + String path=romExportPath; + if (romMultiFile) { + path+=DIR_SEPARATOR_STR; + path+=i.name; + } + FILE* outFile=ps_fopen(path.c_str(),"wb"); + if (outFile!=NULL) { + fwrite(i.data->getFinalBuf(),1,i.data->size(),outFile); + fclose(outFile); + } else { + // TODO: handle failure here + } + i.data->finish(); + delete i.data; + } + } + romExportSave=false; + } + if (ImGui::Button(_("OK"))) { + delete pendingExport; + pendingExport=NULL; + ImGui::CloseCurrentPopup(); + } + if (pendingExport!=NULL) { + if (pendingExport->hasFailed()) { + ImGui::SameLine(); + ImGui::TextUnformatted(_("Error!")); + } + } + } + } + ImGui::EndPopup(); + } + drawTutorial(); ImVec2 newSongMinSize=mobileUI?ImVec2(canvasW-(portrait?0:(60.0*dpiScale)),canvasH-60.0*dpiScale):ImVec2(400.0f*dpiScale,200.0f*dpiScale); @@ -7873,6 +7965,7 @@ FurnaceGUI::FurnaceGUI(): snesFilterHex(false), modTableHex(false), displayEditString(false), + displayExportingROM(false), changeCoarse(false), mobileEdit(false), killGraphics(false), @@ -8350,7 +8443,10 @@ FurnaceGUI::FurnaceGUI(): curTutorialStep(0), dmfExportVersion(0), curExportType(GUI_EXPORT_NONE), - romTarget(DIV_ROM_ABSTRACT) { + romTarget(DIV_ROM_ABSTRACT), + romMultiFile(false), + romExportSave(false), + pendingExport(NULL) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; diff --git a/src/gui/gui.h b/src/gui/gui.h index 1481089ff..060db2a9c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -655,7 +655,6 @@ enum FurnaceGUIExportTypes { GUI_EXPORT_ZSM, GUI_EXPORT_TIUNA, GUI_EXPORT_CMD_STREAM, - GUI_EXPORT_AMIGA_VAL, GUI_EXPORT_TEXT, GUI_EXPORT_DMF }; @@ -1621,6 +1620,7 @@ class FurnaceGUI { bool displayNew, displayExport, displayPalette, fullScreen, preserveChanPos, sysDupCloneChannels, sysDupEnd, noteInputPoly, notifyWaveChange; bool wantScrollListIns, wantScrollListWave, wantScrollListSample; bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString; + bool displayExportingROM; bool changeCoarse; bool mobileEdit; bool killGraphics; @@ -2682,6 +2682,12 @@ class FurnaceGUI { // ROM export specific DivROMExportOptions romTarget; + DivConfig romConfig; + bool romMultiFile; + bool romExportSave; + String romFilterName, romFilterExt; + String romExportPath; + DivROMExport* pendingExport; // user presets window std::vector selectedUserPreset; @@ -2693,7 +2699,6 @@ class FurnaceGUI { void drawExportROM(bool onWindow=false); void drawExportZSM(bool onWindow=false); void drawExportTiuna(bool onWindow=false); - void drawExportAmigaVal(bool onWindow=false); void drawExportText(bool onWindow=false); void drawExportCommand(bool onWindow=false); void drawExportDMF(bool onWindow=false);