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