Commits

Marianne Gagnon committed 234a1b3 Merge

Merge debugging branch from Neive. Cool\!

Comments (0)

Files changed (15)

 wxMupen64PlusSetup.exe
 *Thumbs.db
 .waf-*
+waf-1.*-*
+waf-1.*.*-*
 91e7061a3dc1674b7351019f2b6e9cd52036276b 0.1
 65a79905385fbf77edd2ffb23f1e11df3aea5122 0.2
+998b8b438b655eb99c83d8153ce3d3151a1cff1a 0.3
+998b8b438b655eb99c83d8153ce3d3151a1cff1a 0.3
+0564db396383f0293b8a08e6fa0502c90f543e12 0.3
     <string>WXMU</string>
 
     <key>CFBundleVersion</key>
-    <string>0.2</string>
+    <string>0.3</string>
 
     <key>CFBundleShortVersionString</key>
-    <string>0.2</string>
+    <string>0.3</string>
 
     <key>CFBundleGetInfoString</key>
-    <string>wxMupen64Plus 0.2</string>
+    <string>wxMupen64Plus 0.3</string>
 
     <key>CFBundleDevelopmentRegion</key>
     <string>English</string>
                 ConfigParam* param = section->m_parameters[p];
                 param->m_choices.push_back( ConfigParamChoice(_("Internal"), std::string("internal") ) );
                 param->m_choices.push_back( ConfigParamChoice(_("External"), std::string("external") ) );
