1 module m64p;
2 
3 import dynalib;
4 
5 import std.stdio : writeln;
6 
7 private __gshared m64p_handle coreHandle;
8 private __gshared m64p_handle audioHandle;
9 private __gshared m64p_handle inputHandle;
10 private __gshared m64p_handle rspHandle;
11 private __gshared m64p_handle videoHandle;
12 
13 public:
14 
15     import m64p_common;
16     import m64p_conditionals;
17     import m64p_config;
18     import m64p_debugger;
19     import m64p_frontend;
20     import m64p_plugin;
21     import m64p_types;
22     import m64p_vidext;
23 
24     m64p_handle m64p_coreHandle() { return coreHandle; }
25     bool m64p_coreIsLoaded() { return coreHandle != null; }
26 
27     m64p_error m64p_loadCore()
28     {
29         if (m64p_coreIsLoaded) return M64ERR_SUCCESS;
30 
31         DynaLib lib;
32         if (!lib.loadFromConfig("mupen64plus", "mupen64plus-core"))
33         {
34             writeln("There was a problem loading mupen64plus-core");
35             return M64ERR_NOT_INIT;
36         } coreHandle = lib.handle;
37 
38         m64p_coreBind(&lib);
39     
40         return M64ERR_SUCCESS;
41     }
42 
43     m64p_error m64p_loadCore(string libDir = "", string depDir = "!")
44     {
45         if (m64p_coreIsLoaded) return M64ERR_SUCCESS;
46 
47         DynaLib lib;
48         if (!lib.load("mupen64plus", libDir, depDir))
49         {
50             writeln("There was a problem loading mupen64plus-core");
51             return M64ERR_NOT_INIT;
52         } coreHandle = lib.handle;
53 
54         m64p_coreBind(&lib);
55     
56         return M64ERR_SUCCESS;
57     }
58 
59     private void m64p_coreBind(DynaLib* lib)
60     {
61         import m64p_conditionals;
62 
63         /* Common */
64         lib.bind(&PluginGetVersion,"PluginGetVersion");
65         lib.bind(&CoreGetAPIVersions,"CoreGetAPIVersions");
66         lib.bind(&CoreErrorMessage,"CoreErrorMessage");
67             
68         /* Config */
69         lib.bind(&ConfigListSections,"ConfigListSections");
70         lib.bind(&ConfigOpenSection,"ConfigOpenSection");
71         lib.bind(&ConfigListParameters,"ConfigListParameters");
72         lib.bind(&ConfigSaveFile,"ConfigSaveFile");
73         lib.bind(&ConfigSaveSection,"ConfigSaveSection");
74         lib.bind(&ConfigHasUnsavedChanges,"ConfigHasUnsavedChanges");
75         lib.bind(&ConfigDeleteSection,"ConfigDeleteSection");
76         lib.bind(&ConfigRevertChanges,"ConfigRevertChanges");
77         lib.bind(&ConfigSetParameter,"ConfigSetParameter");
78         lib.bind(&ConfigSetParameterHelp,"ConfigSetParameterHelp");
79         lib.bind(&ConfigGetParameter,"ConfigGetParameter");
80         lib.bind(&ConfigGetParameterType,"ConfigGetParameterType");
81         lib.bind(&ConfigGetParameterHelp,"ConfigGetParameterHelp");
82         lib.bind(&ConfigSetDefaultInt,"ConfigSetDefaultInt");
83         lib.bind(&ConfigSetDefaultFloat,"ConfigSetDefaultFloat");
84         lib.bind(&ConfigSetDefaultBool,"ConfigSetDefaultBool");
85         lib.bind(&ConfigSetDefaultString,"ConfigSetDefaultString");
86         lib.bind(&ConfigGetParamInt,"ConfigGetParamInt");
87         lib.bind(&ConfigGetParamFloat,"ConfigGetParamFloat");
88         lib.bind(&ConfigGetParamBool,"ConfigGetParamBool");
89         lib.bind(&ConfigGetParamString,"ConfigGetParamString");
90         lib.bind(&ConfigGetSharedDataFilepath,"ConfigGetSharedDataFilepath");
91         lib.bind(&ConfigGetUserConfigPath,"ConfigGetUserConfigPath");
92         lib.bind(&ConfigGetUserDataPath,"ConfigGetUserDataPath");
93         lib.bind(&ConfigGetUserCachePath,"ConfigGetUserCachePath");
94         lib.bind(&ConfigExternalOpen,"ConfigExternalOpen");
95         lib.bind(&ConfigExternalClose,"ConfigExternalClose");
96         lib.bind(&ConfigExternalGetParameter,"ConfigExternalGetParameter");
97         lib.bind(&ConfigSendNetplayConfig,"ConfigSendNetplayConfig");
98         lib.bind(&ConfigReceiveNetplayConfig,"ConfigReceiveNetplayConfig");
99         lib.bind(&ConfigOverrideUserPaths,"ConfigOverrideUserPaths");
100             
101         /* Debug */
102         lib.bind(&DebugSetCallbacks,"DebugSetCallbacks");
103         lib.bind(&DebugSetCoreCompare,"DebugSetCoreCompare");
104         lib.bind(&DebugSetRunState,"DebugSetRunState");
105         lib.bind(&DebugGetState,"DebugGetState");
106         lib.bind(&DebugStep,"DebugStep");
107         lib.bind(&DebugDecodeOp,"DebugDecodeOp");
108         lib.bind(&DebugMemGetRecompInfo,"DebugMemGetRecompInfo");
109         lib.bind(&DebugMemGetMemInfo,"DebugMemGetMemInfo");
110         lib.bind(&DebugMemGetPointer,"DebugMemGetPointer");
111         lib.bind(&DebugMemRead64,"DebugMemRead64");
112         lib.bind(&DebugMemRead32,"DebugMemRead32");
113         lib.bind(&DebugMemRead16,"DebugMemRead16");
114         lib.bind(&DebugMemRead8,"DebugMemRead8");
115         lib.bind(&DebugMemWrite64,"DebugMemWrite64");
116         lib.bind(&DebugMemWrite32,"DebugMemWrite32");
117         lib.bind(&DebugMemWrite16,"DebugMemWrite16");
118         lib.bind(&DebugMemWrite8,"DebugMemWrite8");
119         lib.bind(&DebugGetCPUDataPtr,"DebugGetCPUDataPtr");
120         lib.bind(&DebugBreakpointLookup,"DebugBreakpointLookup");
121         lib.bind(&DebugBreakpointCommand,"DebugBreakpointCommand");
122         lib.bind(&DebugBreakpointTriggeredBy,"DebugBreakpointTriggeredBy");
123         lib.bind(&DebugVirtualToPhysical,"DebugVirtualToPhysical");
124             
125         /* Front-End */
126         lib.bind(&CoreStartup,"CoreStartup");
127         lib.bind(&CoreShutdown,"CoreShutdown");
128         lib.bind(&CoreAttachPlugin,"CoreAttachPlugin");
129         lib.bind(&CoreDetachPlugin,"CoreDetachPlugin");
130         lib.bind(&CoreDoCommand,"CoreDoCommand");
131         lib.bind(&CoreOverrideVidExt,"CoreOverrideVidExt");
132         lib.bind(&CoreAddCheat,"CoreAddCheat");
133         lib.bind(&CoreCheatEnabled,"CoreCheatEnabled");
134         lib.bind(&CoreGetRomSettings,"CoreGetRomSettings");
135 
136         if (
137             lib.bind(&CoreSaveOverride,"CoreSaveOverride") &&
138             lib.bind(&GetHeader,"GetHeader") &&
139             lib.bind(&GetRdRam,"GetRdRam") &&
140             lib.bind(&GetRom,"GetRom") &&
141             lib.bind(&GetRdRamSize,"GetRdRamSize") &&
142             lib.bind(&GetRomSize,"GetRomSize") &&
143             lib.bind(&RefreshDynarec,"RefreshDynarec")
144         ) {
145             version(DL_NOTIFICATION)
146                 writeln("Dynalib-Conditional: [M64P] Modding supported.");
147             (cast(bool*)&conditional_Modding)[0] = true;
148         } else (cast(bool*)&conditional_Modding)[0] = false;
149 
150         /* Plugin */
151 
152         /* VidExt */
153         lib.bind(&VidExt_Init,"VidExt_Init");
154         lib.bind(&VidExt_Quit,"VidExt_Quit");
155         lib.bind(&VidExt_ListFullscreenModes,"VidExt_ListFullscreenModes");
156         lib.bind(&VidExt_ListFullscreenRates,"VidExt_ListFullscreenRates");
157         lib.bind(&VidExt_SetVideoMode,"VidExt_SetVideoMode");
158         lib.bind(&VidExt_SetVideoModeWithRate,"VidExt_SetVideoModeWithRate");
159         lib.bind(&VidExt_ResizeWindow,"VidExt_ResizeWindow");
160         lib.bind(&VidExt_SetCaption,"VidExt_SetCaption");
161         lib.bind(&VidExt_ToggleFullScreen,"VidExt_ToggleFullScreen");
162         lib.bind(&VidExt_GL_GetProcAddress,"VidExt_GL_GetProcAddress");
163         lib.bind(&VidExt_GL_SetAttribute,"VidExt_GL_SetAttribute");
164         lib.bind(&VidExt_GL_GetAttribute,"VidExt_GL_GetAttribute");
165         lib.bind(&VidExt_GL_SwapBuffers,"VidExt_GL_SwapBuffers");
166         lib.bind(&VidExt_GL_GetDefaultFramebuffer,"VidExt_GL_GetDefaultFramebuffer");
167     }
168 
169     m64p_error m64p_unloadCore()
170     {
171         if (!m64p_coreIsLoaded) return M64ERR_NOT_INIT;
172 
173         /* In case plugins are attached */
174         m64p_detachPlugins();
175 
176         unloadLib(coreHandle);
177         coreHandle = null;
178 
179         /* Common */
180         PluginGetVersion = null;
181         CoreGetAPIVersions = null;
182         CoreErrorMessage = null;
183         PluginStartup = null;
184         PluginShutdown = null;
185 
186         /* Config */
187         ConfigListSections = null;
188         ConfigOpenSection = null;
189         ConfigListParameters = null;
190         ConfigSaveFile = null;
191         ConfigSaveSection = null;
192         ConfigHasUnsavedChanges = null;
193         ConfigDeleteSection = null;
194         ConfigRevertChanges = null;
195         ConfigSetParameter = null;
196         ConfigSetParameterHelp = null;
197         ConfigGetParameter = null;
198         ConfigGetParameterType = null;
199         ConfigGetParameterHelp = null;
200         ConfigSetDefaultInt = null;
201         ConfigSetDefaultFloat = null;
202         ConfigSetDefaultBool = null;
203         ConfigSetDefaultString = null;
204         ConfigGetParamInt = null;
205         ConfigGetParamFloat = null;
206         ConfigGetParamBool = null;
207         ConfigGetParamString = null;
208         ConfigGetSharedDataFilepath = null;
209         ConfigGetUserConfigPath = null;
210         ConfigGetUserDataPath = null;
211         ConfigGetUserCachePath = null;
212         ConfigExternalOpen = null;
213         ConfigExternalClose = null;
214         ConfigExternalGetParameter = null;
215         ConfigSendNetplayConfig = null;
216         ConfigReceiveNetplayConfig = null;
217         ConfigOverrideUserPaths = null;
218 
219         /* Debug */
220         DebugSetCallbacks = null;
221         DebugSetCoreCompare = null;
222         DebugSetRunState = null;
223         DebugGetState = null;
224         DebugStep = null;
225         DebugDecodeOp = null;
226         DebugMemGetRecompInfo = null;
227         DebugMemGetMemInfo = null;
228         DebugMemGetPointer = null;
229         DebugMemRead64 = null;
230         DebugMemRead32 = null;
231         DebugMemRead16 = null;
232         DebugMemRead8 = null;
233         DebugMemWrite64 = null;
234         DebugMemWrite32 = null;
235         DebugMemWrite16 = null;
236         DebugMemWrite8 = null;
237         DebugGetCPUDataPtr = null;
238         DebugBreakpointLookup = null;
239         DebugBreakpointCommand = null;
240         DebugBreakpointTriggeredBy = null;
241         DebugVirtualToPhysical = null;
242 
243         /* Front-End */
244         CoreStartup = null;
245         CoreShutdown = null;
246         CoreAttachPlugin = null;
247         CoreDetachPlugin = null;
248         CoreDoCommand = null;
249         CoreOverrideVidExt = null;
250         CoreAddCheat = null;
251         CoreCheatEnabled = null;
252         version(Modding)
253         {
254             CoreSaveOverride = null;
255             GetHeader = null;
256             GetRdRam = null;
257             GetRom = null;
258             GetRdRamSize = null;
259             GetRomSize = null;
260             RefreshDynarec = null;
261         }
262 
263         /* Plugin */
264 
265         /* VidExt */
266         VidExt_Init = null;
267         VidExt_Quit = null;
268         VidExt_ListFullscreenModes = null;
269         VidExt_ListFullscreenRates = null;
270         VidExt_SetVideoMode = null;
271         VidExt_SetVideoModeWithRate = null;
272         VidExt_ResizeWindow = null;
273         VidExt_SetCaption = null;
274         VidExt_ToggleFullScreen = null;
275         VidExt_GL_GetProcAddress = null;
276         VidExt_GL_SetAttribute = null;
277         VidExt_GL_GetAttribute = null;
278         VidExt_GL_SwapBuffers = null;
279         VidExt_GL_GetDefaultFramebuffer = null;
280 
281         return M64ERR_SUCCESS;
282     }
283 
284     bool m64p_pluginIsLoaded(m64p_plugin_type type)
285     {
286         switch (type)
287         {
288             case M64PLUGIN_CORE: return coreHandle != null;
289             case M64PLUGIN_AUDIO: return audioHandle != null;
290             case M64PLUGIN_INPUT: return inputHandle != null;
291             case M64PLUGIN_RSP: return rspHandle != null;
292             case M64PLUGIN_GFX: return videoHandle != null;
293             default: return false;
294         }
295     }
296 
297     m64p_error m64p_attachPlugins(DebugCallback debugCallback,
298                                   string videoPlugin, string audioPlugin,
299                                   string inputPlugin, string rspPlugin,
300                                   string libDir = "", string depDir = "!")
301     {
302         auto success =
303         (
304             (m64p_loadPlugin(&videoHandle, M64PLUGIN_GFX, debugCallback,
305                 libDir, videoPlugin, depDir) == M64ERR_SUCCESS) &&
306             (m64p_loadPlugin(&audioHandle, M64PLUGIN_AUDIO, debugCallback,
307                 libDir, audioPlugin, depDir) == M64ERR_SUCCESS) &&
308             (m64p_loadPlugin(&inputHandle, M64PLUGIN_INPUT, debugCallback,
309                 libDir, inputPlugin, depDir) == M64ERR_SUCCESS) &&
310             (m64p_loadPlugin(&rspHandle, M64PLUGIN_RSP, debugCallback,
311                 libDir, rspPlugin, depDir) == M64ERR_SUCCESS)
312         );
313         
314         /* Successfully loaded all plugins */
315         if (success) return M64ERR_SUCCESS;
316 
317         /* Failed horribly! Revert! */
318         m64p_detachPlugins();
319         return M64ERR_PLUGIN_FAIL;
320     }
321 
322     void m64p_detachPlugins()
323     {
324         m64p_unloadPlugin(&rspHandle);
325         m64p_unloadPlugin(&inputHandle);
326         m64p_unloadPlugin(&audioHandle);
327         m64p_unloadPlugin(&videoHandle);
328     }
329 
330     private m64p_error m64p_loadPlugin(m64p_handle* plug, m64p_plugin_type type, DebugCallback callback,
331                                        string path, string name, string depsPath = "!")
332     {
333         /* Check if core is attached */
334         if (coreHandle == null) return M64ERR_NOT_INIT;
335 
336         /* Check if already attached */
337         if (*plug != null) return M64ERR_INVALID_STATE;
338 
339         /* Load the lib */
340         DynaLib lib; lib.load(name, path, depsPath);
341         if (!lib.isLoaded)
342         {
343             writeln("Mupen64Plus: failed to find ", name);
344             return M64ERR_INPUT_NOT_FOUND;
345         }
346 
347         /* Initialize the plugin */
348         lib.bind(&PluginStartup, "PluginStartup");
349         PluginStartup(coreHandle, cast(void*) (name ~ 0x00), callback);
350         PluginStartup = null;
351 
352         /* Attempt attaching it to core lib */
353         if (CoreAttachPlugin(type, lib.handle) != M64ERR_SUCCESS)
354         {
355             lib.unload();
356             return M64ERR_NOT_INIT;
357         }
358 
359         *plug = lib.handle;
360         return M64ERR_SUCCESS;
361     }
362 
363     private m64p_error m64p_unloadPlugin(m64p_handle* plug)
364     {
365         if (coreHandle == null) return M64ERR_NOT_INIT;
366 
367         /* Check if not already attached */
368         if (*plug == null) return M64ERR_INVALID_STATE;
369             
370         /* Shutdown the plugin */
371         bindSymbol(*plug, cast(void**)&PluginShutdown,"PluginShutdown");
372         PluginShutdown();
373         PluginShutdown = null;
374 
375         /* Detach the lib */
376         unloadLib(*plug);
377         *plug = null;
378 
379         return M64ERR_SUCCESS;
380     }