ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / Main.cpp
1 /*
2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002  Dave2001
4 * Copyright (c) 2003-2009  Sergey 'Gonetz' Lipski
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 //****************************************************************
22 //
23 // Glide64 - Glide Plugin for Nintendo 64 emulators
24 // Project started on December 29th, 2001
25 //
26 // Authors:
27 // Dave2001, original author, founded the project in 2001, left it in 2002
28 // Gugaman, joined the project in 2002, left it in 2002
29 // Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
30 // Hiroshi 'KoolSmoky' Morii, joined the project in 2007
31 //
32 //****************************************************************
33 //
34 // To modify Glide64:
35 // * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
36 // * Do NOT send me the whole project or file that you modified.  Take out your modified code sections, and tell me where to put them.  If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
37 //
38 //****************************************************************
39
40 #include "Gfx_1.3.h"
41 #include "Ini.h"
42 #include "Config.h"
43 #include "Util.h"
44 #include "3dmath.h"
45 #include "Debugger.h"
46 #include "Combine.h"
47 #include "TexCache.h"
48 #include "CRC.h"
49 #include "FBtoScreen.h"
50 #include "DepthBufferRender.h"
51
52 #if defined(__GNUC__)
53 #include <sys/time.h>
54 #elif defined(__MSC__)
55 #include <time.h>
56 #define PATH_MAX MAX_PATH
57 #endif
58 #ifndef PATH_MAX
59   #define PATH_MAX 4096
60 #endif
61 #include "osal_dynamiclib.h"
62 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
63 #include <stdarg.h>
64 int  ghq_dmptex_toggle_key = 0;
65 #endif
66 #if defined(__MINGW32__)
67 #define swprintf _snwprintf
68 #define vswprintf _vsnwprintf
69 #endif
70
71 #define G64_VERSION "G64 Mk2"
72 #define RELTIME "Date: " __DATE__// " Time: " __TIME__
73
74 #ifdef EXT_LOGGING
75 std::ofstream extlog;
76 #endif
77
78 #ifdef LOGGING
79 std::ofstream loga;
80 #endif
81
82 #ifdef RDP_LOGGING
83 int log_open = FALSE;
84 std::ofstream rdp_log;
85 #endif
86
87 #ifdef RDP_ERROR_LOG
88 int elog_open = FALSE;
89 std::ofstream rdp_err;
90 #endif
91
92 GFX_INFO gfx;
93
94 /* definitions of pointers to Core config functions */
95 ptr_ConfigOpenSection      ConfigOpenSection = NULL;
96 ptr_ConfigSetParameter     ConfigSetParameter = NULL;
97 ptr_ConfigGetParameter     ConfigGetParameter = NULL;
98 ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
99 ptr_ConfigSetDefaultInt    ConfigSetDefaultInt = NULL;
100 ptr_ConfigSetDefaultFloat  ConfigSetDefaultFloat = NULL;
101 ptr_ConfigSetDefaultBool   ConfigSetDefaultBool = NULL;
102 ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
103 ptr_ConfigGetParamInt      ConfigGetParamInt = NULL;
104 ptr_ConfigGetParamFloat    ConfigGetParamFloat = NULL;
105 ptr_ConfigGetParamBool     ConfigGetParamBool = NULL;
106 ptr_ConfigGetParamString   ConfigGetParamString = NULL;
107
108 ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
109 ptr_ConfigGetUserConfigPath     ConfigGetUserConfigPath = NULL;
110 ptr_ConfigGetUserDataPath       ConfigGetUserDataPath = NULL;
111 ptr_ConfigGetUserCachePath      ConfigGetUserCachePath = NULL;
112
113 /* definitions of pointers to Core video extension functions */
114 ptr_VidExt_Init                  CoreVideo_Init = NULL;
115 ptr_VidExt_Quit                  CoreVideo_Quit = NULL;
116 ptr_VidExt_ListFullscreenModes   CoreVideo_ListFullscreenModes = NULL;
117 ptr_VidExt_SetVideoMode          CoreVideo_SetVideoMode = NULL;
118 ptr_VidExt_SetCaption            CoreVideo_SetCaption = NULL;
119 ptr_VidExt_ToggleFullScreen      CoreVideo_ToggleFullScreen = NULL;
120 ptr_VidExt_ResizeWindow          CoreVideo_ResizeWindow = NULL;
121 ptr_VidExt_GL_GetProcAddress     CoreVideo_GL_GetProcAddress = NULL;
122 ptr_VidExt_GL_SetAttribute       CoreVideo_GL_SetAttribute = NULL;
123 ptr_VidExt_GL_SwapBuffers        CoreVideo_GL_SwapBuffers = NULL;
124 int to_fullscreen = FALSE;
125 int fullscreen = FALSE;
126 int romopen = FALSE;
127 GrContext_t gfx_context = 0;
128 int debugging = FALSE;
129 int exception = FALSE;
130
131 int evoodoo = 0;
132 int ev_fullscreen = 0;
133
134 #ifdef __WINDOWS__
135 #define WINPROC_OVERRIDE
136 #endif
137
138 #ifdef WINPROC_OVERRIDE
139 LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
140 WNDPROC oldWndProc = NULL;
141 WNDPROC myWndProc = NULL;
142 #endif
143
144 #ifdef ALTTAB_FIX
145 HHOOK hhkLowLevelKybd = NULL;
146 LRESULT CALLBACK LowLevelKeyboardProc(int nCode,
147                                       WPARAM wParam, LPARAM lParam);
148 #endif
149
150 #ifdef PERFORMANCE
151 int64 perf_cur;
152 int64 perf_next;
153 #endif
154
155 #ifdef FPS
156 LARGE_INTEGER perf_freq;
157 LARGE_INTEGER fps_last;
158 LARGE_INTEGER fps_next;
159 float      fps = 0.0f;
160 wxUint32   fps_count = 0;
161
162 wxUint32   vi_count = 0;
163 float      vi = 0.0f;
164
165 wxUint32   region = 0;
166
167 float      ntsc_percent = 0.0f;
168 float      pal_percent = 0.0f;
169
170 #endif
171
172 // ref rate
173 // 60=0x0, 70=0x1, 72=0x2, 75=0x3, 80=0x4, 90=0x5, 100=0x6, 85=0x7, 120=0x8, none=0xff
174
175 #ifdef PAULSCODE
176 //#include "ae_bridge.h"
177 #include "FrameSkipper.h"
178 FrameSkipper frameSkipper;
179 void vbo_resetcount();
180 #endif
181
182 unsigned long BMASK = 0x7FFFFF;
183 // Reality display processor structure
184 RDP rdp;
185
186 SETTINGS settings = { FALSE, 640, 480, GR_RESOLUTION_640x480, 0 };
187
188 HOTKEY_INFO hotkey_info;
189
190 VOODOO voodoo = {0, 0, 0, 0,
191                  0, 0, 0, 0,
192                  0, 0, 0, 0
193                 };
194
195 GrTexInfo fontTex;
196 GrTexInfo cursorTex;
197 wxUint32   offset_font = 0;
198 wxUint32   offset_cursor = 0;
199 wxUint32   offset_textures = 0;
200 wxUint32   offset_texbuf1 = 0;
201
202 int    capture_screen = 0;
203 char    capture_path[256];
204
205 //SDL_sem *mutexProcessDList = SDL_CreateSemaphore(1);
206
207 // SOME FUNCTION DEFINITIONS 
208
209 static void DrawFrameBuffer ();
210
211
212 void (*renderCallback)(int) = NULL;
213 static void (*l_DebugCallback)(void *, int, const char *) = NULL;
214 static void *l_DebugCallContext = NULL;
215
216 void _ChangeSize ()
217 {
218   rdp.scale_1024 = settings.scr_res_x / 1024.0f;
219   rdp.scale_768 = settings.scr_res_y / 768.0f;
220
221 //  float res_scl_x = (float)settings.res_x / 320.0f;
222   float res_scl_y = (float)settings.res_y / 240.0f;
223
224   wxUint32 scale_x = *gfx.VI_X_SCALE_REG & 0xFFF;
225   if (!scale_x) return;
226   wxUint32 scale_y = *gfx.VI_Y_SCALE_REG & 0xFFF;
227   if (!scale_y) return;
228
229   float fscale_x = (float)scale_x / 1024.0f;
230   float fscale_y = (float)scale_y / 2048.0f;
231
232   wxUint32 dwHStartReg = *gfx.VI_H_START_REG;
233   wxUint32 dwVStartReg = *gfx.VI_V_START_REG;
234
235   wxUint32 hstart = dwHStartReg >> 16;
236   wxUint32 hend = dwHStartReg & 0xFFFF;
237
238   // dunno... but sometimes this happens
239   if (hend == hstart) hend = (int)(*gfx.VI_WIDTH_REG / fscale_x);
240
241   wxUint32 vstart = dwVStartReg >> 16;
242   wxUint32 vend = dwVStartReg & 0xFFFF;
243
244   rdp.vi_width = (hend - hstart) * fscale_x;
245   rdp.vi_height = (vend - vstart) * fscale_y * 1.0126582f;
246   float aspect = (settings.adjust_aspect && (fscale_y > fscale_x) && (rdp.vi_width > rdp.vi_height)) ? fscale_x/fscale_y : 1.0f;
247
248 #ifdef LOGGING
249   sprintf (out_buf, "hstart: %d, hend: %d, vstart: %d, vend: %d\n", hstart, hend, vstart, vend);
250   LOG (out_buf);
251   sprintf (out_buf, "size: %d x %d\n", (int)rdp.vi_width, (int)rdp.vi_height);
252   LOG (out_buf);
253 #endif
254
255   rdp.scale_x = (float)settings.res_x / rdp.vi_width;
256   if (region > 0 && settings.pal230)
257   {
258     // odd... but pal games seem to want 230 as height...
259     rdp.scale_y = res_scl_y * (230.0f / rdp.vi_height)  * aspect;
260   }
261   else
262   {
263     rdp.scale_y = (float)settings.res_y / rdp.vi_height * aspect;
264   }
265   //  rdp.offset_x = settings.offset_x * res_scl_x;
266   //  rdp.offset_y = settings.offset_y * res_scl_y;
267   //rdp.offset_x = 0;
268   //  rdp.offset_y = 0;
269   rdp.offset_y = ((float)settings.res_y - rdp.vi_height * rdp.scale_y) * 0.5f;
270   if (((wxUint32)rdp.vi_width <= (*gfx.VI_WIDTH_REG)/2) && (rdp.vi_width > rdp.vi_height))
271     rdp.scale_y *= 0.5f;
272
273   rdp.scissor_o.ul_x = 0;
274   rdp.scissor_o.ul_y = 0;
275   rdp.scissor_o.lr_x = (wxUint32)rdp.vi_width;
276   rdp.scissor_o.lr_y = (wxUint32)rdp.vi_height;
277
278   rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR;
279 }
280
281 void ChangeSize ()
282 {
283   if (debugging)
284   {
285     _ChangeSize ();
286     return;
287   }
288   switch (settings.aspectmode)
289   {
290   case 0: //4:3
291     if (settings.scr_res_x >= settings.scr_res_y * 4.0f / 3.0f) {
292       settings.res_y = settings.scr_res_y;
293       settings.res_x = (wxUint32)(settings.res_y * 4.0f / 3.0f);
294     } else {
295       settings.res_x = settings.scr_res_x;
296       settings.res_y = (wxUint32)(settings.res_x / 4.0f * 3.0f);
297     }
298     break;
299   case 1: //16:9
300     if (settings.scr_res_x >= settings.scr_res_y * 16.0f / 9.0f) {
301       settings.res_y = settings.scr_res_y;
302       settings.res_x = (wxUint32)(settings.res_y * 16.0f / 9.0f);
303     } else {
304       settings.res_x = settings.scr_res_x;
305       settings.res_y = (wxUint32)(settings.res_x / 16.0f * 9.0f);
306     }
307     break;
308   default: //stretch or original
309     settings.res_x = settings.scr_res_x;
310     settings.res_y = settings.scr_res_y;
311   }
312   _ChangeSize ();
313   rdp.offset_x = (settings.scr_res_x - settings.res_x) / 2.0f;
314   float offset_y = (settings.scr_res_y - settings.res_y) / 2.0f;
315   settings.res_x += (wxUint32)rdp.offset_x;
316   settings.res_y += (wxUint32)offset_y;
317   rdp.offset_y += offset_y;
318   if (settings.aspectmode == 3) // original
319   {
320           rdp.scale_x = rdp.scale_y = 1.0f;
321           rdp.offset_x = (settings.scr_res_x - rdp.vi_width) / 2.0f;
322           rdp.offset_y = (settings.scr_res_y - rdp.vi_height) / 2.0f;
323   }
324   //    settings.res_x = settings.scr_res_x;
325   //    settings.res_y = settings.scr_res_y;
326 }
327
328 void ConfigWrapper()
329 {
330   char strConfigWrapperExt[] = "grConfigWrapperExt";
331   GRCONFIGWRAPPEREXT grConfigWrapperExt = (GRCONFIGWRAPPEREXT)grGetProcAddress(strConfigWrapperExt);
332   if (grConfigWrapperExt)
333     grConfigWrapperExt(settings.wrpResolution, settings.wrpVRAM * 1024 * 1024, settings.wrpFBO, settings.wrpAnisotropic);
334 }
335 /*
336 static wxConfigBase * OpenIni()
337 {
338   wxConfigBase * ini = wxConfigBase::Get(false);
339   if (!ini)
340   {
341     if (iniName.IsEmpty())
342       iniName = pluginPath + wxT("/Glide64mk2.ini");
343     if (wxFileExists(iniName))
344     {
345       wxFileInputStream is(iniName);
346       wxFileConfig * fcfg = new wxFileConfig(is, wxConvISO8859_1);
347       wxConfigBase::Set(fcfg);
348       ini = fcfg;
349     }
350   }
351   if (!ini)
352     wxMessageBox(_T("Can not find ini file! Plugin will not run properly."), _T("File not found"), wxOK|wxICON_EXCLAMATION);
353   return ini;
354 }
355 */
356 #ifndef OLDAPI
357 void WriteLog(m64p_msg_level level, const char *msg, ...)
358 {
359   char buf[1024];
360   va_list args;
361   va_start(args, msg);
362   vsnprintf(buf, 1023, msg, args);
363   buf[1023]='\0';
364   va_end(args);
365   if (l_DebugCallback)
366   {
367     l_DebugCallback(l_DebugCallContext, level, buf);
368   }
369 }
370 #endif
371
372 void ReadSettings ()
373 {
374   //  LOG("ReadSettings\n");
375   if (!Config_Open())
376   {
377     ERRLOG("Could not open configuration!");
378     return;
379   }
380
381   settings.card_id = (BYTE)Config_ReadInt ("card_id", "Card ID", 0, TRUE, FALSE);
382   //settings.lang_id not needed
383   // depth_bias = -Config_ReadInt ("depth_bias", "Depth bias level", 0, TRUE, FALSE);
384   settings.res_data = 0;
385   settings.scr_res_x = settings.res_x = Config_ReadScreenInt("ScreenWidth");
386   settings.scr_res_y = settings.res_y = Config_ReadScreenInt("ScreenHeight");
387
388   settings.vsync = (BOOL)Config_ReadInt ("vsync", "Vertical sync", 0);
389   settings.ssformat = (BOOL)Config_ReadInt("ssformat", "TODO:ssformat", 0);
390   //settings.fast_crc = (BOOL)Config_ReadInt ("fast_crc", "Fast CRC", 0);
391
392   settings.show_fps = (BYTE)Config_ReadInt ("show_fps", "Display performance stats (add together desired flags): 1=FPS counter, 2=VI/s counter, 4=% speed, 8=FPS transparent", 0, TRUE, FALSE);
393   settings.clock = (BOOL)Config_ReadInt ("clock", "Clock enabled", 0);
394   settings.clock_24_hr = (BOOL)Config_ReadInt ("clock_24_hr", "Clock is 24-hour", 0);
395   // settings.advanced_options only good for GUI config
396   // settings.texenh_options = only good for GUI config
397   //settings.use_hotkeys = ini->Read(_T("hotkeys"), 1l);
398
399   settings.wrpResolution = (BYTE)Config_ReadInt ("wrpResolution", "Wrapper resolution", 0, TRUE, FALSE);
400   settings.wrpVRAM = (BYTE)Config_ReadInt ("wrpVRAM", "Wrapper VRAM", 0, TRUE, FALSE);
401   settings.wrpFBO = (BOOL)Config_ReadInt ("wrpFBO", "Wrapper FBO", 1, TRUE, TRUE);
402   settings.wrpAnisotropic = (BOOL)Config_ReadInt ("wrpAnisotropic", "Wrapper Anisotropic Filtering", 0, TRUE, TRUE);
403
404 #ifndef _ENDUSER_RELEASE_
405   settings.autodetect_ucode = (BOOL)Config_ReadInt ("autodetect_ucode", "Auto-detect microcode", 1);
406   settings.ucode = (wxUint32)Config_ReadInt ("ucode", "Force microcode", 2, TRUE, FALSE);
407   settings.wireframe = (BOOL)Config_ReadInt ("wireframe", "Wireframe display", 0);
408   settings.wfmode = (int)Config_ReadInt ("wfmode", "Wireframe mode: 0=Normal colors, 1=Vertex colors, 2=Red only", 1, TRUE, FALSE);
409
410   settings.logging = (BOOL)Config_ReadInt ("logging", "Logging", 0);
411   settings.log_clear = (BOOL)Config_ReadInt ("log_clear", "", 0);
412
413   settings.run_in_window = (BOOL)Config_ReadInt ("run_in_window", "", 0);
414
415   settings.elogging = (BOOL)Config_ReadInt ("elogging", "", 0);
416   settings.filter_cache = (BOOL)Config_ReadInt ("filter_cache", "Filter cache", 0);
417   settings.unk_as_red = (BOOL)Config_ReadInt ("unk_as_red", "Display unknown combines as red", 0);
418   settings.log_unk = (BOOL)Config_ReadInt ("log_unk", "Log unknown combines", 0);
419   settings.unk_clear = (BOOL)Config_ReadInt ("unk_clear", "", 0);
420 #else
421   settings.autodetect_ucode = TRUE;
422   settings.ucode = 2;
423   settings.wireframe = FALSE;
424   settings.wfmode = 0;
425   settings.logging = FALSE;
426   settings.log_clear = FALSE;
427   settings.run_in_window = FALSE;
428   settings.elogging = FALSE;
429   settings.filter_cache = FALSE;
430   settings.unk_as_red = FALSE;
431   settings.log_unk = FALSE;
432   settings.unk_clear = FALSE;
433 #endif
434
435 #ifdef TEXTURE_FILTER
436   
437   // settings.ghq_fltr range is 0 through 6
438   // Filters:\nApply a filter to either smooth or sharpen textures.\nThere are 4 different smoothing filters and 2 different sharpening filters.\nThe higher the number, the stronger the effect,\ni.e. \"Smoothing filter 4\" will have a much more noticeable effect than \"Smoothing filter 1\".\nBe aware that performance may have an impact depending on the game and/or the PC.\n[Recommended: your preference]
439   // _("None"),
440   // _("Smooth filtering 1"),
441   // _("Smooth filtering 2"),
442   // _("Smooth filtering 3"),
443   // _("Smooth filtering 4"),
444   // _("Sharp filtering 1"),
445   // _("Sharp filtering 2")
446
447 // settings.ghq_cmpr 0=S3TC and 1=FXT1
448
449 //settings.ghq_ent is ___
450 // "Texture enhancement:\n7 different filters are selectable here, each one with a distinctive look.\nBe aware of possible performance impacts.\n\nIMPORTANT: 'Store' mode - saves textures in cache 'as is'. It can improve performance in games, which load many textures.\nDisable 'Ignore backgrounds' option for better result.\n\n[Recommended: your preference]"
451
452
453
454   settings.ghq_fltr = Config_ReadInt ("ghq_fltr", "Texture Enhancement: Smooth/Sharpen Filters", 0, TRUE, FALSE);
455   settings.ghq_cmpr = Config_ReadInt ("ghq_cmpr", "Texture Compression: 0 for S3TC, 1 for FXT1", 0, TRUE, FALSE);
456   settings.ghq_enht = Config_ReadInt ("ghq_enht", "Texture Enhancement: More filters", 0, TRUE, FALSE);
457   settings.ghq_hirs = Config_ReadInt ("ghq_hirs", "Hi-res texture pack format (0 for none, 1 for Rice)", 0, TRUE, FALSE);
458   settings.ghq_enht_cmpr  = Config_ReadInt ("ghq_enht_cmpr", "Compress texture cache with S3TC or FXT1", 0, TRUE, TRUE);
459   settings.ghq_enht_tile = Config_ReadInt ("ghq_enht_tile", "Tile textures (saves memory but could cause issues)", 0, TRUE, FALSE);
460   settings.ghq_enht_f16bpp = Config_ReadInt ("ghq_enht_f16bpp", "Force 16bpp textures (saves ram but lower quality)", 0, TRUE, TRUE);
461   settings.ghq_enht_gz  = Config_ReadInt ("ghq_enht_gz", "Compress texture cache", 1, TRUE, TRUE);
462   settings.ghq_enht_nobg  = Config_ReadInt ("ghq_enht_nobg", "Don't enhance textures for backgrounds", 0, TRUE, TRUE);
463   settings.ghq_hirs_cmpr  = Config_ReadInt ("ghq_hirs_cmpr", "Enable S3TC and FXT1 compression", 0, TRUE, TRUE);
464   settings.ghq_hirs_tile = Config_ReadInt ("ghq_hirs_tile", "Tile hi-res textures (saves memory but could cause issues)", 0, TRUE, TRUE);
465   settings.ghq_hirs_f16bpp = Config_ReadInt ("ghq_hirs_f16bpp", "Force 16bpp hi-res textures (saves ram but lower quality)", 0, TRUE, TRUE);
466   settings.ghq_hirs_gz  = Config_ReadInt ("ghq_hirs_gz", "Compress hi-res texture cache", 1, TRUE, TRUE);
467   settings.ghq_hirs_altcrc = Config_ReadInt ("ghq_hirs_altcrc", "Alternative CRC calculation -- emulates Rice bug", 1, TRUE, TRUE);
468   settings.ghq_cache_save = Config_ReadInt ("ghq_cache_save", "Save tex cache to disk", 1, TRUE, TRUE);
469   settings.ghq_cache_size = Config_ReadInt ("ghq_cache_size", "Texture Cache Size (MB)", 128, TRUE, FALSE);
470   settings.ghq_hirs_let_texartists_fly = Config_ReadInt ("ghq_hirs_let_texartists_fly", "Use full alpha channel -- could cause issues for some tex packs", 0, TRUE, TRUE);
471   settings.ghq_hirs_dump = Config_ReadInt ("ghq_hirs_dump", "Dump textures", 0, FALSE, TRUE);
472 #endif
473   //TODO-PORT: remove?
474   ConfigWrapper();
475 }
476
477 void ReadSpecialSettings (const char * name)
478 {
479   //  char buf [256];
480   //  sprintf(buf, "ReadSpecialSettings. Name: %s\n", name);
481   //  LOG(buf);
482   settings.hacks = 0;
483
484   //detect games which require special hacks
485   if (strstr(name, (const char *)"ZELDA") || strstr(name, (const char *)"MASK"))
486     settings.hacks |= hack_Zelda;
487   else if (strstr(name, (const char *)"ROADSTERS TROPHY"))
488     settings.hacks |= hack_Zelda;
489   else if (strstr(name, (const char *)"Diddy Kong Racing"))
490     settings.hacks |= hack_Diddy;
491   else if (strstr(name, (const char *)"Tonic Trouble"))
492     settings.hacks |= hack_Tonic;
493   else if (strstr(name, (const char *)"All") && strstr(name, (const char *)"Star") && strstr(name, (const char *)"Baseball"))
494     settings.hacks |= hack_ASB;
495   else if (strstr(name, (const char *)"Beetle") || strstr(name, (const char *)"BEETLE") || strstr(name, (const char *)"HSV"))
496     settings.hacks |= hack_BAR;
497   else if (strstr(name, (const char *)"I S S 64") || strstr(name, (const char *)"J WORLD SOCCER3") || strstr(name, (const char *)"PERFECT STRIKER") || strstr(name, (const char *)"RONALDINHO SOCCER"))
498     settings.hacks |= hack_ISS64;
499   else if (strstr(name, (const char *)"MARIOKART64"))
500     settings.hacks |= hack_MK64;
501   else if (strstr(name, (const char *)"NITRO64"))
502     settings.hacks |= hack_WCWnitro;
503   else if (strstr(name, (const char *)"CHOPPER_ATTACK") || strstr(name, (const char *)"WILD CHOPPERS"))
504     settings.hacks |= hack_Chopper;
505   else if (strstr(name, (const char *)"Resident Evil II") || strstr(name, (const char *)"BioHazard II"))
506     settings.hacks |= hack_RE2;
507   else if (strstr(name, (const char *)"YOSHI STORY"))
508     settings.hacks |= hack_Yoshi;
509   else if (strstr(name, (const char *)"F-Zero X") || strstr(name, (const char *)"F-ZERO X"))
510     settings.hacks |= hack_Fzero;
511   else if (strstr(name, (const char *)"PAPER MARIO") || strstr(name, (const char *)"MARIO STORY"))
512     settings.hacks |= hack_PMario;
513   else if (strstr(name, (const char *)"TOP GEAR RALLY 2"))
514     settings.hacks |= hack_TGR2;
515   else if (strstr(name, (const char *)"TOP GEAR RALLY"))
516     settings.hacks |= hack_TGR;
517   else if (strstr(name, (const char *)"Top Gear Hyper Bike"))
518     settings.hacks |= hack_Hyperbike;
519   else if (strstr(name, (const char *)"Killer Instinct Gold") || strstr(name, (const char *)"KILLER INSTINCT GOLD"))
520     settings.hacks |= hack_KI;
521   else if (strstr(name, (const char *)"Knockout Kings 2000"))
522     settings.hacks |= hack_Knockout;
523   else if (strstr(name, (const char *)"LEGORacers"))
524     settings.hacks |= hack_Lego;
525   else if (strstr(name, (const char *)"OgreBattle64"))
526     settings.hacks |= hack_Ogre64;
527   else if (strstr(name, (const char *)"Pilot Wings64"))
528     settings.hacks |= hack_Pilotwings;
529   else if (strstr(name, (const char *)"Supercross"))
530     settings.hacks |= hack_Supercross;
531   else if (strstr(name, (const char *)"STARCRAFT 64"))
532     settings.hacks |= hack_Starcraft;
533   else if (strstr(name, (const char *)"BANJO KAZOOIE 2") || strstr(name, (const char *)"BANJO TOOIE"))
534     settings.hacks |= hack_Banjo2;
535   else if (strstr(name, (const char *)"FIFA: RTWC 98") || strstr(name, (const char *)"RoadToWorldCup98"))
536     settings.hacks |= hack_Fifa98;
537   else if (strstr(name, (const char *)"Mega Man 64") || strstr(name, (const char *)"RockMan Dash"))
538     settings.hacks |= hack_Megaman;
539   else if (strstr(name, (const char *)"MISCHIEF MAKERS") || strstr(name, (const char *)"TROUBLE MAKERS"))
540     settings.hacks |= hack_Makers;
541   else if (strstr(name, (const char *)"GOLDENEYE"))
542     settings.hacks |= hack_GoldenEye;
543   else if (strstr(name, (const char *)"PUZZLE LEAGUE"))
544     settings.hacks |= hack_PPL;
545
546   Ini * ini = Ini::OpenIni();
547   if (!ini)
548     return;
549   ini->SetPath(name);
550
551   ini->Read(_T("alt_tex_size"), &(settings.alt_tex_size));
552   ini->Read(_T("use_sts1_only"), &(settings.use_sts1_only));
553   ini->Read(_T("force_calc_sphere"), &(settings.force_calc_sphere));
554   ini->Read(_T("correct_viewport"), &(settings.correct_viewport));
555   ini->Read(_T("increase_texrect_edge"), &(settings.increase_texrect_edge));
556   ini->Read(_T("decrease_fillrect_edge"), &(settings.decrease_fillrect_edge));
557   if (ini->Read(_T("texture_correction"), -1) == 0) settings.texture_correction = 0;
558   else settings.texture_correction = 1;
559   if (ini->Read(_T("pal230"), -1) == 1) settings.pal230 = 1;
560   else settings.pal230 = 0;
561   ini->Read(_T("stipple_mode"), &(settings.stipple_mode));
562   int stipple_pattern = ini->Read(_T("stipple_pattern"), -1);
563   if (stipple_pattern > 0) settings.stipple_pattern = (wxUint32)stipple_pattern;
564   ini->Read(_T("force_microcheck"), &(settings.force_microcheck));
565   ini->Read(_T("force_quad3d"), &(settings.force_quad3d));
566   ini->Read(_T("clip_zmin"), &(settings.clip_zmin));
567   ini->Read(_T("clip_zmax"), &(settings.clip_zmax));
568   ini->Read(_T("fast_crc"), &(settings.fast_crc));
569   ini->Read(_T("adjust_aspect"), &(settings.adjust_aspect), 1);
570   ini->Read(_T("zmode_compare_less"), &(settings.zmode_compare_less));
571   ini->Read(_T("old_style_adither"), &(settings.old_style_adither));
572   ini->Read(_T("n64_z_scale"), &(settings.n64_z_scale));
573   if (settings.n64_z_scale)
574     ZLUT_init();
575
576   //frame buffer
577   int optimize_texrect = ini->Read(_T("optimize_texrect"), -1);
578   int ignore_aux_copy = ini->Read(_T("ignore_aux_copy"), -1);
579   int hires_buf_clear = ini->Read(_T("hires_buf_clear"), -1);
580   int read_alpha = ini->Read(_T("fb_read_alpha"), -1);
581   int useless_is_useless = ini->Read(_T("useless_is_useless"), -1);
582   int fb_crc_mode = ini->Read(_T("fb_crc_mode"), -1);
583
584   if (optimize_texrect > 0) settings.frame_buffer |= fb_optimize_texrect;
585   else if (optimize_texrect == 0) settings.frame_buffer &= ~fb_optimize_texrect;
586   if (ignore_aux_copy > 0) settings.frame_buffer |= fb_ignore_aux_copy;
587   else if (ignore_aux_copy == 0) settings.frame_buffer &= ~fb_ignore_aux_copy;
588   if (hires_buf_clear > 0) settings.frame_buffer |= fb_hwfbe_buf_clear;
589   else if (hires_buf_clear == 0) settings.frame_buffer &= ~fb_hwfbe_buf_clear;
590   if (read_alpha > 0) settings.frame_buffer |= fb_read_alpha;
591   else if (read_alpha == 0) settings.frame_buffer &= ~fb_read_alpha;
592   if (useless_is_useless > 0) settings.frame_buffer |= fb_useless_is_useless;
593   else settings.frame_buffer &= ~fb_useless_is_useless;
594   if (fb_crc_mode >= 0) settings.fb_crc_mode = (SETTINGS::FBCRCMODE)fb_crc_mode;
595
596   //  if (settings.custom_ini)
597   {
598     ini->Read(_T("filtering"), &(settings.filtering));
599     ini->Read(_T("fog"), &(settings.fog));
600     ini->Read(_T("buff_clear"), &(settings.buff_clear));
601     ini->Read(_T("swapmode"), &(settings.swapmode));
602     ini->Read(_T("aspect"), &(settings.aspectmode));
603     ini->Read(_T("lodmode"), &(settings.lodmode));
604 #ifdef PAULSCODE
605     ini->Read(_T("autoframeskip"), &(settings.autoframeskip));
606     ini->Read(_T("maxframeskip"), &(settings.maxframeskip));
607     if( settings.autoframeskip == 1 )
608       frameSkipper.setSkips( FrameSkipper::AUTO, settings.maxframeskip );
609     else
610       frameSkipper.setSkips( FrameSkipper::MANUAL, settings.maxframeskip );
611 #endif
612
613     /*
614     TODO-port: fix resolutions
615     int resolution;
616     if (ini->Read(_T("resolution"), &resolution))
617     {
618       settings.res_data = (wxUint32)resolution;
619       if (settings.res_data >= 0x18) settings.res_data = 12;
620       settings.scr_res_x = settings.res_x = resolutions[settings.res_data][0];
621       settings.scr_res_y = settings.res_y = resolutions[settings.res_data][1];
622     }
623     */
624         
625         PackedScreenResolution tmpRes = Config_ReadScreenSettings();
626         settings.res_data = tmpRes.resolution;
627         settings.scr_res_x = settings.res_x = tmpRes.width;
628         settings.scr_res_y = settings.res_y = tmpRes.height;
629
630     //frame buffer
631     int smart_read = ini->Read(_T("fb_smart"), -1);
632     int hires = ini->Read(_T("fb_hires"), -1);
633     int read_always = ini->Read(_T("fb_read_always"), -1);
634     int read_back_to_screen = ini->Read(_T("read_back_to_screen"), -1);
635     int cpu_write_hack = ini->Read(_T("detect_cpu_write"), -1);
636     int get_fbinfo = ini->Read(_T("fb_get_info"), -1);
637     int depth_render = ini->Read(_T("fb_render"), -1);
638
639     if (smart_read > 0) settings.frame_buffer |= fb_emulation;
640     else if (smart_read == 0) settings.frame_buffer &= ~fb_emulation;
641     if (hires > 0) settings.frame_buffer |= fb_hwfbe;
642     else if (hires == 0) settings.frame_buffer &= ~fb_hwfbe;
643     if (read_always > 0) settings.frame_buffer |= fb_ref;
644     else if (read_always == 0) settings.frame_buffer &= ~fb_ref;
645     if (read_back_to_screen == 1) settings.frame_buffer |= fb_read_back_to_screen;
646     else if (read_back_to_screen == 2) settings.frame_buffer |= fb_read_back_to_screen2;
647     else if (read_back_to_screen == 0) settings.frame_buffer &= ~(fb_read_back_to_screen|fb_read_back_to_screen2);
648     if (cpu_write_hack > 0) settings.frame_buffer |= fb_cpu_write_hack;
649     else if (cpu_write_hack == 0) settings.frame_buffer &= ~fb_cpu_write_hack;
650     if (get_fbinfo > 0) settings.frame_buffer |= fb_get_info;
651     else if (get_fbinfo == 0) settings.frame_buffer &= ~fb_get_info;
652     if (depth_render > 0) settings.frame_buffer |= fb_depth_render;
653     else if (depth_render == 0) settings.frame_buffer &= ~fb_depth_render;
654     settings.frame_buffer |= fb_motionblur;
655   }
656   settings.flame_corona = (settings.hacks & hack_Zelda) && !fb_depth_render_enabled;
657 }
658
659 //TODO-PORT: more ini stuff
660 void WriteSettings (bool saveEmulationSettings)
661 {
662 /*
663   wxConfigBase * ini = OpenIni();
664   if (!ini || !ini->HasGroup(_T("/SETTINGS")))
665     return;
666   ini->SetPath(_T("/SETTINGS"));
667
668   ini->Write(_T("card_id"), settings.card_id);
669   ini->Write(_T("lang_id"), settings.lang_id);
670   ini->Write(_T("resolution"), (int)settings.res_data);
671   ini->Write(_T("ssformat"), settings.ssformat);
672   ini->Write(_T("vsync"), settings.vsync);
673   ini->Write(_T("show_fps"), settings.show_fps);
674   ini->Write(_T("clock"), settings.clock);
675   ini->Write(_T("clock_24_hr"), settings.clock_24_hr);
676   ini->Write(_T("advanced_options"), settings.advanced_options);
677   ini->Write(_T("texenh_options"), settings.texenh_options);
678
679   ini->Write(_T("wrpResolution"), settings.wrpResolution);
680   ini->Write(_T("wrpVRAM"), settings.wrpVRAM);
681   ini->Write(_T("wrpFBO"), settings.wrpFBO);
682   ini->Write(_T("wrpAnisotropic"), settings.wrpAnisotropic);
683
684 #ifndef _ENDUSER_RELEASE_
685   ini->Write(_T("autodetect_ucode"), settings.autodetect_ucode);
686   ini->Write(_T("ucode"), (int)settings.ucode);
687   ini->Write(_T("wireframe"), settings.wireframe);
688   ini->Write(_T("wfmode"), settings.wfmode);
689   ini->Write(_T("logging"), settings.logging);
690   ini->Write(_T("log_clear"), settings.log_clear);
691   ini->Write(_T("run_in_window"), settings.run_in_window);
692   ini->Write(_T("elogging"), settings.elogging);
693   ini->Write(_T("filter_cache"), settings.filter_cache);
694   ini->Write(_T("unk_as_red"), settings.unk_as_red);
695   ini->Write(_T("log_unk"), settings.log_unk);
696   ini->Write(_T("unk_clear"), settings.unk_clear);
697 #endif //_ENDUSER_RELEASE_
698
699 #ifdef TEXTURE_FILTER
700   ini->Write(_T("ghq_fltr"), settings.ghq_fltr);
701   ini->Write(_T("ghq_cmpr"), settings.ghq_cmpr);
702   ini->Write(_T("ghq_enht"), settings.ghq_enht);
703   ini->Write(_T("ghq_hirs"), settings.ghq_hirs);
704   ini->Write(_T("ghq_enht_cmpr"), settings.ghq_enht_cmpr);
705   ini->Write(_T("ghq_enht_tile"), settings.ghq_enht_tile);
706   ini->Write(_T("ghq_enht_f16bpp"), settings.ghq_enht_f16bpp);
707   ini->Write(_T("ghq_enht_gz"), settings.ghq_enht_gz);
708   ini->Write(_T("ghq_enht_nobg"), settings.ghq_enht_nobg);
709   ini->Write(_T("ghq_hirs_cmpr"), settings.ghq_hirs_cmpr);
710   ini->Write(_T("ghq_hirs_tile"), settings.ghq_hirs_tile);
711   ini->Write(_T("ghq_hirs_f16bpp"), settings.ghq_hirs_f16bpp);
712   ini->Write(_T("ghq_hirs_gz"), settings.ghq_hirs_gz);
713   ini->Write(_T("ghq_hirs_altcrc"), settings.ghq_hirs_altcrc);
714   ini->Write(_T("ghq_cache_save"), settings.ghq_cache_save);
715   ini->Write(_T("ghq_cache_size"), settings.ghq_cache_size);
716   ini->Write(_T("ghq_hirs_let_texartists_fly"), settings.ghq_hirs_let_texartists_fly);
717   ini->Write(_T("ghq_hirs_dump"), settings.ghq_hirs_dump);
718 #endif
719
720   if (saveEmulationSettings)
721   {
722     if (romopen)
723     {
724       wxString S = _T("/");
725       ini->SetPath(S+rdp.RomName);
726     }
727     else
728       ini->SetPath(_T("/DEFAULT"));
729     ini->Write(_T("filtering"), settings.filtering);
730     ini->Write(_T("fog"), settings.fog);
731     ini->Write(_T("buff_clear"), settings.buff_clear);
732     ini->Write(_T("swapmode"), settings.swapmode);
733     ini->Write(_T("lodmode"), settings.lodmode);
734     ini->Write(_T("aspect"), settings.aspectmode);
735
736     ini->Write(_T("fb_read_always"), settings.frame_buffer&fb_ref ? 1 : 0l);
737     ini->Write(_T("fb_smart"), settings.frame_buffer & fb_emulation ? 1 : 0l);
738     //    ini->Write("motionblur", settings.frame_buffer & fb_motionblur ? 1 : 0);
739     ini->Write(_T("fb_hires"), settings.frame_buffer & fb_hwfbe ? 1 : 0l);
740     ini->Write(_T("fb_get_info"), settings.frame_buffer & fb_get_info ? 1 : 0l);
741     ini->Write(_T("fb_render"), settings.frame_buffer & fb_depth_render ? 1 : 0l);
742     ini->Write(_T("detect_cpu_write"), settings.frame_buffer & fb_cpu_write_hack ? 1 : 0l);
743     if (settings.frame_buffer & fb_read_back_to_screen)
744       ini->Write(_T("read_back_to_screen"), 1);
745     else if (settings.frame_buffer & fb_read_back_to_screen2)
746       ini->Write(_T("read_back_to_screen"), 2);
747     else
748       ini->Write(_T("read_back_to_screen"), 0l);
749   }
750
751   wxFileOutputStream os(iniName);
752   ((wxFileConfig*)ini)->Save(os);
753 */
754 }
755
756 GRTEXBUFFEREXT   grTextureBufferExt = NULL;
757 GRTEXBUFFEREXT   grTextureAuxBufferExt = NULL;
758 GRAUXBUFFEREXT   grAuxBufferExt = NULL;
759 GRSTIPPLE grStippleModeExt = NULL;
760 GRSTIPPLE grStipplePatternExt = NULL;
761 FxBool (FX_CALL *grKeyPressed)(FxU32) = NULL;
762
763 int GetTexAddrUMA(int tmu, int texsize)
764 {
765   int addr = voodoo.tex_min_addr[0] + voodoo.tmem_ptr[0];
766   voodoo.tmem_ptr[0] += texsize;
767   voodoo.tmem_ptr[1] = voodoo.tmem_ptr[0];
768   return addr;
769 }
770 int GetTexAddrNonUMA(int tmu, int texsize)
771 {
772   int addr = voodoo.tex_min_addr[tmu] + voodoo.tmem_ptr[tmu];
773   voodoo.tmem_ptr[tmu] += texsize;
774   return addr;
775 }
776 GETTEXADDR GetTexAddr = GetTexAddrNonUMA;
777
778 // guLoadTextures - used to load the cursor and font textures
779 void guLoadTextures ()
780 {
781   if (grTextureBufferExt)
782   {
783     int tbuf_size = 0;
784     if (voodoo.max_tex_size <= 256)
785     {
786       grTextureBufferExt(  GR_TMU1, voodoo.tex_min_addr[GR_TMU1], GR_LOD_LOG2_256, GR_LOD_LOG2_256,
787         GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
788       tbuf_size = 8 * grTexCalcMemRequired(GR_LOD_LOG2_256, GR_LOD_LOG2_256,
789         GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565);
790     }
791     else if (settings.scr_res_x <= 1024)
792     {
793       grTextureBufferExt(  GR_TMU0, voodoo.tex_min_addr[GR_TMU0], GR_LOD_LOG2_1024, GR_LOD_LOG2_1024,
794         GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
795       tbuf_size = grTexCalcMemRequired(GR_LOD_LOG2_1024, GR_LOD_LOG2_1024,
796         GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565);
797       grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT );
798       grBufferClear (0, 0, 0xFFFF);
799       grRenderBuffer( GR_BUFFER_BACKBUFFER );
800     }
801     else
802     {
803       grTextureBufferExt(  GR_TMU0, voodoo.tex_min_addr[GR_TMU0], GR_LOD_LOG2_2048, GR_LOD_LOG2_2048,
804         GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
805       tbuf_size = grTexCalcMemRequired(GR_LOD_LOG2_2048, GR_LOD_LOG2_2048,
806         GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565);
807       grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT );
808       grBufferClear (0, 0, 0xFFFF);
809       grRenderBuffer( GR_BUFFER_BACKBUFFER );
810     }
811
812     rdp.texbufs[0].tmu = GR_TMU0;
813     rdp.texbufs[0].begin = voodoo.tex_min_addr[GR_TMU0];
814     rdp.texbufs[0].end = rdp.texbufs[0].begin+tbuf_size;
815     rdp.texbufs[0].count = 0;
816     rdp.texbufs[0].clear_allowed = TRUE;
817     offset_font = tbuf_size;
818     if (voodoo.num_tmu > 1)
819     {
820       rdp.texbufs[1].tmu = GR_TMU1;
821       rdp.texbufs[1].begin = voodoo.tex_UMA ? rdp.texbufs[0].end : voodoo.tex_min_addr[GR_TMU1];
822       rdp.texbufs[1].end = rdp.texbufs[1].begin+tbuf_size;
823       rdp.texbufs[1].count = 0;
824       rdp.texbufs[1].clear_allowed = TRUE;
825       if (voodoo.tex_UMA)
826         offset_font += tbuf_size;
827       else
828         offset_texbuf1 = tbuf_size;
829     }
830   }
831   else
832     offset_font = 0;
833
834 #include "font.h"
835   wxUint32 *data = (wxUint32*)font;
836   wxUint32 cur;
837
838   // ** Font texture **
839   wxUint8 *tex8 = (wxUint8*)malloc(256*64);
840
841   fontTex.smallLodLog2 = fontTex.largeLodLog2 = GR_LOD_LOG2_256;
842   fontTex.aspectRatioLog2 = GR_ASPECT_LOG2_4x1;
843   fontTex.format = GR_TEXFMT_ALPHA_8;
844   fontTex.data = tex8;
845
846   // Decompression: [1-bit inverse alpha --> 8-bit alpha]
847   wxUint32 i,b;
848   for (i=0; i<0x200; i++)
849   {
850     // cur = ~*(data++), byteswapped
851 #ifdef __VISUALC__
852     cur = _byteswap_ulong(~*(data++));
853 #else
854     cur = ~*(data++);
855     cur = ((cur&0xFF)<<24)|(((cur>>8)&0xFF)<<16)|(((cur>>16)&0xFF)<<8)|((cur>>24)&0xFF);
856 #endif
857
858     for (b=0x80000000; b!=0; b>>=1)
859     {
860       if (cur&b) *tex8 = 0xFF;
861       else *tex8 = 0x00;
862       tex8 ++;
863     }
864   }
865
866   grTexDownloadMipMap (GR_TMU0,
867     voodoo.tex_min_addr[GR_TMU0] + offset_font,
868     GR_MIPMAPLEVELMASK_BOTH,
869     &fontTex);
870
871   offset_cursor = offset_font + grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, &fontTex);
872
873   free (fontTex.data);
874
875   // ** Cursor texture **
876 #include "cursor.h"
877   data = (wxUint32*)cursor;
878
879   wxUint16 *tex16 = (wxUint16*)malloc(32*32*2);
880
881   cursorTex.smallLodLog2 = cursorTex.largeLodLog2 = GR_LOD_LOG2_32;
882   cursorTex.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
883   cursorTex.format = GR_TEXFMT_ARGB_1555;
884   cursorTex.data = tex16;
885
886   // Conversion: [16-bit 1555 (swapped) --> 16-bit 1555]
887   for (i=0; i<0x200; i++)
888   {
889     cur = *(data++);
890     *(tex16++) = (wxUint16)(((cur&0x000000FF)<<8)|((cur&0x0000FF00)>>8));
891     *(tex16++) = (wxUint16)(((cur&0x00FF0000)>>8)|((cur&0xFF000000)>>24));
892   }
893
894   grTexDownloadMipMap (GR_TMU0,
895     voodoo.tex_min_addr[GR_TMU0] + offset_cursor,
896     GR_MIPMAPLEVELMASK_BOTH,
897     &cursorTex);
898
899   // Round to higher 16
900   offset_textures = ((offset_cursor + grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, &cursorTex))
901     & 0xFFFFFFF0) + 16;
902   free (cursorTex.data);
903 }
904
905 #ifdef TEXTURE_FILTER
906 void DisplayLoadProgress(const wchar_t *format, ...)
907 {
908   va_list args;
909   wchar_t wbuf[INFO_BUF];
910   char buf[INFO_BUF];
911
912   // process input
913   va_start(args, format);
914   vswprintf(wbuf, INFO_BUF, format, args);
915   va_end(args);
916
917   // XXX: convert to multibyte
918   wcstombs(buf, wbuf, INFO_BUF);
919
920   if (fullscreen)
921   {
922     float x;
923     set_message_combiner ();
924     output (382, 380, 1, "LOADING TEXTURES. PLEASE WAIT...");
925     int len = min (strlen(buf)*8, 1024);
926     x = (1024-len)/2.0f;
927     output (x, 360, 1, buf);
928     grBufferSwap (0);
929     grColorMask (FXTRUE, FXTRUE);
930     grBufferClear (0, 0, 0xFFFF);
931   }
932 }
933 #endif
934
935 int InitGfx ()
936 {
937 #ifdef TEXTURE_FILTER
938   wchar_t romname[256];
939   wchar_t foldername[PATH_MAX + 64];
940   wchar_t cachename[PATH_MAX + 64];
941 #endif
942   if (fullscreen)
943     ReleaseGfx ();
944
945   OPEN_RDP_LOG ();  // doesn't matter if opens again; it will check for it
946   OPEN_RDP_E_LOG ();
947   VLOG ("InitGfx ()\n");
948
949   debugging = FALSE;
950   rdp_reset ();
951
952   // Initialize Glide
953   grGlideInit ();
954
955   // Select the Glide device
956   grSstSelect (settings.card_id);
957
958   // Is mirroring allowed?
959   const char *extensions = grGetString (GR_EXTENSION);
960
961   // Check which SST we are using and initialize stuff
962   // Hiroshi Morii <koolsmoky@users.sourceforge.net>
963   enum {
964     GR_SSTTYPE_VOODOO  = 0,
965     GR_SSTTYPE_SST96   = 1,
966     GR_SSTTYPE_AT3D    = 2,
967     GR_SSTTYPE_Voodoo2 = 3,
968     GR_SSTTYPE_Banshee = 4,
969     GR_SSTTYPE_Voodoo3 = 5,
970     GR_SSTTYPE_Voodoo4 = 6,
971     GR_SSTTYPE_Voodoo5 = 7
972   };
973   const char *hardware = grGetString(GR_HARDWARE);
974   unsigned int SST_type = GR_SSTTYPE_VOODOO;
975   if (strstr(hardware, "Rush")) {
976     SST_type = GR_SSTTYPE_SST96;
977   } else if (strstr(hardware, "Voodoo2")) {
978     SST_type = GR_SSTTYPE_Voodoo2;
979   } else if (strstr(hardware, "Voodoo Banshee")) {
980     SST_type = GR_SSTTYPE_Banshee;
981   } else if (strstr(hardware, "Voodoo3")) {
982     SST_type = GR_SSTTYPE_Voodoo3;
983   } else if (strstr(hardware, "Voodoo4")) {
984     SST_type = GR_SSTTYPE_Voodoo4;
985   } else if (strstr(hardware, "Voodoo5")) {
986     SST_type = GR_SSTTYPE_Voodoo5;
987   }
988   // 2Mb Texture boundary
989   voodoo.has_2mb_tex_boundary = (SST_type < GR_SSTTYPE_Banshee) && !evoodoo;
990   // use UMA if available
991   voodoo.tex_UMA = FALSE;
992   //*
993   if (strstr(extensions, " TEXUMA ")) {
994     // we get better texture cache hits with UMA on
995     grEnable(GR_TEXTURE_UMA_EXT);
996     voodoo.tex_UMA = TRUE;
997     LOG ("Using TEXUMA extension.\n");
998   }
999   //*/
1000 //TODO-PORT: fullscreen stuff
1001   wxUint32 res_data = settings.res_data;
1002   char strWrapperFullScreenResolutionExt[] = "grWrapperFullScreenResolutionExt";
1003   if (ev_fullscreen)
1004   {
1005       GRWRAPPERFULLSCREENRESOLUTIONEXT grWrapperFullScreenResolutionExt =
1006         (GRWRAPPERFULLSCREENRESOLUTIONEXT)grGetProcAddress(strWrapperFullScreenResolutionExt);
1007       if (grWrapperFullScreenResolutionExt) {
1008         wxUint32 _width, _height = 0;
1009         settings.res_data = grWrapperFullScreenResolutionExt(&_width, &_height);
1010         settings.scr_res_x = settings.res_x = _width;
1011         settings.scr_res_y = settings.res_y = _height;
1012       }
1013       res_data = settings.res_data;
1014   }
1015   else if (evoodoo)
1016   {
1017       GRWRAPPERFULLSCREENRESOLUTIONEXT grWrapperFullScreenResolutionExt =
1018         (GRWRAPPERFULLSCREENRESOLUTIONEXT)grGetProcAddress(strWrapperFullScreenResolutionExt);
1019       if (grWrapperFullScreenResolutionExt != NULL)
1020       {
1021 /*
1022         TODO-port: fix resolutions
1023         settings.res_data = settings.res_data_org;
1024         settings.scr_res_x = settings.res_x = resolutions[settings.res_data][0];
1025         settings.scr_res_y = settings.res_y = resolutions[settings.res_data][1];
1026 */
1027       }
1028       res_data = settings.res_data | 0x80000000;
1029   }
1030
1031   gfx_context = 0;
1032
1033   // Select the window
1034
1035   if (fb_hwfbe_enabled)
1036   {
1037     char strSstWinOpenExt[] ="grSstWinOpenExt";
1038     GRWINOPENEXT grSstWinOpenExt = (GRWINOPENEXT)grGetProcAddress(strSstWinOpenExt);
1039     if (grSstWinOpenExt)
1040       gfx_context = grSstWinOpenExt ((FxU32)NULL,
1041       res_data,
1042       GR_REFRESH_60Hz,
1043       GR_COLORFORMAT_RGBA,
1044       GR_ORIGIN_UPPER_LEFT,
1045       fb_emulation_enabled?GR_PIXFMT_RGB_565:GR_PIXFMT_ARGB_8888, //32b color is not compatible with fb emulation
1046       2,    // Double-buffering
1047       1);   // 1 auxillary buffer
1048   }
1049   if (!gfx_context)
1050     gfx_context = grSstWinOpen ((FxU32)NULL,
1051     res_data,
1052     GR_REFRESH_60Hz,
1053     GR_COLORFORMAT_RGBA,
1054     GR_ORIGIN_UPPER_LEFT,
1055     2,    // Double-buffering
1056     1);   // 1 auxillary buffer
1057
1058   if (!gfx_context)
1059   {
1060     ERRLOG("Error setting display mode");
1061     //    grSstWinClose (gfx_context);
1062     grGlideShutdown ();
1063     return FALSE;
1064   }
1065
1066   fullscreen = TRUE;
1067   to_fullscreen = FALSE;
1068
1069
1070   // get the # of TMUs available
1071   grGet (GR_NUM_TMU, 4, (FxI32*)&voodoo.num_tmu);
1072   // get maximal texture size
1073   grGet (GR_MAX_TEXTURE_SIZE, 4, (FxI32*)&voodoo.max_tex_size);
1074   voodoo.sup_large_tex = (voodoo.max_tex_size > 256 && !(settings.hacks & hack_PPL));
1075
1076   //num_tmu = 1;
1077   if (voodoo.tex_UMA)
1078   {
1079     GetTexAddr = GetTexAddrUMA;
1080     voodoo.tex_min_addr[0] = voodoo.tex_min_addr[1] = grTexMinAddress(GR_TMU0);
1081     voodoo.tex_max_addr[0] = voodoo.tex_max_addr[1] = grTexMaxAddress(GR_TMU0);
1082   }
1083   else
1084   {
1085     GetTexAddr = GetTexAddrNonUMA;
1086     voodoo.tex_min_addr[0] = grTexMinAddress(GR_TMU0);
1087     voodoo.tex_min_addr[1] = grTexMinAddress(GR_TMU1);
1088     voodoo.tex_max_addr[0] = grTexMaxAddress(GR_TMU0);
1089     voodoo.tex_max_addr[1] = grTexMaxAddress(GR_TMU1);
1090   }
1091
1092   if (strstr (extensions, "TEXMIRROR") && !(settings.hacks&hack_Zelda)) //zelda's trees suffer from hardware mirroring
1093     voodoo.sup_mirroring = 1;
1094   else
1095     voodoo.sup_mirroring = 0;
1096
1097   if (strstr (extensions, "TEXFMT"))  //VSA100 texture format extension
1098     voodoo.sup_32bit_tex = TRUE;
1099   else
1100     voodoo.sup_32bit_tex = FALSE;
1101
1102   voodoo.gamma_correction = 0;
1103   if (strstr(extensions, "GETGAMMA"))
1104     grGet(GR_GAMMA_TABLE_ENTRIES, sizeof(voodoo.gamma_table_size), &voodoo.gamma_table_size);
1105
1106   if (fb_hwfbe_enabled)
1107   {
1108     if (char * extstr = (char*)strstr(extensions, "TEXTUREBUFFER"))
1109     {
1110       if (!strncmp(extstr, "TEXTUREBUFFER", 13))
1111       {
1112         char strTextureBufferExt[] = "grTextureBufferExt";
1113         grTextureBufferExt = (GRTEXBUFFEREXT) grGetProcAddress(strTextureBufferExt);
1114         char strTextureAuxBufferExt[] = "grTextureAuxBufferExt";
1115         grTextureAuxBufferExt = (GRTEXBUFFEREXT) grGetProcAddress(strTextureAuxBufferExt);
1116         char strAuxBufferExt[] = "grAuxBufferExt";
1117         grAuxBufferExt = (GRAUXBUFFEREXT) grGetProcAddress(strAuxBufferExt);
1118       }
1119     }
1120     else
1121       settings.frame_buffer &= ~fb_hwfbe;
1122   }
1123   else
1124     grTextureBufferExt = 0;
1125
1126   grStippleModeExt = (GRSTIPPLE)grStippleMode;
1127   grStipplePatternExt = (GRSTIPPLE)grStipplePattern;
1128
1129   if (grStipplePatternExt)
1130     grStipplePatternExt(settings.stipple_pattern);
1131
1132 //  char strKeyPressedExt[] = "grKeyPressedExt";
1133 //  grKeyPressed = (FxBool (FX_CALL *)(FxU32))grGetProcAddress (strKeyPressedExt);
1134
1135   InitCombine();
1136
1137 #ifdef SIMULATE_VOODOO1
1138   voodoo.num_tmu = 1;
1139   voodoo.sup_mirroring = 0;
1140 #endif
1141
1142 #ifdef SIMULATE_BANSHEE
1143   voodoo.num_tmu = 1;
1144   voodoo.sup_mirroring = 1;
1145 #endif
1146
1147   grCoordinateSpace (GR_WINDOW_COORDS);
1148   grVertexLayout (GR_PARAM_XY, offsetof(VERTEX,x), GR_PARAM_ENABLE);
1149   grVertexLayout (GR_PARAM_Q, offsetof(VERTEX,q), GR_PARAM_ENABLE);
1150   grVertexLayout (GR_PARAM_Z, offsetof(VERTEX,z), GR_PARAM_ENABLE);
1151   grVertexLayout (GR_PARAM_ST0, offsetof(VERTEX,coord[0]), GR_PARAM_ENABLE);
1152   grVertexLayout (GR_PARAM_ST1, offsetof(VERTEX,coord[2]), GR_PARAM_ENABLE);
1153   grVertexLayout (GR_PARAM_PARGB, offsetof(VERTEX,b), GR_PARAM_ENABLE);
1154
1155   grCullMode(GR_CULL_NEGATIVE);
1156
1157   if (settings.fog) //"FOGCOORD" extension
1158   {
1159     if (strstr (extensions, "FOGCOORD"))
1160     {
1161       GrFog_t fog_t[64];
1162       guFogGenerateLinear (fog_t, 0.0f, 255.0f);//(float)rdp.fog_multiplier + (float)rdp.fog_offset);//256.0f);
1163
1164       for (int i = 63; i > 0; i--)
1165       {
1166         if (fog_t[i] - fog_t[i-1] > 63)
1167         {
1168           fog_t[i-1] = fog_t[i] - 63;
1169         }
1170       }
1171       fog_t[0] = 0;
1172       //      for (int f = 0; f < 64; f++)
1173       //      {
1174       //        FRDP("fog[%d]=%d->%f\n", f, fog_t[f], guFogTableIndexToW(f));
1175       //      }
1176       grFogTable (fog_t);
1177       grVertexLayout (GR_PARAM_FOG_EXT, offsetof(VERTEX,f), GR_PARAM_ENABLE);
1178     }
1179     else //not supported
1180       settings.fog = FALSE;
1181   }
1182
1183   grDepthBufferMode (GR_DEPTHBUFFER_ZBUFFER);
1184   grDepthBufferFunction(GR_CMP_LESS);
1185   grDepthMask(FXTRUE);
1186
1187   settings.res_x = settings.scr_res_x;
1188   settings.res_y = settings.scr_res_y;
1189   ChangeSize ();
1190
1191   guLoadTextures ();
1192   ClearCache ();
1193
1194   grCullMode (GR_CULL_DISABLE);
1195   grDepthBufferMode (GR_DEPTHBUFFER_ZBUFFER);
1196   grDepthBufferFunction (GR_CMP_ALWAYS);
1197   grRenderBuffer(GR_BUFFER_BACKBUFFER);
1198   grColorMask (FXTRUE, FXTRUE);
1199   grDepthMask (FXTRUE);
1200   grBufferClear (0, 0, 0xFFFF);
1201   grBufferSwap (0);
1202   grBufferClear (0, 0, 0xFFFF);
1203   grDepthMask (FXFALSE);
1204   grTexFilterMode (0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR);
1205   grTexFilterMode (1, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR);
1206   grTexClampMode (0, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_CLAMP);
1207   grTexClampMode (1, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_CLAMP);
1208   grClipWindow (0, 0, settings.scr_res_x, settings.scr_res_y);
1209   rdp.update |= UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
1210
1211 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1212   if (!settings.ghq_use)
1213   {
1214     settings.ghq_use = settings.ghq_fltr || settings.ghq_enht /*|| settings.ghq_cmpr*/ || settings.ghq_hirs;
1215     if (settings.ghq_use)
1216     {
1217       /* Plugin path */
1218       int options = texfltr[settings.ghq_fltr]|texenht[settings.ghq_enht]|texcmpr[settings.ghq_cmpr]|texhirs[settings.ghq_hirs];
1219       if (settings.ghq_enht_cmpr)
1220         options |= COMPRESS_TEX;
1221       if (settings.ghq_hirs_cmpr)
1222         options |= COMPRESS_HIRESTEX;
1223       //      if (settings.ghq_enht_tile)
1224       //        options |= TILE_TEX;
1225       if (settings.ghq_hirs_tile)
1226         options |= TILE_HIRESTEX;
1227       if (settings.ghq_enht_f16bpp)
1228         options |= FORCE16BPP_TEX;
1229       if (settings.ghq_hirs_f16bpp)
1230         options |= FORCE16BPP_HIRESTEX;
1231       if (settings.ghq_enht_gz)
1232         options |= GZ_TEXCACHE;
1233       if (settings.ghq_hirs_gz)
1234         options |= GZ_HIRESTEXCACHE;
1235       if (settings.ghq_cache_save)
1236         options |= (DUMP_TEXCACHE|DUMP_HIRESTEXCACHE);
1237       if (settings.ghq_hirs_let_texartists_fly)
1238         options |= LET_TEXARTISTS_FLY;
1239       if (settings.ghq_hirs_dump)
1240         options |= DUMP_TEX;
1241
1242       ghq_dmptex_toggle_key = 0;
1243
1244       swprintf(romname, sizeof(romname) / sizeof(*romname), L"%hs", rdp.RomName);
1245       swprintf(foldername, sizeof(foldername) / sizeof(*foldername), L"%hs", ConfigGetUserDataPath());
1246       swprintf(cachename, sizeof(cachename) / sizeof(*cachename), L"%hs", ConfigGetUserCachePath());
1247
1248       settings.ghq_use = (int)ext_ghq_init(voodoo.max_tex_size, // max texture width supported by hardware
1249         voodoo.max_tex_size, // max texture height supported by hardware
1250         voodoo.sup_32bit_tex?32:16, // max texture bpp supported by hardware
1251         options,
1252         settings.ghq_cache_size * 1024*1024, // cache texture to system memory
1253         foldername,
1254         cachename,
1255         romname, // name of ROM. must be no longer than 256 characters
1256         DisplayLoadProgress);
1257     }
1258   }
1259   if (settings.ghq_use && strstr (extensions, "TEXMIRROR"))
1260     voodoo.sup_mirroring = 1;
1261 #endif
1262
1263   return TRUE;
1264 }
1265
1266 void ReleaseGfx ()
1267 {
1268   VLOG("ReleaseGfx ()\n");
1269
1270   // Restore gamma settings
1271   if (voodoo.gamma_correction)
1272   {
1273     if (voodoo.gamma_table_r)
1274       grLoadGammaTable(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b);
1275     else
1276       guGammaCorrectionRGB(1.3f, 1.3f, 1.3f); //1.3f is default 3dfx gamma for everything but desktop
1277     voodoo.gamma_correction = 0;
1278   }
1279
1280   // Release graphics
1281   grSstWinClose (gfx_context);
1282
1283   // Shutdown glide
1284   grGlideShutdown();
1285
1286   fullscreen = FALSE;
1287   rdp.window_changed = TRUE;
1288 }
1289
1290 // new API code begins here!
1291
1292 #ifdef __cplusplus
1293 extern "C" {
1294 #endif
1295
1296 EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int front)
1297 {
1298   VLOG("CALL ReadScreen2 ()\n");
1299   *width = settings.res_x;
1300   *height = settings.res_y;
1301   if (dest)
1302   {
1303     BYTE * line = (BYTE*)dest;
1304     if (!fullscreen)
1305     {
1306       for (wxUint32 y=0; y<settings.res_y; y++)
1307       {
1308         for (wxUint32 x=0; x<settings.res_x; x++)
1309         {
1310           line[x*3] = 0x20;
1311           line[x*3+1] = 0x7f;
1312           line[x*3+2] = 0x40;
1313         }
1314       }
1315       // LOG ("ReadScreen. not in the fullscreen!\n");
1316       WARNLOG("[Glide64] Cannot save screenshot in windowed mode?\n");
1317
1318       return;
1319     }
1320
1321   GrLfbInfo_t info;
1322   info.size = sizeof(GrLfbInfo_t);
1323   if (grLfbLock (GR_LFB_READ_ONLY,
1324     GR_BUFFER_FRONTBUFFER,
1325     GR_LFBWRITEMODE_888,
1326     GR_ORIGIN_UPPER_LEFT,
1327     FXFALSE,
1328     &info))
1329   {
1330     // Copy the screen, let's hope this works.
1331       for (wxUint32 y=0; y<settings.res_y; y++)
1332       {
1333         BYTE *ptr = (BYTE*) info.lfbPtr + (info.strideInBytes * y);
1334         for (wxUint32 x=0; x<settings.res_x; x++)
1335         {
1336           line[x*3]   = ptr[2];  // red
1337           line[x*3+1] = ptr[1];  // green
1338           line[x*3+2] = ptr[0];  // blue
1339           ptr += 4;
1340         }
1341         line += settings.res_x * 3;
1342       }
1343
1344       // Unlock the frontbuffer
1345       grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER);
1346     }
1347     VLOG ("ReadScreen. Success.\n");
1348   }
1349 }
1350
1351 EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
1352                                    void (*DebugCallback)(void *, int, const char *))
1353 {
1354   VLOG("CALL PluginStartup ()\n");
1355     l_DebugCallback = DebugCallback;
1356     l_DebugCallContext = Context;
1357
1358     /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */
1359     ptr_CoreGetAPIVersions CoreAPIVersionFunc;
1360     CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
1361     if (CoreAPIVersionFunc == NULL)
1362     {
1363         ERRLOG("Core emulator broken; no CoreAPIVersionFunc() function found.");
1364         return M64ERR_INCOMPATIBLE;
1365     }
1366     int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
1367     (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
1368     if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
1369     {
1370         ERRLOG("Emulator core Config API incompatible with this plugin");
1371         return M64ERR_INCOMPATIBLE;
1372     }
1373     if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000))
1374     {
1375         ERRLOG("Emulator core Video Extension API incompatible with this plugin");
1376         return M64ERR_INCOMPATIBLE;
1377     }
1378
1379     ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
1380     ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
1381     ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
1382     ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
1383     ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
1384     ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
1385     ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
1386     ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
1387     ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
1388     ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
1389     ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
1390
1391     ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath");
1392     ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath");
1393     ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath");
1394     ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath");
1395
1396     if (!ConfigOpenSection   || !ConfigSetParameter    || !ConfigGetParameter ||
1397         !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
1398         !ConfigGetParamInt   || !ConfigGetParamFloat   || !ConfigGetParamBool   || !ConfigGetParamString ||
1399         !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
1400     {
1401         ERRLOG("Couldn't connect to Core configuration functions");
1402         return M64ERR_INCOMPATIBLE;
1403     }
1404
1405     /* Get the core Video Extension function pointers from the library handle */
1406     CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init");
1407     CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit");
1408     CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes");
1409     CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode");
1410     CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption");
1411     CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen");
1412     CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow");
1413     CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress");
1414     CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute");
1415     CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers");
1416
1417     if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode ||
1418         !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_ResizeWindow || !CoreVideo_GL_GetProcAddress ||
1419         !CoreVideo_GL_SetAttribute || !CoreVideo_GL_SwapBuffers)
1420     {
1421         ERRLOG("Couldn't connect to Core video functions");
1422         return M64ERR_INCOMPATIBLE;
1423     }
1424
1425     const char *configDir = ConfigGetSharedDataFilepath("Glide64mk2.ini");
1426     if (configDir)
1427     {
1428         SetConfigDir(configDir);
1429         ReadSettings();
1430                 return M64ERR_SUCCESS;
1431     }
1432     else
1433     {
1434         ERRLOG("Couldn't find Glide64mk2.ini");
1435         return M64ERR_FILES;
1436     }
1437 }
1438
1439 EXPORT m64p_error CALL PluginShutdown(void)
1440 {
1441   VLOG("CALL PluginShutdown ()\n");
1442     return M64ERR_SUCCESS;
1443 }
1444
1445 EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
1446 {
1447   VLOG("CALL PluginGetVersion ()\n");
1448     /* set version info */
1449     if (PluginType != NULL)
1450         *PluginType = M64PLUGIN_GFX;
1451
1452     if (PluginVersion != NULL)
1453         *PluginVersion = PLUGIN_VERSION;
1454
1455     if (APIVersion != NULL)
1456         *APIVersion = VIDEO_PLUGIN_API_VERSION;
1457
1458     if (PluginNamePtr != NULL)
1459         *PluginNamePtr = PLUGIN_NAME;
1460
1461     if (Capabilities != NULL)
1462     {
1463         *Capabilities = 0;
1464     }
1465
1466     return M64ERR_SUCCESS;
1467 }
1468
1469 /******************************************************************
1470 Function: CaptureScreen
1471 Purpose:  This function dumps the current frame to a file
1472 input:    pointer to the directory to save the file to
1473 output:   none
1474 *******************************************************************/
1475 EXPORT void CALL CaptureScreen ( char * Directory )
1476 {
1477   capture_screen = 1;
1478   strcpy (capture_path, Directory);
1479 }
1480
1481 /******************************************************************
1482 Function: ChangeWindow
1483 Purpose:  to change the window between fullscreen and window
1484 mode. If the window was in fullscreen this should
1485 change the screen to window mode and vice vesa.
1486 input:    none
1487 output:   none
1488 *******************************************************************/
1489 //#warning ChangeWindow unimplemented
1490 EXPORT void CALL ChangeWindow (void)
1491 {
1492   VLOG ("ChangeWindow()\n");
1493   #ifdef OLDAPI
1494   if (evoodoo)
1495   {
1496     if (!ev_fullscreen)
1497     {
1498       to_fullscreen = TRUE;
1499       ev_fullscreen = TRUE;
1500 #ifdef __WINDOWS__
1501       if (gfx.hStatusBar)
1502         ShowWindow( gfx.hStatusBar, SW_HIDE );
1503       ShowCursor( FALSE );
1504 #endif
1505     }
1506     else
1507     {
1508       ev_fullscreen = FALSE;
1509       InitGfx ();
1510 #ifdef __WINDOWS__
1511       ShowCursor( TRUE );
1512       if (gfx.hStatusBar)
1513         ShowWindow( gfx.hStatusBar, SW_SHOW );
1514       SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
1515 #endif
1516     }
1517   }
1518   else
1519   {
1520     // Go to fullscreen at next dlist
1521     // This is for compatibility with 1964, which reloads the plugin
1522     //  when switching to fullscreen
1523     if (!fullscreen)
1524     {
1525       to_fullscreen = TRUE;
1526 #ifdef __WINDOWS__
1527       if (gfx.hStatusBar)
1528         ShowWindow( gfx.hStatusBar, SW_HIDE );
1529       ShowCursor( FALSE );
1530 #endif
1531     }
1532     else
1533     {
1534       ReleaseGfx ();
1535 #ifdef __WINDOWS__
1536       ShowCursor( TRUE );
1537       if (gfx.hStatusBar)
1538         ShowWindow( gfx.hStatusBar, SW_SHOW );
1539       // SetWindowLong fixes the following Windows XP Banshee issues:
1540       // 1964 crash error when loading another rom.
1541       // All N64 emu's minimize, restore crashes.
1542       SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
1543 #endif
1544     }
1545   }
1546 #endif
1547 }
1548
1549 /******************************************************************
1550 Function: CloseDLL
1551 Purpose:  This function is called when the emulator is closing
1552 down allowing the dll to de-initialise.
1553 input:    none
1554 output:   none
1555 *******************************************************************/
1556 void CALL CloseDLL (void)
1557 {
1558   VLOG ("CloseDLL ()\n");
1559
1560   // re-set the old window proc
1561 #ifdef WINPROC_OVERRIDE
1562   SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
1563 #endif
1564
1565 #ifdef ALTTAB_FIX
1566   if (hhkLowLevelKybd)
1567   {
1568     UnhookWindowsHookEx(hhkLowLevelKybd);
1569     hhkLowLevelKybd = 0;
1570   }
1571 #endif
1572
1573   //CLOSELOG ();
1574
1575 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1576   if (settings.ghq_use)
1577   {
1578     ext_ghq_shutdown();
1579     settings.ghq_use = 0;
1580   }
1581 #endif
1582   if (fullscreen)
1583     ReleaseGfx ();
1584   ZLUT_release();
1585   ClearCache ();
1586   delete[] voodoo.gamma_table_r;
1587   voodoo.gamma_table_r = 0;
1588   delete[] voodoo.gamma_table_g;
1589   voodoo.gamma_table_g = 0;
1590   delete[] voodoo.gamma_table_b;
1591   voodoo.gamma_table_b = 0;
1592 }
1593
1594 /******************************************************************
1595 Function: DllTest
1596 Purpose:  This function is optional function that is provided
1597 to allow the user to test the dll
1598 input:    a handle to the window that calls this function
1599 output:   none
1600 *******************************************************************/
1601 void CALL DllTest ( HWND hParent )
1602 {
1603 }
1604
1605 /******************************************************************
1606 Function: DrawScreen
1607 Purpose:  This function is called when the emulator receives a
1608 WM_PAINT message. This allows the gfx to fit in when
1609 it is being used in the desktop.
1610 input:    none
1611 output:   none
1612 *******************************************************************/
1613 void CALL DrawScreen (void)
1614 {
1615   VLOG ("DrawScreen ()\n");
1616 }
1617
1618 /******************************************************************
1619 Function: GetDllInfo
1620 Purpose:  This function allows the emulator to gather information
1621 about the dll by filling in the PluginInfo structure.
1622 input:    a pointer to a PLUGIN_INFO stucture that needs to be
1623 filled by the function. (see def above)
1624 output:   none
1625 *******************************************************************/
1626 void CALL GetDllInfo ( PLUGIN_INFO * PluginInfo )
1627 {
1628   VLOG ("GetDllInfo ()\n");
1629   PluginInfo->Version = 0x0103;     // Set to 0x0103
1630   PluginInfo->Type  = PLUGIN_TYPE_GFX;  // Set to PLUGIN_TYPE_GFX
1631   sprintf (PluginInfo->Name, "Glide64mk2 " G64_VERSION RELTIME);  // Name of the DLL
1632
1633   // If DLL supports memory these memory options then set them to TRUE or FALSE
1634   //  if it does not support it
1635   PluginInfo->NormalMemory = TRUE;  // a normal wxUint8 array
1636   PluginInfo->MemoryBswaped = TRUE; // a normal wxUint8 array where the memory has been pre
1637   // bswap on a dword (32 bits) boundry
1638 }
1639
1640 #ifndef WIN32
1641 BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter)
1642 {
1643    struct timeval tv;
1644
1645    /* generic routine */
1646    gettimeofday( &tv, NULL );
1647    counter->QuadPart = (LONGLONG)tv.tv_usec + (LONGLONG)tv.tv_sec * 1000000;
1648    return TRUE;
1649 }
1650
1651 BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER frequency)
1652 {
1653    frequency->s.LowPart= 1000000;
1654    frequency->s.HighPart= 0;
1655    return TRUE;
1656 }
1657 #endif
1658
1659 /******************************************************************
1660 Function: InitiateGFX
1661 Purpose:  This function is called when the DLL is started to give
1662 information from the emulator that the n64 graphics
1663 uses. This is not called from the emulation thread.
1664 Input:    Gfx_Info is passed to this function which is defined
1665 above.
1666 Output:   TRUE on success
1667 FALSE on failure to initialise
1668
1669 ** note on interrupts **:
1670 To generate an interrupt set the appropriate bit in MI_INTR_REG
1671 and then call the function CheckInterrupts to tell the emulator
1672 that there is a waiting interrupt.
1673 *******************************************************************/
1674
1675 EXPORT int CALL InitiateGFX (GFX_INFO Gfx_Info)
1676 {
1677   VLOG ("InitiateGFX (*)\n");
1678   voodoo.num_tmu = 2;
1679
1680   // Assume scale of 1 for debug purposes
1681   rdp.scale_x = 1.0f;
1682   rdp.scale_y = 1.0f;
1683
1684   memset (&settings, 0, sizeof(SETTINGS));
1685   ReadSettings ();
1686   char name[21] = "DEFAULT";
1687   ReadSpecialSettings (name);
1688   settings.res_data_org = settings.res_data;
1689 #ifdef FPS
1690   QueryPerformanceFrequency (&perf_freq);
1691   QueryPerformanceCounter (&fps_last);
1692 #endif
1693
1694   debug_init ();    // Initialize debugger
1695
1696   gfx = Gfx_Info;
1697
1698 #ifdef WINPROC_OVERRIDE
1699   // [H.Morii] inject our own winproc so that "alt-enter to fullscreen"
1700   // message is shown when the emulator window is activated.
1701   WNDPROC curWndProc = (WNDPROC)GetWindowLong(gfx.hWnd, GWL_WNDPROC);
1702   if (curWndProc && curWndProc != (WNDPROC)WndProc) {
1703     oldWndProc = (WNDPROC)SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)WndProc);
1704   }
1705 #endif
1706
1707   util_init ();
1708   math_init ();
1709   TexCacheInit ();
1710   CRC_BuildTable();
1711   CountCombine();
1712   if (fb_depth_render_enabled)
1713     ZLUT_init();
1714
1715   char strConfigWrapperExt[] = "grConfigWrapperExt";
1716   GRCONFIGWRAPPEREXT grConfigWrapperExt = (GRCONFIGWRAPPEREXT)grGetProcAddress(strConfigWrapperExt);
1717   if (grConfigWrapperExt)
1718     grConfigWrapperExt(settings.wrpResolution, settings.wrpVRAM * 1024 * 1024, settings.wrpFBO, settings.wrpAnisotropic);
1719
1720   grGlideInit ();
1721   grSstSelect (0);
1722   const char *extensions = grGetString (GR_EXTENSION);
1723   grGlideShutdown ();
1724   if (strstr (extensions, "EVOODOO"))
1725   {
1726     evoodoo = 1;
1727     voodoo.has_2mb_tex_boundary = 0;
1728   }
1729   else {
1730     evoodoo = 0;
1731     voodoo.has_2mb_tex_boundary = 1;
1732   }
1733
1734   return TRUE;
1735 }
1736
1737 /******************************************************************
1738 Function: MoveScreen
1739 Purpose:  This function is called in response to the emulator
1740 receiving a WM_MOVE passing the xpos and ypos passed
1741 from that message.
1742 input:    xpos - the x-coordinate of the upper-left corner of the
1743 client area of the window.
1744 ypos - y-coordinate of the upper-left corner of the
1745 client area of the window.
1746 output:   none
1747 *******************************************************************/
1748 EXPORT void CALL MoveScreen (int xpos, int ypos)
1749 {
1750   rdp.window_changed = TRUE;
1751 }
1752
1753 /******************************************************************
1754 Function: ResizeVideoOutput
1755 Purpose:  This function is called to force us to resize our output OpenGL window.
1756           This is currently unsupported, and should never be called because we do
1757           not pass the RESIZABLE flag to VidExt_SetVideoMode when initializing.
1758 input:    new width and height
1759 output:   none
1760 *******************************************************************/
1761 EXPORT void CALL ResizeVideoOutput(int Width, int Height)
1762 {
1763 }
1764
1765 /******************************************************************
1766 Function: RomClosed
1767 Purpose:  This function is called when a rom is closed.
1768 input:    none
1769 output:   none
1770 *******************************************************************/
1771 EXPORT void CALL RomClosed (void)
1772 {
1773   VLOG ("RomClosed ()\n");
1774 printf("RomClosed ()\n");
1775
1776   CLOSE_RDP_LOG ();
1777   CLOSE_RDP_E_LOG ();
1778   rdp.window_changed = TRUE;
1779   romopen = FALSE;
1780 //  if (fullscreen && evoodoo)//*SEB*
1781     ReleaseGfx ();
1782 }
1783
1784 static void CheckDRAMSize()
1785 {
1786   wxUint32 test;
1787   GLIDE64_TRY
1788   {
1789     test = gfx.RDRAM[0x007FFFFF] + 1;
1790   }
1791   GLIDE64_CATCH
1792   {
1793     test = 0;
1794   }
1795   if (test)
1796     BMASK = 0x7FFFFF;
1797   else
1798     BMASK = WMASK;
1799 #ifdef LOGGING
1800   sprintf (out_buf, "Detected RDRAM size: %08lx\n", BMASK);
1801   LOG (out_buf);
1802 #endif
1803 }
1804
1805 /******************************************************************
1806 Function: RomOpen
1807 Purpose:  This function is called when a rom is open. (from the
1808 emulation thread)
1809 input:    none
1810 output:   none
1811 *******************************************************************/
1812 EXPORT int CALL RomOpen (void)
1813 {
1814   VLOG ("RomOpen ()\n");
1815   no_dlist = true;
1816   romopen = TRUE;
1817   ucode_error_report = TRUE;    // allowed to report ucode errors
1818   rdp_reset ();
1819
1820   // Get the country code & translate to NTSC(0) or PAL(1)
1821   wxUint16 code = ((wxUint16*)gfx.HEADER)[0x1F^1];
1822
1823   if (code == 0x4400) region = 1; // Germany (PAL)
1824   if (code == 0x4500) region = 0; // USA (NTSC)
1825   if (code == 0x4A00) region = 0; // Japan (NTSC)
1826   if (code == 0x5000) region = 1; // Europe (PAL)
1827   if (code == 0x5500) region = 0; // Australia (NTSC)
1828
1829 #ifdef PAULSCODE
1830   frameSkipper.setTargetFPS(region == 1 ? 50 : 60);
1831 #endif
1832
1833   char name[21] = "DEFAULT";
1834   ReadSpecialSettings (name);
1835
1836   // get the name of the ROM
1837   for (int i=0; i<20; i++)
1838     name[i] = gfx.HEADER[(32+i)^3];
1839   name[20] = 0;
1840
1841   // remove all trailing spaces
1842   while (name[strlen(name)-1] == ' ')
1843     name[strlen(name)-1] = 0;
1844
1845   strncpy(rdp.RomName, name, sizeof(name));
1846   ReadSpecialSettings (name);
1847   ClearCache ();
1848
1849   CheckDRAMSize();
1850
1851   OPEN_RDP_LOG ();
1852   OPEN_RDP_E_LOG ();
1853
1854
1855   // ** EVOODOO EXTENSIONS **
1856   if (!fullscreen)
1857   {
1858     grGlideInit ();
1859     grSstSelect (0);
1860   }
1861   const char *extensions = grGetString (GR_EXTENSION);
1862   if (!fullscreen)
1863   {
1864     grGlideShutdown ();
1865
1866     if (strstr (extensions, "EVOODOO"))
1867       evoodoo = 1;
1868     else
1869       evoodoo = 0;
1870
1871     if (evoodoo)
1872       InitGfx ();
1873   }
1874
1875   if (strstr (extensions, "ROMNAME"))
1876   {
1877     char strSetRomName[] = "grSetRomName";
1878     void (FX_CALL *grSetRomName)(char*);
1879     grSetRomName = (void (FX_CALL *)(char*))grGetProcAddress (strSetRomName);
1880     grSetRomName (name);
1881   }
1882   // **
1883   return true;
1884 }
1885
1886 EXPORT void CALL RomResumed(void)
1887 {
1888 #ifdef PAULSCODE
1889   frameSkipper.start();
1890 #endif
1891 }
1892
1893 /******************************************************************
1894 Function: ShowCFB
1895 Purpose:  Useally once Dlists are started being displayed, cfb is
1896 ignored. This function tells the dll to start displaying
1897 them again.
1898 input:    none
1899 output:   none
1900 *******************************************************************/
1901 bool no_dlist = true;
1902 EXPORT void CALL ShowCFB (void)
1903 {
1904   no_dlist = true;
1905   VLOG ("ShowCFB ()\n");
1906 }
1907
1908 EXPORT void CALL SetRenderingCallback(void (*callback)(int))
1909 {
1910   VLOG("CALL SetRenderingCallback (*)\n");
1911     renderCallback = callback;
1912 }
1913
1914 void drawViRegBG()
1915 {
1916   LRDP("drawViRegBG\n");
1917   const wxUint32 VIwidth = *gfx.VI_WIDTH_REG;
1918   FB_TO_SCREEN_INFO fb_info;
1919   fb_info.width  = VIwidth;
1920   fb_info.height = (wxUint32)rdp.vi_height;
1921   if (fb_info.height == 0)
1922   {
1923     LRDP("Image height = 0 - skipping\n");
1924     return;
1925   }
1926   fb_info.ul_x = 0;
1927
1928   fb_info.lr_x = VIwidth - 1;
1929   //  fb_info.lr_x = (wxUint32)rdp.vi_width - 1;
1930   fb_info.ul_y = 0;
1931   fb_info.lr_y = fb_info.height - 1;
1932   fb_info.opaque = 1;
1933   fb_info.addr = *gfx.VI_ORIGIN_REG;
1934   fb_info.size = *gfx.VI_STATUS_REG & 3;
1935   rdp.last_bg = fb_info.addr;
1936
1937   bool drawn = DrawFrameBufferToScreen(fb_info);
1938   if (settings.hacks&hack_Lego && drawn)
1939   {
1940     rdp.updatescreen = 1;
1941     newSwapBuffers ();
1942     DrawFrameBufferToScreen(fb_info);
1943   }
1944 }
1945
1946 }
1947
1948 void drawNoFullscreenMessage();
1949
1950 void DrawFrameBuffer ()
1951 {
1952   if (!fullscreen)
1953   {
1954     drawNoFullscreenMessage();
1955   }
1956   if (to_fullscreen)
1957     GoToFullScreen();
1958
1959   if (fullscreen)
1960   {
1961     grDepthMask (FXTRUE);
1962     grColorMask (FXTRUE, FXTRUE);
1963     grBufferClear (0, 0, 0xFFFF);
1964     drawViRegBG();
1965   }
1966 }
1967
1968 extern "C" {
1969 /******************************************************************
1970 Function: UpdateScreen
1971 Purpose:  This function is called in response to a vsync of the
1972 screen were the VI bit in MI_INTR_REG has already been
1973 set
1974 input:    none
1975 output:   none
1976 *******************************************************************/
1977 wxUint32 update_screen_count = 0;
1978 EXPORT void CALL UpdateScreen (void)
1979 {
1980 #ifdef PAULSCODE
1981 //printf("UpdateScreen()\n");
1982   frameSkipper.update();
1983 #endif
1984 #ifdef LOG_KEY
1985   if (CheckKeyPressed(G64_VK_SPACE, 0x0001))
1986   {
1987     LOG ("KEY!!!\n");
1988   }
1989 #endif
1990   char out_buf[128];
1991   sprintf (out_buf, "UpdateScreen (). Origin: %08x, Old origin: %08x, width: %d\n", *gfx.VI_ORIGIN_REG, rdp.vi_org_reg, *gfx.VI_WIDTH_REG);
1992   VLOG (out_buf);
1993   LRDP(out_buf);
1994
1995   wxUint32 width = (*gfx.VI_WIDTH_REG) << 1;
1996   if (fullscreen && (*gfx.VI_ORIGIN_REG  > width))
1997     update_screen_count++;
1998 //TODO-PORT: wx times
1999 #ifdef FPS
2000   // vertical interrupt has occurred, increment counter
2001   vi_count ++;
2002
2003   // Check frames per second
2004   LARGE_INTEGER difference;
2005   QueryPerformanceCounter (&fps_next);
2006   difference.QuadPart = fps_next.QuadPart - fps_last.QuadPart;
2007   float diff_secs = (float)((double)difference.QuadPart / (double)perf_freq.QuadPart);
2008   if (diff_secs > 0.5f)
2009   {
2010     fps = (float)(fps_count / diff_secs);
2011     vi = (float)(vi_count / diff_secs);
2012     ntsc_percent = vi / 0.6f;
2013     pal_percent = vi / 0.5f;
2014     fps_last = fps_next;
2015     fps_count = 0;
2016     vi_count = 0;
2017   }
2018 #endif
2019   //*
2020   wxUint32 limit = (settings.hacks&hack_Lego) ? 15 : 30;
2021 #ifdef PAULSCODE0
2022   if (frameSkipper.willSkipNext())
2023         return;
2024 #endif
2025 #ifdef PAULSCODE
2026 //  if (!frameSkipper.hasSkipped())
2027   if (!frameSkipper.willSkipNext())
2028 #endif
2029   if ((settings.frame_buffer&fb_cpu_write_hack) && (update_screen_count > limit) && (rdp.last_bg == 0))
2030   {
2031     LRDP("DirectCPUWrite hack!\n");
2032     update_screen_count = 0;
2033     no_dlist = true;
2034     ClearCache ();
2035     UpdateScreen();
2036     return;
2037   }
2038   //*/
2039   //*
2040   if( no_dlist )
2041   {
2042     if( *gfx.VI_ORIGIN_REG  > width )
2043     {
2044       ChangeSize ();
2045       LRDP("ChangeSize done\n");
2046 #ifdef PAULSCODE
2047           if (!frameSkipper.willSkipNext())
2048 #endif
2049       DrawFrameBuffer();
2050       LRDP("DrawFrameBuffer done\n");
2051       rdp.updatescreen = 1;
2052       newSwapBuffers ();
2053     }
2054     return;
2055   }
2056   //*/
2057 #ifdef PAULSCODE0
2058   if (!frameSkipper.willSkipNext())
2059 #endif
2060   if (settings.swapmode == 0)
2061     newSwapBuffers ();
2062 }
2063
2064 static void DrawWholeFrameBufferToScreen()
2065 {
2066   static wxUint32 toScreenCI = 0;
2067   if (rdp.ci_width < 200)
2068     return;
2069   if (rdp.cimg == toScreenCI)
2070     return;
2071   toScreenCI = rdp.cimg;
2072   FB_TO_SCREEN_INFO fb_info;
2073   fb_info.addr   = rdp.cimg;
2074   fb_info.size   = rdp.ci_size;
2075   fb_info.width  = rdp.ci_width;
2076   fb_info.height = rdp.ci_height;
2077   if (fb_info.height == 0)
2078     return;
2079   fb_info.ul_x = 0;
2080   fb_info.lr_x = rdp.ci_width-1;
2081   fb_info.ul_y = 0;
2082   fb_info.lr_y = rdp.ci_height-1;
2083   fb_info.opaque = 0;
2084   DrawFrameBufferToScreen(fb_info);
2085   if (!(settings.frame_buffer & fb_ref))
2086     memset(gfx.RDRAM+rdp.cimg, 0, (rdp.ci_width*rdp.ci_height)<<rdp.ci_size>>1);
2087 }
2088
2089 static void GetGammaTable()
2090 {
2091   char strGetGammaTableExt[] = "grGetGammaTableExt";
2092   void (FX_CALL *grGetGammaTableExt)(FxU32, FxU32*, FxU32*, FxU32*) =
2093     (void (FX_CALL *)(FxU32, FxU32*, FxU32*, FxU32*))grGetProcAddress(strGetGammaTableExt);
2094   if (grGetGammaTableExt)
2095   {
2096     voodoo.gamma_table_r = new FxU32[voodoo.gamma_table_size];
2097     voodoo.gamma_table_g = new FxU32[voodoo.gamma_table_size];
2098     voodoo.gamma_table_b = new FxU32[voodoo.gamma_table_size];
2099     grGetGammaTableExt(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b);
2100   }
2101 }
2102
2103 }
2104 wxUint32 curframe = 0;
2105 void newSwapBuffers()
2106 {
2107 #ifdef PAULSCODE
2108 //frameSkipper.newFrame();
2109 //bool skipped = false;
2110 //printf("newSwapBuffers()\n");
2111 bool skipped = frameSkipper.willSkipNext();
2112 //bool skipped = frameSkipper.hasSkipped();
2113 #endif
2114   if (!rdp.updatescreen) {
2115 #ifdef PAULSCODE0
2116     if (skipped) {
2117       if (settings.frame_buffer & fb_read_back_to_screen2)
2118         DrawWholeFrameBufferToScreen();
2119       frameSkipper.newFrame();
2120     }
2121 #endif
2122     return;
2123   }
2124
2125   rdp.updatescreen = 0;
2126
2127   LRDP("swapped\n");
2128
2129   // Allow access to the whole screen
2130   if (fullscreen)
2131   {
2132     rdp.update |= UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
2133     grClipWindow (0, 0, settings.scr_res_x, settings.scr_res_y);
2134     grDepthBufferFunction (GR_CMP_ALWAYS);
2135     grDepthMask (FXFALSE);
2136     grCullMode (GR_CULL_DISABLE);
2137
2138     if ((settings.show_fps & 0xF) || settings.clock)
2139       set_message_combiner ();
2140 #ifdef FPS
2141     float y = (float)settings.res_y;
2142     if (settings.show_fps & 0x0F)
2143     {
2144       if (settings.show_fps & 4)
2145       {
2146         if (region)   // PAL
2147           output (0, y, 0, "%d%% ", (int)pal_percent);
2148         else
2149           output (0, y, 0, "%d%% ", (int)ntsc_percent);
2150         y -= 16;
2151       }
2152       if (settings.show_fps & 2)
2153       {
2154         output (0, y, 0, "VI/s: %.02f ", vi);
2155         y -= 16;
2156       }
2157       if (settings.show_fps & 1)
2158         output (0, y, 0, "FPS: %.02f ", fps);
2159     }
2160 #endif
2161
2162     if (settings.clock)
2163     {
2164       if (settings.clock_24_hr)
2165       {
2166           time_t ltime;
2167           time (&ltime);
2168           tm *cur_time = localtime (&ltime);
2169
2170           sprintf (out_buf, "%.2d:%.2d:%.2d", cur_time->tm_hour, cur_time->tm_min, cur_time->tm_sec);
2171       }
2172       else
2173       {
2174           char ampm[] = "AM";
2175           time_t ltime;
2176
2177           time (&ltime);
2178           tm *cur_time = localtime (&ltime);
2179
2180           if (cur_time->tm_hour >= 12)
2181           {
2182             strcpy (ampm, "PM");
2183             if (cur_time->tm_hour != 12)
2184               cur_time->tm_hour -= 12;
2185           }
2186           if (cur_time->tm_hour == 0)
2187             cur_time->tm_hour = 12;
2188
2189           if (cur_time->tm_hour >= 10)
2190             sprintf (out_buf, "%.5s %s", asctime(cur_time) + 11, ampm);
2191           else
2192             sprintf (out_buf, " %.4s %s", asctime(cur_time) + 12, ampm);
2193         }
2194         output ((float)(settings.res_x - 68), y, 0, out_buf, 0);
2195       }
2196     //hotkeys
2197     if (CheckKeyPressed(G64_VK_BACK, 0x0001))
2198     {
2199       hotkey_info.hk_filtering = 100;
2200       if (settings.filtering < 2)
2201         settings.filtering++;
2202       else
2203         settings.filtering = 0;
2204     }
2205     if ((abs((int)(frame_count - curframe)) > 3 ) && CheckKeyPressed(G64_VK_ALT, 0x8000))  //alt +
2206     {
2207       if (CheckKeyPressed(G64_VK_B, 0x8000))  //b
2208       {
2209         hotkey_info.hk_motionblur = 100;
2210         hotkey_info.hk_ref = 0;
2211         curframe = frame_count;
2212         settings.frame_buffer ^= fb_motionblur;
2213       }
2214       else if (CheckKeyPressed(G64_VK_V, 0x8000))  //v
2215       {
2216         hotkey_info.hk_ref = 100;
2217         hotkey_info.hk_motionblur = 0;
2218         curframe = frame_count;
2219         settings.frame_buffer ^= fb_ref;
2220       }
2221     }
2222     if (settings.buff_clear && (hotkey_info.hk_ref || hotkey_info.hk_motionblur || hotkey_info.hk_filtering))
2223     {
2224       set_message_combiner ();
2225       char buf[256];
2226       buf[0] = 0;
2227       char * message = 0;
2228       if (hotkey_info.hk_ref)
2229       {
2230         if (settings.frame_buffer & fb_ref)
2231           message = strcat(buf, "FB READ ALWAYS: ON");
2232         else
2233           message = strcat(buf, "FB READ ALWAYS: OFF");
2234         hotkey_info.hk_ref--;
2235       }
2236       if (hotkey_info.hk_motionblur)
2237       {
2238         if (settings.frame_buffer & fb_motionblur)
2239           message = strcat(buf, "  MOTION BLUR: ON");
2240         else
2241           message = strcat(buf, "  MOTION BLUR: OFF");
2242         hotkey_info.hk_motionblur--;
2243       }
2244       if (hotkey_info.hk_filtering)
2245       {
2246         switch (settings.filtering)
2247         {
2248         case 0:
2249           message = strcat(buf, "  FILTERING MODE: AUTOMATIC");
2250           break;
2251         case 1:
2252           message = strcat(buf, "  FILTERING MODE: FORCE BILINEAR");
2253           break;
2254         case 2:
2255           message = strcat(buf, "  FILTERING MODE: FORCE POINT-SAMPLED");
2256           break;
2257         }
2258         hotkey_info.hk_filtering--;
2259       }
2260       output (120.0f, (float)settings.res_y, 0, message, 0);
2261     }
2262   }
2263     #ifdef OLDAPI
2264   if (capture_screen)
2265   {
2266     //char path[256];
2267     // Make the directory if it doesn't exist
2268     if (!wxDirExists(capture_path))
2269       wxMkdir(capture_path);
2270     wxString path;
2271     wxString romName = rdp.RomName;
2272     romName.Replace(wxT(" "), wxT("_"), true);
2273     romName.Replace(wxT(":"), wxT(";"), true);
2274
2275     for (int i=1; ; i++)
2276     {
2277       path = capture_path;
2278       path += wxT("Glide64mk2_");
2279       path += romName;
2280       path += wxT("_");
2281       if (i < 10)
2282         path += wxT("0");
2283       path << i << wxT(".") << ScreenShotFormats[settings.ssformat].extension;
2284       if (!wxFileName::FileExists(path))
2285         break;
2286     }
2287
2288     const wxUint32 offset_x = (wxUint32)rdp.offset_x;
2289     const wxUint32 offset_y = (wxUint32)rdp.offset_y;
2290     const wxUint32 image_width = settings.scr_res_x - offset_x*2;
2291     const wxUint32 image_height = settings.scr_res_y - offset_y*2;
2292
2293     GrLfbInfo_t info;
2294     info.size = sizeof(GrLfbInfo_t);
2295     if (grLfbLock (GR_LFB_READ_ONLY,
2296       GR_BUFFER_BACKBUFFER,
2297       GR_LFBWRITEMODE_565,
2298       GR_ORIGIN_UPPER_LEFT,
2299       FXFALSE,
2300       &info))
2301     {
2302       wxUint8 *ssimg = (wxUint8*)malloc(image_width * image_height * 3); // will be free in wxImage destructor
2303       int sspos = 0;
2304       wxUint32 offset_src = info.strideInBytes * offset_y;
2305
2306       // Copy the screen
2307       if (info.writeMode == GR_LFBWRITEMODE_8888)
2308       {
2309         wxUint32 col;
2310         for (wxUint32 y = 0; y < image_height; y++)
2311         {
2312           wxUint32 *ptr = (wxUint32*)((wxUint8*)info.lfbPtr + offset_src);
2313           ptr += offset_x;
2314           for (wxUint32 x = 0; x < image_width; x++)
2315           {
2316             col = *(ptr++);
2317             ssimg[sspos++] = (wxUint8)((col >> 16) & 0xFF);
2318             ssimg[sspos++] = (wxUint8)((col >> 8) & 0xFF);
2319             ssimg[sspos++] = (wxUint8)(col & 0xFF);
2320           }
2321           offset_src += info.strideInBytes;
2322         }
2323       }
2324       else
2325       {
2326         wxUint16 col;
2327         for (wxUint32 y = 0; y < image_height; y++)
2328         {
2329           wxUint16 *ptr = (wxUint16*)((wxUint8*)info.lfbPtr + offset_src);
2330           ptr += offset_x;
2331           for (wxUint32 x = 0; x < image_width; x++)
2332           {
2333             col = *(ptr++);
2334             ssimg[sspos++] = (wxUint8)((float)(col >> 11) / 31.0f * 255.0f);
2335             ssimg[sspos++] = (wxUint8)((float)((col >> 5) & 0x3F) / 63.0f * 255.0f);
2336             ssimg[sspos++] = (wxUint8)((float)(col & 0x1F) / 31.0f * 255.0f);
2337           }
2338           offset_src += info.strideInBytes;
2339         }
2340       }
2341       // Unlock the backbuffer
2342       grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER);
2343       wxImage screenshot(image_width, image_height, ssimg);
2344       screenshot.SaveFile(path, ScreenShotFormats[settings.ssformat].type);
2345       capture_screen = 0;
2346     }
2347   }
2348     #endif
2349
2350   // Capture the screen if debug capture is set
2351   if (_debugger.capture)
2352   {
2353     // Allocate the screen
2354     _debugger.screen = new wxUint8 [(settings.res_x*settings.res_y) << 1];
2355
2356     // Lock the backbuffer (already rendered)
2357     GrLfbInfo_t info;
2358     info.size = sizeof(GrLfbInfo_t);
2359     while (!grLfbLock (GR_LFB_READ_ONLY,
2360       GR_BUFFER_BACKBUFFER,
2361       GR_LFBWRITEMODE_565,
2362       GR_ORIGIN_UPPER_LEFT,
2363       FXFALSE,
2364       &info));
2365
2366     wxUint32 offset_src=0, offset_dst=0;
2367
2368     // Copy the screen
2369     for (wxUint32 y=0; y<settings.res_y; y++)
2370     {
2371       if (info.writeMode == GR_LFBWRITEMODE_8888)
2372       {
2373         wxUint32 *src = (wxUint32*)((wxUint8*)info.lfbPtr + offset_src);
2374         wxUint16 *dst = (wxUint16*)(_debugger.screen + offset_dst);
2375         wxUint8 r, g, b;
2376         wxUint32 col;
2377         for (unsigned int x = 0; x < settings.res_x; x++)
2378         {
2379           col = src[x];
2380           r = (wxUint8)((col >> 19) & 0x1F);
2381           g = (wxUint8)((col >> 10) & 0x3F);
2382           b = (wxUint8)((col >> 3)  & 0x1F);
2383           dst[x] = (r<<11)|(g<<5)|b;
2384         }
2385       }
2386       else
2387       {
2388         memcpy (_debugger.screen + offset_dst, (wxUint8*)info.lfbPtr + offset_src, settings.res_x << 1);
2389       }
2390       offset_dst += settings.res_x << 1;
2391       offset_src += info.strideInBytes;
2392     }
2393
2394     // Unlock the backbuffer
2395     grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER);
2396   }
2397
2398   if (fullscreen && debugging)
2399   {
2400     debug_keys ();
2401     debug_cacheviewer ();
2402     debug_mouse ();
2403   }
2404
2405 #ifdef PAULSCODE
2406   if (!skipped)
2407 #endif
2408   if (settings.frame_buffer & fb_read_back_to_screen)
2409     DrawWholeFrameBufferToScreen();
2410
2411   if (fullscreen)
2412   {
2413     if (fb_hwfbe_enabled && !(settings.hacks&hack_RE2) && !evoodoo)
2414       grAuxBufferExt( GR_BUFFER_AUXBUFFER );
2415 #ifdef PAULSCODE
2416         if (skipped)
2417         {
2418                 vbo_resetcount();
2419         } 
2420         else
2421 #endif
2422         {
2423                 grBufferSwap (settings.vsync);
2424                 fps_count ++;
2425         }
2426 #ifdef PAULSCODE
2427     if (!skipped)
2428 #endif
2429     if (*gfx.VI_STATUS_REG&0x08) //gamma correction is used
2430     {
2431       if (!voodoo.gamma_correction)
2432       {
2433         if (voodoo.gamma_table_size && !voodoo.gamma_table_r)
2434           GetGammaTable(); //save initial gamma tables
2435         guGammaCorrectionRGB(2.0f, 2.0f, 2.0f); //with gamma=2.0 gamma table is the same, as in N64
2436         voodoo.gamma_correction = 1;
2437       }
2438     }
2439     else
2440     {
2441       if (voodoo.gamma_correction)
2442       {
2443         if (voodoo.gamma_table_r)
2444           grLoadGammaTable(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b);
2445         else
2446           guGammaCorrectionRGB(1.3f, 1.3f, 1.3f); //1.3f is default 3dfx gamma for everything but desktop
2447         voodoo.gamma_correction = 0;
2448       }
2449     }
2450   }
2451
2452   if (_debugger.capture)
2453     debug_capture ();
2454
2455   if (fullscreen)
2456   {
2457 #ifdef PAULSCODE0
2458     if (!skipped)
2459 #endif
2460     if  (debugging || settings.wireframe || settings.buff_clear || (settings.hacks&hack_PPL && settings.ucode == 6))
2461     {
2462       if (settings.hacks&hack_RE2 && fb_depth_render_enabled)
2463         grDepthMask (FXFALSE);
2464       else
2465         grDepthMask (FXTRUE);
2466       grBufferClear (0, 0, 0xFFFF);
2467     }
2468     /* //let the game to clear the buffers
2469     else
2470     {
2471     grDepthMask (FXTRUE);
2472     grColorMask (FXFALSE, FXFALSE);
2473     grBufferClear (0, 0, 0xFFFF);
2474     grColorMask (FXTRUE, FXTRUE);
2475     }
2476     */
2477   }
2478
2479 #ifdef PAULSCODE
2480   if (!skipped)
2481 #endif
2482   if (settings.frame_buffer & fb_read_back_to_screen2)
2483     DrawWholeFrameBufferToScreen();
2484
2485   frame_count ++;
2486 #ifdef PAULSCODE
2487         frameSkipper.newFrame();
2488 #endif
2489
2490   // Open/close debugger?
2491   if (CheckKeyPressed(G64_VK_SCROLL, 0x0001))
2492   {
2493     if (!debugging)
2494     {
2495       //if (settings.scr_res_x == 1024 && settings.scr_res_y == 768)
2496       {
2497         debugging = 1;
2498
2499         // Recalculate screen size, don't resize screen
2500         settings.res_x = (wxUint32)(settings.scr_res_x * 0.625f);
2501         settings.res_y = (wxUint32)(settings.scr_res_y * 0.625f);
2502
2503         ChangeSize ();
2504       }
2505     } 
2506     else
2507     {
2508       debugging = 0;
2509
2510       settings.res_x = settings.scr_res_x;
2511       settings.res_y = settings.scr_res_y;
2512
2513       ChangeSize ();
2514     }
2515   }
2516
2517   // Debug capture?
2518   if (/*fullscreen && */debugging && CheckKeyPressed(G64_VK_INSERT, 0x0001))
2519   {
2520     _debugger.capture = 1;
2521   }
2522 }
2523
2524 extern "C"
2525 {
2526
2527 /******************************************************************
2528 Function: ViStatusChanged
2529 Purpose:  This function is called to notify the dll that the
2530 ViStatus registers value has been changed.
2531 input:    none
2532 output:   none
2533 *******************************************************************/
2534 EXPORT void CALL ViStatusChanged (void)
2535 {
2536 }
2537
2538 /******************************************************************
2539 Function: ViWidthChanged
2540 Purpose:  This function is called to notify the dll that the
2541 ViWidth registers value has been changed.
2542 input:    none
2543 output:   none
2544 *******************************************************************/
2545 EXPORT void CALL ViWidthChanged (void)
2546 {
2547 }
2548
2549 #ifdef WINPROC_OVERRIDE
2550 LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2551 {
2552   switch (msg)
2553   {
2554   case WM_ACTIVATEAPP:
2555     if (wParam == TRUE && !fullscreen) rdp.window_changed = TRUE;
2556     break;
2557   case WM_PAINT:
2558     if (!fullscreen) rdp.window_changed = TRUE;
2559     break;
2560
2561     /*    case WM_DESTROY:
2562     SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
2563     break;*/
2564   }
2565
2566   return CallWindowProc(oldWndProc, hwnd, msg, wParam, lParam);
2567 }
2568 #endif
2569
2570 }
2571
2572 int CheckKeyPressed(int key, int mask)
2573 {
2574 static Glide64Keys g64Keys;
2575   if (settings.use_hotkeys == 0)
2576     return 0;
2577 #ifdef __WINDOWS__
2578   return (GetAsyncKeyState(g64Keys[key]) & mask);
2579 #else
2580   if (grKeyPressed)
2581     return grKeyPressed(g64Keys[key]);
2582 #endif
2583   return 0;
2584 }
2585
2586
2587 #ifdef ALTTAB_FIX
2588 int k_ctl=0, k_alt=0, k_del=0;
2589
2590 LRESULT CALLBACK LowLevelKeyboardProc(int nCode,
2591                                       WPARAM wParam, LPARAM lParam)
2592 {
2593   if (!fullscreen) return CallNextHookEx(NULL, nCode, wParam, lParam);
2594
2595   int TabKey = FALSE;
2596
2597   PKBDLLHOOKSTRUCT p;
2598
2599   if (nCode == HC_ACTION)
2600   {
2601     switch (wParam) {
2602 case WM_KEYUP:    case WM_SYSKEYUP:
2603   p = (PKBDLLHOOKSTRUCT) lParam;
2604   if (p->vkCode == 162) k_ctl = 0;
2605   if (p->vkCode == 164) k_alt = 0;
2606   if (p->vkCode == 46) k_del = 0;
2607   goto do_it;
2608
2609 case WM_KEYDOWN:  case WM_SYSKEYDOWN:
2610   p = (PKBDLLHOOKSTRUCT) lParam;
2611   if (p->vkCode == 162) k_ctl = 1;
2612   if (p->vkCode == 164) k_alt = 1;
2613   if (p->vkCode == 46) k_del = 1;
2614   goto do_it;
2615
2616 do_it:
2617   TabKey =
2618     ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
2619     ((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
2620     ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0)) ||
2621     (k_ctl && k_alt && k_del);
2622
2623   break;
2624     }
2625   }
2626
2627   if (TabKey)
2628   {
2629     k_ctl = 0;
2630     k_alt = 0;
2631     k_del = 0;
2632     ReleaseGfx ();
2633   }
2634
2635   return CallNextHookEx(NULL, nCode, wParam, lParam);
2636 }
2637 #endif
2638
2639 //
2640 // DllMain - called when the DLL is loaded, use this to get the DLL's instance
2641 //
2642 #ifdef OLDAPI
2643 class wxDLLApp : public wxApp
2644 {
2645 public:
2646   virtual bool OnInit();
2647 };
2648
2649 IMPLEMENT_APP_NO_MAIN(wxDLLApp)
2650
2651 bool wxDLLApp::OnInit()
2652 {
2653 /*  if (mutexProcessDList == NULL)
2654     mutexProcessDList = new wxMutex(wxMUTEX_DEFAULT);*/
2655   wxImage::AddHandler(new wxPNGHandler);
2656   wxImage::AddHandler(new wxJPEGHandler);
2657   return true;
2658 }
2659
2660 #ifndef __WINDOWS__
2661 int __attribute__ ((constructor)) DllLoad(void);
2662 int __attribute__ ((destructor)) DllUnload(void);
2663 #endif
2664
2665 // Called when the library is loaded and before dlopen() returns
2666 int DllLoad(void)
2667 {
2668     int argc = 0;
2669     char **argv = NULL;
2670     wxEntryStart(argc, argv);
2671     if (wxTheApp)
2672       return wxTheApp->CallOnInit() ? TRUE : FALSE;
2673     return 0;
2674 }
2675
2676 // Called when the library is unloaded and before dlclose() returns
2677 int DllUnload(void)
2678 {
2679     if ( wxTheApp )
2680       wxTheApp->OnExit();
2681     wxEntryCleanup();
2682     return TRUE;
2683 }
2684
2685 #ifdef __WINDOWS__
2686 extern "C" int WINAPI DllMain (HINSTANCE hinstDLL,
2687                      wxUint32 fdwReason,
2688                      LPVOID lpReserved)
2689 {
2690   sprintf (out_buf, "DllMain (%08lx - %d)\n", hinstDLL, fdwReason);
2691   LOG (out_buf);
2692
2693   if (fdwReason == DLL_PROCESS_ATTACH)
2694   {
2695     wxSetInstance(hinstDLL);
2696     return DllLoad();
2697   }
2698   else if (fdwReason == DLL_PROCESS_DETACH)
2699   {
2700     if (GFXWindow != NULL)
2701       GFXWindow->SetHWND(NULL);
2702     return DllUnload();
2703   }
2704   return TRUE;
2705 }
2706
2707 void CALL ReadScreen(void **dest, int *width, int *height)
2708 {
2709   *width = settings.res_x;
2710   *height = settings.res_y;
2711   wxUint8 * buff = (wxUint8*)malloc(settings.res_x * settings.res_y * 3);
2712   wxUint8 * line = buff;
2713   *dest = (void*)buff;
2714
2715   if (!fullscreen)
2716   {
2717     for (wxUint32 y=0; y<settings.res_y; y++)
2718     {
2719       for (wxUint32 x=0; x<settings.res_x; x++)
2720       {
2721         line[x*3] = 0x20;
2722         line[x*3+1] = 0x7f;
2723         line[x*3+2] = 0x40;
2724       }
2725     }
2726     LOG ("ReadScreen. not in the fullscreen!\n");
2727     return;
2728   }
2729
2730   GrLfbInfo_t info;
2731   info.size = sizeof(GrLfbInfo_t);
2732   if (grLfbLock (GR_LFB_READ_ONLY,
2733     GR_BUFFER_FRONTBUFFER,
2734     GR_LFBWRITEMODE_565,
2735     GR_ORIGIN_UPPER_LEFT,
2736     FXFALSE,
2737     &info))
2738   {
2739     wxUint32 offset_src=info.strideInBytes*(settings.scr_res_y-1);
2740
2741     // Copy the screen
2742     wxUint8 r, g, b;
2743     if (info.writeMode == GR_LFBWRITEMODE_8888)
2744     {
2745       wxUint32 col;
2746       for (wxUint32 y=0; y<settings.res_y; y++)
2747       {
2748         wxUint32 *ptr = (wxUint32*)((wxUint8*)info.lfbPtr + offset_src);
2749         for (wxUint32 x=0; x<settings.res_x; x++)
2750         {
2751           col = *(ptr++);
2752           r = (wxUint8)((col >> 16) & 0xFF);
2753           g = (wxUint8)((col >> 8) & 0xFF);
2754           b = (wxUint8)(col & 0xFF);
2755           line[x*3] = b;
2756           line[x*3+1] = g;
2757           line[x*3+2] = r;
2758         }
2759         line += settings.res_x * 3;
2760         offset_src -= info.strideInBytes;
2761       }
2762     }
2763     else
2764     {
2765       wxUint16 col;
2766       for (wxUint32 y=0; y<settings.res_y; y++)
2767       {
2768         wxUint16 *ptr = (wxUint16*)((wxUint8*)info.lfbPtr + offset_src);
2769         for (wxUint32 x=0; x<settings.res_x; x++)
2770         {
2771           col = *(ptr++);
2772           r = (wxUint8)((float)(col >> 11) / 31.0f * 255.0f);
2773           g = (wxUint8)((float)((col >> 5) & 0x3F) / 63.0f * 255.0f);
2774           b = (wxUint8)((float)(col & 0x1F) / 31.0f * 255.0f);
2775           line[x*3] = b;
2776           line[x*3+1] = g;
2777           line[x*3+2] = r;
2778         }
2779         line += settings.res_x * 3;
2780         offset_src -= info.strideInBytes;
2781       }
2782     }
2783     // Unlock the frontbuffer
2784     grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER);
2785   }
2786   LOG ("ReadScreen. Success.\n");
2787 }
2788 #endif
2789 #endif