-                param->m_need_restart = true;
+                param->setCommentString(_("* Changes to this parameter will be only effective after restarting Mupen64Plus"));
             }
             else if (param_wxname == "R4300Emulator")
             {
 
         if (wxString(section->m_section_name).StartsWith("Video"))
         {
+            ConfigParam* screenH = section->getParamWithName("ScreenHeight");
+            if (screenH != NULL)
+            {
+                screenH->setCommentString(_("* Size parameters are only used if external video is used. If you use one-window-mupen,\nsimply resize the window. This setting can be changed in the 'Plugins' section."));
+            }
+            
             if (wxString(section->m_section_name).Contains("Rice"))
             {
                 ConfigParam* frameBufferSetting = section->getParamWithName("FrameBufferSetting");
                     openGLRenderSetting->m_choices.push_back( ConfigParamChoice(_("OGL Fragment Program"), 8) );
                 }
             }
+            else if (wxString(section->m_section_name).Contains("Glide64"))
+            {
+                ConfigParam* filteringSetting = section->getParamWithName("filtering");
+                if (filteringSetting != NULL)
+                {
+                    filteringSetting->m_choices.push_back( ConfigParamChoice(_("None"), 0) );
+                    filteringSetting->m_choices.push_back( ConfigParamChoice(_("Force Bilinear"), 1) );
+                    filteringSetting->m_choices.push_back( ConfigParamChoice(_("Force Point-sampled"), 2) );
+                }
+                
+                ConfigParam* wfmode = section->getParamWithName("wfmode");
+                if (wfmode != NULL)
+                {
+                    wfmode->setHelpString(_("Wireframe mode"));
+                    wfmode->m_choices.push_back( ConfigParamChoice(_("Normal Colors"), 0) );
+                    wfmode->m_choices.push_back( ConfigParamChoice(_("Vertex Colors"), 1) );
+                    wfmode->m_choices.push_back( ConfigParamChoice(_("Red Only"), 2) );
+                }
+                
+                ConfigParam* swapmode = section->getParamWithName("swapmode");
+                if (swapmode != NULL)
+                {
+                    swapmode->setHelpString(_("Buffer Swapping Method"));
+                    swapmode->m_choices.push_back( ConfigParamChoice(_("Old"), 0) );
+                    swapmode->m_choices.push_back( ConfigParamChoice(_("New"), 1) );
+                    swapmode->m_choices.push_back( ConfigParamChoice(_("Hybrid"), 2) );
+                }
+                
+                ConfigParam* lodmode = section->getParamWithName("lodmode");
+                if (lodmode != NULL)
+                {
+                    lodmode->setHelpString(_("LOD Calculation"));
+                    lodmode->m_choices.push_back( ConfigParamChoice(_("Off"), 0) );
+                    lodmode->m_choices.push_back( ConfigParamChoice(_("Fast"), 1) );
+                    lodmode->m_choices.push_back( ConfigParamChoice(_("Precise"), 2) );
+                }
+                
+                ConfigParam* show_fps = section->getParamWithName("show_fps");
+                if (show_fps != NULL)
+                {
+                    show_fps->setHelpString(_("Show FPS"));
+                    // TODO: allow combinable bitmasks
+                    show_fps->m_choices.push_back( ConfigParamChoice(_("Disabled"), 0) );
+                    show_fps->m_choices.push_back( ConfigParamChoice(_("FPS Counter"), 1) );
+                    show_fps->m_choices.push_back( ConfigParamChoice(_("VI/s Counter"), 2) );
+                    show_fps->m_choices.push_back( ConfigParamChoice(_("% Speed"), 4) );
+                    show_fps->m_choices.push_back( ConfigParamChoice(_("FPS Transparent"), 8) );
+                }
+                
+                ConfigParam* tex_filter = section->getParamWithName("tex_filter");
+                if (tex_filter != NULL)
+                {
+                    tex_filter->setHelpString(_("Texture Filter"));
+                    tex_filter->m_choices.push_back( ConfigParamChoice(_("Disabled"), 0) );
+                    tex_filter->m_choices.push_back( ConfigParamChoice(_("Blur edges"), 1) );
+                    tex_filter->m_choices.push_back( ConfigParamChoice(_("Super 2xSAI"), 2) );
+                    tex_filter->m_choices.push_back( ConfigParamChoice(_("Hq2x"), 3) );
+                    tex_filter->m_choices.push_back( ConfigParamChoice(_("Hq4x"), 4) );
+                }
+            }
         }
         else if (section->m_section_name == "Audio-SDL")
         {
 #include <wx/frame.h>
 #include <wx/glcanvas.h>
 #include <wx/display.h>
+#include <wx/dataview.h>
 
 #include <stdexcept>
 #include <map>
 
     m_dir_picker->Connect(m_dir_picker->GetId(), wxEVT_COMMAND_DIRPICKER_CHANGED,
                           wxFileDirPickerEventHandler(GamesPanel::onPathChange), NULL, this);
-        
-    m_item_list = new wxListCtrl(m_center_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
-                                 wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_HRULES);
+    
+    m_item_list = new wxDataViewListCtrl(m_center_panel, wxID_ANY);
     m_list_sizer->Add(m_item_list, 1, wxALL | wxEXPAND, 5);
     
+    wxArrayString columns;              std::vector<int> sizes;
+    columns.Add( _("File Name") );      sizes.push_back( 380 );
+    columns.Add( _("Internal Name") );  sizes.push_back( 250 );
+    columns.Add( _("Country") );        sizes.push_back( 100 );
+    
+    const int count = columns.Count();
+    for (int n=0; n<count; n++)
+    {
+        wxDataViewColumn* col = new wxDataViewColumn(columns[n], new wxDataViewTextRenderer(), n,
+                                   sizes[n], wxALIGN_LEFT,
+                                   wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
+        m_item_list->AppendColumn(col);
+        if (n == 0) col->SetSortOrder(true); // select column 0 by default
+    }
+    
     populateList();
     
-    /*
-    m_status = new wxStaticText(this, wxID_ANY, _("Emulation is stopped"));
-    buttons->Add(m_status, 0, wxALIGN_CENTER_VERTICAL  | wxALL, 5);
-    
-    wxBitmap icon_cart(datadir + "mupen64cart.png", wxBITMAP_TYPE_PNG);  
-    wxStaticBitmap* icon = new wxStaticBitmap(this, wxID_ANY, icon_cart);
-    buttons->Add(icon, 0, wxALL, 5);
-    */
-    
     m_center_panel->SetSizer(m_list_sizer);
     
     oversizer->Add(m_center_panel, 1, wxEXPAND);
     m_pause_button->Disable();
     m_stop_button->Disable();
     
-    m_item_list->Connect(m_item_list->GetId(), wxEVT_COMMAND_LIST_COL_CLICK,
-                         wxListEventHandler(GamesPanel::onColClick), NULL, this);
-    
     Connect(wxID_ANY, wxMUPEN_STATE_CHANGE,
             wxCommandEventHandler(GamesPanel::onMupenStateChangeEvt), NULL, this);
     Connect(wxID_ANY, wxMUPEN_SAVE_SLOT_CHANGE,
 void GamesPanel::populateList()
 {
     wxString path = m_dir_picker->GetPath();
-    m_item_list->ClearAll();
-        
+    m_item_list->DeleteAllItems();
+    
     if (path.IsEmpty()) return;
     
-    wxArrayString columns;              std::vector<int> sizes;
-    columns.Add( _("File Name") );      sizes.push_back( 300 );
-    columns.Add( _("Internal Name") );  sizes.push_back( 225 );
-    //columns.Add( _("Good Name") );      sizes.push_back( 225 );
-    columns.Add( _("Country") );        sizes.push_back( 75 );
-    //columns.Add( _("Size") );        sizes.push_back( 75 );
-    
-    const int count = columns.Count();
-    for (int n=0; n<count; n++)
-    {
-        wxListItem col;
-        col.SetId(n);
-        col.SetText( columns[n] );
-        col.SetWidth( sizes[n] );
-        m_item_list->InsertColumn(n, col);
-    }
-    
     m_roms = getRomsInDir(path);
     
     const int item_amount = m_roms.size();
     for (int n=0; n<item_amount; n++)
     {
         RomInfo& curritem = m_roms[n];
-                
-        wxListItem item;
-        item.SetId(n);
-        item.SetText( curritem.m_file_name );
         
         Mupen64PlusPlus::RomInfo info;
         
-        long id = m_item_list->InsertItem( item );
+
+        std::map<wxString, Mupen64PlusPlus::RomInfo>::iterator elem = g_cache.find(curritem.m_full_path);
+        if (elem != g_cache.end())
+        {
+            // Element found in cache, great
+            info = g_cache[curritem.m_full_path];
+        }
+        else
+        {
+            try
+            {
+                info = m_api->getRomInfo(curritem.m_full_path.utf8_str());
+            }
+            catch (std::runtime_error& ex)
+            {
+                mplog_error("GamesPanel", "Failed to load rom %s : %s",
+                            (const char*)curritem.m_full_path.utf8_str(),
+                            ex.what());
+            }
+        }
         
-        if (id != -1)
-        {
-            std::map<wxString, Mupen64PlusPlus::RomInfo>::iterator elem = g_cache.find(curritem.m_full_path);
-            if (elem != g_cache.end())
-            {
-                // Element found in cache, great
-                info = g_cache[curritem.m_full_path];
-            }
-            else
-            {
-                try
-                {
-                    info = m_api->getRomInfo(curritem.m_full_path.utf8_str());
-                }
-                catch (std::runtime_error& ex)
-                {
-                    mplog_error("GamesPanel", "Failed to load rom %s : %s",
-                                (const char*)curritem.m_full_path.utf8_str(),
-                                ex.what());
-                }
-            }
-            
-            curritem.m_country = info.country;
-            curritem.m_internal_name = info.name;
+        curritem.m_country = info.country;
+        curritem.m_internal_name = info.name;
         
-            // set value in first column
-            m_item_list->SetItem(id, COLUMN_FILE, curritem.m_file_name);
-            
-            // set value in second column
-            m_item_list->SetItem(id, COLUMN_NAME, info.name);
-            
-            // set value in third column
-            //m_item_list->SetItem(id, 2, info.goodname);
-            
-            // set value in fourth column
-            m_item_list->SetItem(id, COLUMN_COUNTRY, info.country);
-            
-            m_item_list->SetItemData(id, id);
-        }
+        wxVector< wxVariant > values;
+        values.push_back( wxVariant(curritem.m_file_name) );
+        values.push_back( wxVariant(curritem.m_internal_name) );
+        values.push_back( wxVariant(curritem.m_country) );
+        m_item_list->AppendItem(values);
     } // end for
     
-    m_item_list->SortItems(GamesPanel::wxListCompareFunction, (wxIntPtr)this /* user data */);
+    //m_item_list->SortItems(GamesPanel::wxListCompareFunction, (wxIntPtr)this /* user data */);
 }
 
 // -----------------------------------------------------------------------------------------------------------
 
 // -----------------------------------------------------------------------------------------------------------
 
-void GamesPanel::onColClick(wxListEvent& evt)
-{
-    if (m_curr_col != evt.GetColumn())
-    {
-        m_curr_col = evt.GetColumn();
-        m_item_list->SortItems(GamesPanel::wxListCompareFunction, (wxIntPtr)this /* user data */);
-    }  
-}
-
-// -----------------------------------------------------------------------------------------------------------
-
 std::vector<GamesPanel::RomInfo> GamesPanel::getRomsInDir(wxString dirpath)
 {
     std::vector<RomInfo> out;
         }
     }
     
-    long item = m_item_list->GetNextItem(-1,
-                                        wxLIST_NEXT_ALL,
-                                        wxLIST_STATE_SELECTED);
+    int item = m_item_list->GetSelectedRow();
     
-    if (item == -1)
+    if (item == wxNOT_FOUND)
     {
         wxMessageBox( _("No game is selected, cannot start emulation") );
         return;
     }
     
-    wxString file = path + wxFileName::GetPathSeparator() + m_item_list->GetItemText(item);
-    loadRom(m_item_list->GetItemText(item), file);
+    wxString romfile = m_item_list->GetTextValue(item, 0);
+    wxString file = path + wxFileName::GetPathSeparator() + romfile; //m_item_list->GetItemText(item);
+    loadRom(romfile, file);
 }
 
 // -----------------------------------------------------------------------------------------------------------
 
 #include <wx/panel.h>
 #include <vector>
+#include <wx/dataview.h>
 
 #include "mupen64plusplus/MupenAPIpp.h"
 #include "parameterpanel.h"
 
 class GamesPanel : public wxPanel, public IConfigurationPanel, public IEmuStateListener
 {
-    wxListCtrl* m_item_list;
+    wxDataViewListCtrl* m_item_list;
     wxDirPickerCtrl* m_dir_picker;
     ConfigParam* m_gamesPathParam;
     wxBoxSizer* m_list_sizer;
     void onPlay(wxCommandEvent& evt);
     void onPause(wxCommandEvent& evt);
     void onStop(wxCommandEvent& evt);
-    void onColClick(wxListEvent& evt);
     void wanderingFocus(wxFocusEvent& evt);
 	
     void loadRom(wxString name, wxString pathAndFile);
 
 const bool g_Verbose = false;
 
+const int VERSION_MAJOR = 0;
+const int VERSION_MINOR = 3;
+
 const char* DEFAULT_VIDEO_PLUGIN = "mupen64plus-video-rice";
 const char* DEFAULT_AUDIO_PLUGIN = "mupen64plus-audio-sdl";
 const char* DEFAULT_INPUT_PLUGIN = "mupen64plus-input-sdl";
 const char* DEFAULT_RSP_PLUGIN   = "mupen64plus-rsp-hle";
 
-const int VERSION_MAJOR = 0;
-const int VERSION_MINOR = 2;
-
 bool osd_logging = false;
 
 void setOsdLogging(bool p)
     
     m_frame->SetSizer(m_sizer);
     
-    m_frame->Centre();
+    m_frame->Maximize();
     m_frame->Show();
     
     m_frame->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MupenFrontendApp::onClose), NULL, this);

mupen64plusplus/MupenAPIpp.cpp

 #include <wx/progdlg.h>
 #include <wx/thread.h>
 #include <wx/log.h>
+#include <wx/zstream.h>
 #include <SDL.h>
+#include <memory> 
+
+#include "ownerptr.h"
 
 void Mupen64PlusPlus::StateCallback(void *Context, m64p_core_param param_type, int new_value)
 {
     if (result != M64ERR_SUCCESS)
     {
         mplog_warning("MupenApiPP", "Cannot retrieve video extension from config, will use platform defaults\n");
-#ifdef __WXGTK__
+#ifdef __WXMAC__
+        m_use_video_extension = true;
+#else
         m_use_video_extension = false;
-#else
-        m_use_video_extension = true;
 #endif
     }
     else
         else
         {
             mplog_warning("MupenApiPP", "Unknown video extension in config, will use platform defaults\n");
-#ifdef __WXGTK__
-            m_use_video_extension = false;
+#ifdef __WXMAC__
+        m_use_video_extension = true;
 #else
-            m_use_video_extension = true;
+        m_use_video_extension = false;
 #endif
         }
     }
 
 void ParameterListCallback(void* sectionHandle, const char* ParamName, m64p_type ParamType)
 {
+    // 'Version' parameters are internal to mupen
+    if (strcmp(ParamName, "version") == 0 or strcmp(ParamName, "Version") == 0) {
+        return;
+    }
+    
     m64p_handle* section = (m64p_handle*)sectionHandle;
 
     ConfigParam* param = new ConfigParam(*section);
 
 // -----------------------------------------------------------------------------------------------------------
 
-void Mupen64PlusPlus::loadRom(wxString filename, bool attachPlugins, wxProgressDialog* dialog)
+class FileContentsReader
 {
-    // SDL_Quit();
-    printf("==== load rom ====\n");
+    int total;
+    OwnerPtr<wxMemoryOutputStream> memoryImage;
+    char* rom_buf;
     
-    wxFFileInputStream input(filename);
-    if (not input.IsOk() or not input.CanRead())
+
+    /** Read uncompressed file */
+    void readNormal(wxString filename, wxProgressDialog* dialog)
     {
-        throw std::runtime_error(("[Mupen64PlusPlus::loadRom] failed to open file '" +
-                                  filename + "'").ToStdString());
-    }
-    
-    wxFile thefile;
-    if (not thefile.Open(filename))
-    {
-        throw std::runtime_error((const char*)wxString::Format(_("Cannot open file %s"), filename.c_str()).utf8_str());
-    }
-    const int rom_size = thefile.Length() + 1024*2 /* in case the OS reports the size inaccurately */;
-    char* rom_buf = new char[rom_size];
-    wxMemoryOutputStream memoryImage(rom_buf, rom_size);
+        rom_buf = NULL;
+        total = 0;
+        wxFFileInputStream input(filename);
+        
+        if (not input.IsOk() or not input.CanRead())
+        {
+            throw std::runtime_error(("[Mupen64PlusPlus::loadRom] failed to open file '" +
+                                      filename + "'").ToStdString());
+        }
+        
+        wxFile thefile;
+        if (not thefile.Open(filename))
+        {
+            throw std::runtime_error((const char*)wxString::Format(_("Cannot open file %s"), filename.c_str()).utf8_str());
+        }
+        const int rom_size = thefile.Length() + 1024*2 /* in case the OS reports the size inaccurately */;
+        rom_buf = new char[rom_size];
+        memoryImage = new wxMemoryOutputStream(rom_buf, rom_size);
 
-    int total = 0;
-
-    {
         const int BUFFER_SIZE = 1024*20;
         char buffer[BUFFER_SIZE];
         size_t size;
                 }
             }
             
-            memoryImage.Write(buffer, size);
+            memoryImage->Write(buffer, size);
             
-            if (memoryImage.LastWrite() != size)
+            if (memoryImage->LastWrite() != size)
             {
                 delete[] rom_buf;
                 throw std::runtime_error("Memory stream full");
         while (size > 0 and not input.Eof() and input.IsOk() and input.CanRead());
     }
     
-    wxStreamBuffer* buffer = memoryImage.GetOutputStreamBuffer();
+    /** Read compressed file */
+    void readZipped(wxString filename, wxProgressDialog* dialog)
+    {
+        rom_buf = NULL;
+        total = 0;
+        wxFFileInputStream input(filename);
+        if (not input.IsOk() or not input.CanRead())
+        {
+            throw std::runtime_error(("[Mupen64PlusPlus::loadRom] failed to open file '" +
+                                      filename + "'").ToStdString());
+        }
+        
+        wxFile thefile;
+        if (not thefile.Open(filename))
+        {
+            throw std::runtime_error((const char*)wxString::Format(_("Cannot open file %s"), filename.c_str()).utf8_str());
+        }
+        const int compressed_size = thefile.Length();
+        
+        wxZlibInputStream dezipper(input);
+        
+        memoryImage = new wxMemoryOutputStream();
+
+        const int BUFFER_SIZE = 1024*20;
+        char buffer[BUFFER_SIZE];
+        size_t size;
+        int t = 0;
+        
+        //printf("Will read ROM\n");
+        do
+        {
+            size = dezipper.Read(buffer, BUFFER_SIZE).LastRead();
+            
+            total += size;
+            t++;
+            if (t > 100)
+            {
+                t = 0;
+                dialog->Pulse();
+                //printf("Read %i, total %i (%i MB)\n", (int)size, total, total/(1024*1024));
+                if (dialog != NULL)
+                {
+                    dialog->Update(int(std::min(1.0f, float(input.TellI())/float(compressed_size))*80.0f));
+                }
+            }
+            
+            memoryImage->Write(buffer, size);
+        }
+        while (size > 0 and not dezipper.Eof() and dezipper.IsOk() and dezipper.CanRead());
+    }
     
+public:
+    FileContentsReader(bool compressed, wxString filename, wxProgressDialog* dialog)
+    {
+        if (compressed) readZipped(filename, dialog);
+        else            readNormal(filename, dialog);
+    }
+    
+    ~FileContentsReader()
+    {
+        if (rom_buf != NULL) delete[] rom_buf;
+    }
+    
+    wxMemoryOutputStream* getBuffer()
+    {
+        return memoryImage.raw_ptr;
+    }
+    
+    int getByteCount() const
+    {
+        return total;
+    }
+};
+
+// -----------------------------------------------------------------------------------------------------------
+
+void Mupen64PlusPlus::loadRom(wxString filename, bool attachPlugins, wxProgressDialog* dialog)
+{
+    printf("==== load rom ====\n");
+    
+    // ---- check if ROM is compressed
+    m64p_rom_header header;
+    m64p_error result = getRomHeader(filename.utf8_str(), &header);
+    if (result != M64ERR_SUCCESS)
+    {
+        std::string errmsg = "Reading ROM header failed with error : ";
+        errmsg = errmsg + getErrorMessage(result);
+        throw std::runtime_error(errmsg);
+    }
+    bool is_gzip = false;
+    bool is_zip = false;
+    if (header.init_PI_BSB_DOM1_LAT_REG == 31 and
+        header.init_PI_BSB_DOM1_PGS_REG == 139)
+    {
+        is_gzip = true;
+    }
+    else if (header.init_PI_BSB_DOM1_LAT_REG == 4 and
+             header.init_PI_BSB_DOM1_PGS_REG == 3 and
+             header.init_PI_BSB_DOM1_PWD_REG == 75 and
+             header.init_PI_BSB_DOM1_PGS_REG2 == 80)
+    {
+        is_zip = true;
+    }
+    // -------------------------------
+    
+    FileContentsReader fcr(is_zip or is_gzip, filename, dialog);
+    int total = fcr.getByteCount();
+
+    wxMemoryOutputStream* fileContentsStream = fcr.getBuffer();
+    wxStreamBuffer* buffer = fileContentsStream->GetOutputStreamBuffer();
     m_curr_rom_size = buffer->GetBufferSize();
-    m64p_error result = ::openRom(total, buffer->GetBufferStart());
-    
-    delete[] rom_buf;
+    result = ::openRom(total, buffer->GetBufferStart());
     
     if (dialog != NULL) dialog->Update(90);
     
         out.country = getCountryName(countrycode);
         
         if (header.init_PI_BSB_DOM1_LAT_REG == 128 and
-             header.init_PI_BSB_DOM1_PGS_REG == 55 and
-             header.init_PI_BSB_DOM1_PWD_REG == 18 and
-             header.init_PI_BSB_DOM1_PGS_REG2 == 64)
+            header.init_PI_BSB_DOM1_PGS_REG == 55 and
+            header.init_PI_BSB_DOM1_PWD_REG == 18 and
+            header.init_PI_BSB_DOM1_PGS_REG2 == 64)
         {
              out.name = header.Name;
         }

mupen64plusplus/MupenAPIpp.h

     /** Only set if m_special_type is PLUGIN_FILE. */
     m64p_plugin_type m_plugin_type; 
 
-    /** Set to true if this parameter will only take effect on restart */
-    bool m_need_restart;
+    /** A comment string to add under this parameter */
+    bool m_has_comment_string;
+    wxString m_comment_string;
 
     /** Dummy instance ctor; produces a non-usable instance that needs to be setup later */
     /*
     ConfigParam(m64p_handle section, SpecialParamType type = NOTHING_SPECIAL)
     {
         m_enabled = true;
-        m_need_restart = false;
+        m_has_comment_string = false;
         m_parent_section = section;
         m_special_type = type;
         m_magic_number = 0xC001C001;
     void copyFrom(const ConfigParam& other)
     {
         m_enabled = other.m_enabled;
-        m_need_restart = other.m_need_restart;
+        m_has_comment_string = other.m_has_comment_string;
+        m_comment_string = other.m_comment_string;
         m_parent_section = other.m_parent_section;
         m_special_type = other.m_special_type;
         m_choices = other.m_choices;
         if (helpString != NULL) m_help_string = helpString;
     }
     
+    void setHelpString(const wxString helpString)
+    {
+        m_help_string = helpString;
+    }
+    
     void setEnabled(bool enabled) { m_enabled = enabled; }
+    
+    void setCommentString(wxString comment)
+    {
+        m_comment_string = comment;
+        m_has_comment_string = true;
+    }
+    
+    bool hasCommentString() const { return m_has_comment_string; }
+    wxString getCommentString() const { return m_comment_string; }
 };
 
 class ConfigSection

mupen64plusplus/plugin.c

     rval = (*PluginStartup)(CoreHandle, g_PluginMap[MapIndex].name, DebugCallback);  /* DebugCallback is in main.c */
     if (rval != M64ERR_SUCCESS)
     {
-        mplog_error("Plugin", "ERROR: %s plugin library '%s' failed to start.\n", g_PluginMap[MapIndex].name, filepath);
+        mplog_error("Plugin", "ERROR: %s plugin library '%s' failed to start. Error code : %i\n",
+                    g_PluginMap[MapIndex].name, filepath, rval);
         osal_dynlib_close(handle);
         return rval;
     }
+
+#ifndef __OWNER_PTR__
+#define __OWNER_PTR__
+
+template<typename T>
+class OwnerPtr
+{
+public:
+    bool owner;
+    T* raw_ptr;
+    
+    OwnerPtr()
+    {
+        raw_ptr = NULL;
+        owner = true;
+    }
+    
+    OwnerPtr(OwnerPtr<T>& ptr)
+    {
+        if (owner) delete raw_ptr;
+        raw_ptr = ptr;
+        ptr.owner = false; // prevent the older instance from deleting the pointer
+    }
+    
+    OwnerPtr(T* obj)
+    {
+        raw_ptr = obj;
+        owner = true;
+    }
+    
+    ~OwnerPtr()
+    {
+        if (owner) delete raw_ptr;
+#ifndef NDEBUG
+        raw_ptr = (T*)0xDEADBEEF;
+#endif
+    }
+    
+    OwnerPtr& operator=(T* ptr)
+    {
+        if (owner) delete raw_ptr;
+        raw_ptr = ptr;
+        return *this;
+    }
+    OwnerPtr& operator=(OwnerPtr& other)
+    {
+        if (owner) delete raw_ptr;
+        raw_ptr = other.raw_ptr;
+        other.owner = false;
+        return *this;
+    }
+    
+    operator T*()
+    { 
+        return raw_ptr; 
+    }
+    
+    operator const T*() const
+    {
+        return raw_ptr; 
+    }
+    
+    T* operator->() const
+    {
+        return raw_ptr;
+    }
+    
+};
+template<typename T>
+class WxOwnerPtr
+{
+public:
+    T* raw_ptr;
+    
+    WxOwnerPtr()
+    {
+        raw_ptr = NULL;
+    }
+    WxOwnerPtr(T* obj)
+    {
+        raw_ptr = obj;
+    }
+    
+    ~WxOwnerPtr()
+    {
+        if (raw_ptr != NULL) raw_ptr->Destroy();
+    }
+    
+    WxOwnerPtr& operator=(T* ptr)
+    {
+        if (raw_ptr != NULL) raw_ptr->Destroy();
+        
+        raw_ptr = ptr;
+        return *this;
+    }
+    
+    operator T*()
+    { 
+        return raw_ptr; 
+    }
+    
+    T* operator->() const
+    {
+        return raw_ptr;
+    }
+    
+};
+
+#endif

parameterpanel.cpp

         ctrl->SetClientData( curr );
         m_parameter_widgets.push_back(ctrl);
         
-        if (curr->m_need_restart)
+        if (curr->hasCommentString())
         {
             sizer->AddSpacer(1);
             wxStaticText* effect_label = new wxStaticText(this, wxID_ANY,
-                                                          _("* Changes to this parameter will be only effective after restarting Mupen64Plus"));
+                                                          curr->getCommentString());
             effect_label->SetFont( wxFont(wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT,
                                           wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL) );
             sizer->Add( effect_label );
 # waf
 
 # the following two variables are used by the target "waf dist"
-VERSION='0.1'
+VERSION='0.4'
 APPNAME='wxMupen64Plus'
 
 # these variables are mandatory ('/' are converted automatically)
                         'debugger/disasmpanel.cpp', 'debugger/dv_treelist.cpp', 'debugger/memorypanel.cpp',
                         'debugger/registerpanel.cpp', 'debugger/debugconfig.cpp', 'debugger/memorysearch.cpp']
     bld.program(features='c cxx cxxprogram',
-                cxxflags=build_flags+['-std=gnu++0x'],
+                cxxflags=build_flags+['-std=gnu++0x','-fpermissive'],
                 cflags=build_flags+['-Wfatal-errors'],
                 linkflags=link_flags + additional_links,
                 source=['main.cpp', 'gamespanel.cpp', 'parameterpanel.cpp', 'sdlkeypicker.cpp',
 
 [Setup]
 AppName=wxMupen64Plus Combo
-AppVerName=wxMupen64Plus 0.2 (Combo)
-VersionInfoVersion=0.2
+AppVerName=wxMupen64Plus 0.3 (Combo)
+VersionInfoVersion=0.3
 AppPublisher=
 AppPublisherURL=https://bitbucket.org/auria/wxmupen64plus
 AppSupportURL=
 AppCopyright=Copyright Auria
 OutputBaseFilename=wxMupen64PlusSetup
 UninstallDisplayIcon={app}\wxmupen64plus.exe
-LicenseFile=WinRuntime\License.txt
+LicenseFile=License.txt
 DisableStartupPrompt=yes
 ChangesAssociations=yes
 
 Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
 
 [Files]
-Source: "WinRuntime\*"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.bmp"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.png"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.ttf"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.ini"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.cht"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.txt"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.ico"; DestDir: "{app}"; Flags: ignoreversion
+Source: "build\*.exe"; DestDir: "{app}"; Flags: ignoreversion
 
 [Icons]
 Name: "{group}\wxMupen64Plus"; Filename: "{app}\wxmupen64plus.exe"
     }
 #endif
 	
+    std::set<int> toRemove;
+    
     for (it=pressed_keys.begin(); it!=pressed_keys.end(); it++)
     {
         #if defined(__WXOSX__)
             }
             printf("END}\n");
              * */
-            pressed_keys.erase(it);
+            toRemove.insert(*it);
         }
     }
+    
+    for (it=toRemove.begin(); it!=toRemove.end(); it++)
+    {
+        pressed_keys.erase(*it);
+    }
 }
 
 DcHolder* holder = NULL;