2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002 Dave2001
4 * Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski
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
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.
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
21 //****************************************************************
23 // Glide64 - Glide Plugin for Nintendo 64 emulators
24 // Project started on December 29th, 2001
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
32 //****************************************************************
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.
38 //****************************************************************
49 #include "FBtoScreen.h"
50 #include "DepthBufferRender.h"
54 #elif defined(__MSC__)
56 #define PATH_MAX MAX_PATH
61 #include "osal_dynamiclib.h"
62 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
64 int ghq_dmptex_toggle_key = 0;
66 #if defined(__MINGW32__)
67 #define swprintf _snwprintf
68 #define vswprintf _vsnwprintf
71 #define G64_VERSION "G64 Mk2"
72 #define RELTIME "Date: " __DATE__// " Time: " __TIME__
84 std::ofstream rdp_log;
88 int elog_open = FALSE;
89 std::ofstream rdp_err;
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;
108 ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
109 ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
110 ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
111 ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL;
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;
127 GrContext_t gfx_context = 0;
128 int debugging = FALSE;
129 int exception = FALSE;
132 int ev_fullscreen = 0;
135 #define WINPROC_OVERRIDE
138 #ifdef WINPROC_OVERRIDE
139 LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
140 WNDPROC oldWndProc = NULL;
141 WNDPROC myWndProc = NULL;
145 HHOOK hhkLowLevelKybd = NULL;
146 LRESULT CALLBACK LowLevelKeyboardProc(int nCode,
147 WPARAM wParam, LPARAM lParam);
156 LARGE_INTEGER perf_freq;
157 LARGE_INTEGER fps_last;
158 LARGE_INTEGER fps_next;
160 wxUint32 fps_count = 0;
162 wxUint32 vi_count = 0;
167 float ntsc_percent = 0.0f;
168 float pal_percent = 0.0f;
173 // 60=0x0, 70=0x1, 72=0x2, 75=0x3, 80=0x4, 90=0x5, 100=0x6, 85=0x7, 120=0x8, none=0xff
176 //#include "ae_bridge.h"
177 #include "FrameSkipper.h"
178 FrameSkipper frameSkipper;
179 void vbo_resetcount();
182 unsigned long BMASK = 0x7FFFFF;
183 // Reality display processor structure
186 SETTINGS settings = { FALSE, 640, 480, GR_RESOLUTION_640x480, 0 };
188 HOTKEY_INFO hotkey_info;
190 VOODOO voodoo = {0, 0, 0, 0,
197 wxUint32 offset_font = 0;
198 wxUint32 offset_cursor = 0;
199 wxUint32 offset_textures = 0;
200 wxUint32 offset_texbuf1 = 0;
202 int capture_screen = 0;
203 char capture_path[256];
205 //SDL_sem *mutexProcessDList = SDL_CreateSemaphore(1);
207 // SOME FUNCTION DEFINITIONS
209 static void DrawFrameBuffer ();
212 void (*renderCallback)(int) = NULL;
213 static void (*l_DebugCallback)(void *, int, const char *) = NULL;
214 static void *l_DebugCallContext = NULL;
218 rdp.scale_1024 = settings.scr_res_x / 1024.0f;
219 rdp.scale_768 = settings.scr_res_y / 768.0f;
221 // float res_scl_x = (float)settings.res_x / 320.0f;
222 float res_scl_y = (float)settings.res_y / 240.0f;
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;
229 float fscale_x = (float)scale_x / 1024.0f;
230 float fscale_y = (float)scale_y / 2048.0f;
232 wxUint32 dwHStartReg = *gfx.VI_H_START_REG;
233 wxUint32 dwVStartReg = *gfx.VI_V_START_REG;
235 wxUint32 hstart = dwHStartReg >> 16;
236 wxUint32 hend = dwHStartReg & 0xFFFF;
238 // dunno... but sometimes this happens
239 if (hend == hstart) hend = (int)(*gfx.VI_WIDTH_REG / fscale_x);
241 wxUint32 vstart = dwVStartReg >> 16;
242 wxUint32 vend = dwVStartReg & 0xFFFF;
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;
249 sprintf (out_buf, "hstart: %d, hend: %d, vstart: %d, vend: %d\n", hstart, hend, vstart, vend);
251 sprintf (out_buf, "size: %d x %d\n", (int)rdp.vi_width, (int)rdp.vi_height);
255 rdp.scale_x = (float)settings.res_x / rdp.vi_width;
256 if (region > 0 && settings.pal230)
258 // odd... but pal games seem to want 230 as height...
259 rdp.scale_y = res_scl_y * (230.0f / rdp.vi_height) * aspect;
263 rdp.scale_y = (float)settings.res_y / rdp.vi_height * aspect;
265 // rdp.offset_x = settings.offset_x * res_scl_x;
266 // rdp.offset_y = settings.offset_y * res_scl_y;
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))
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;
278 rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR;
288 switch (settings.aspectmode)
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);
295 settings.res_x = settings.scr_res_x;
296 settings.res_y = (wxUint32)(settings.res_x / 4.0f * 3.0f);
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);
304 settings.res_x = settings.scr_res_x;
305 settings.res_y = (wxUint32)(settings.res_x / 16.0f * 9.0f);
308 default: //stretch or original
309 settings.res_x = settings.scr_res_x;
310 settings.res_y = settings.scr_res_y;
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
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;
324 // settings.res_x = settings.scr_res_x;
325 // settings.res_y = settings.scr_res_y;
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);
336 static wxConfigBase * OpenIni()
338 wxConfigBase * ini = wxConfigBase::Get(false);
341 if (iniName.IsEmpty())
342 iniName = pluginPath + wxT("/Glide64mk2.ini");
343 if (wxFileExists(iniName))
345 wxFileInputStream is(iniName);
346 wxFileConfig * fcfg = new wxFileConfig(is, wxConvISO8859_1);
347 wxConfigBase::Set(fcfg);
352 wxMessageBox(_T("Can not find ini file! Plugin will not run properly."), _T("File not found"), wxOK|wxICON_EXCLAMATION);
357 void WriteLog(m64p_msg_level level, const char *msg, ...)
362 vsnprintf(buf, 1023, msg, args);
367 l_DebugCallback(l_DebugCallContext, level, buf);
374 // LOG("ReadSettings\n");
377 ERRLOG("Could not open configuration!");
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");
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);
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);
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);
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);
410 settings.logging = (BOOL)Config_ReadInt ("logging", "Logging", 0);
411 settings.log_clear = (BOOL)Config_ReadInt ("log_clear", "", 0);
413 settings.run_in_window = (BOOL)Config_ReadInt ("run_in_window", "", 0);
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);
421 settings.autodetect_ucode = TRUE;
423 settings.wireframe = FALSE;
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;
435 #ifdef TEXTURE_FILTER
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]
440 // _("Smooth filtering 1"),
441 // _("Smooth filtering 2"),
442 // _("Smooth filtering 3"),
443 // _("Smooth filtering 4"),
444 // _("Sharp filtering 1"),
445 // _("Sharp filtering 2")
447 // settings.ghq_cmpr 0=S3TC and 1=FXT1
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]"
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);
474 settings.special_alt_tex_size = Config_ReadInt("alt_tex_size", "Alternate texture size method: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
475 settings.special_use_sts1_only = Config_ReadInt("use_sts1_only", "Use first SETTILESIZE only: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
476 settings.special_force_calc_sphere = Config_ReadInt("force_calc_sphere", "Use spheric mapping only: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
477 settings.special_correct_viewport = Config_ReadInt("correct_viewport", "Force positive viewport: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
478 settings.special_increase_texrect_edge = Config_ReadInt("increase_texrect_edge", "Force texrect size to integral value: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
479 settings.special_decrease_fillrect_edge = Config_ReadInt("decrease_fillrect_edge", "Reduce fillrect size by 1: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
480 settings.special_texture_correction = Config_ReadInt("texture_correction", "Enable perspective texture correction emulation: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
481 settings.special_pal230 = Config_ReadInt("pal230", "Set special scale for PAL games: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
482 settings.special_stipple_mode = Config_ReadInt("stipple_mode", "3DFX Dithered alpha emulation mode: -1=Game default, >=0=dithered alpha emulation mode", -1, TRUE, FALSE);
483 settings.special_stipple_pattern = Config_ReadInt("stipple_pattern", "3DFX Dithered alpha pattern: -1=Game default, >=0=pattern used for dithered alpha emulation", -1, TRUE, FALSE);
484 settings.special_force_microcheck = Config_ReadInt("force_microcheck", "Check microcode each frame: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
485 settings.special_force_quad3d = Config_ReadInt("force_quad3d", "Force 0xb5 command to be quad, not line 3D: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
486 settings.special_clip_zmin = Config_ReadInt("clip_zmin", "Enable near z clipping: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
487 settings.special_clip_zmax = Config_ReadInt("clip_zmax", "Enable far plane clipping: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
488 settings.special_fast_crc = Config_ReadInt("fast_crc", "Use fast CRC algorithm: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
489 settings.special_adjust_aspect = Config_ReadInt("adjust_aspect", "Adjust screen aspect for wide screen mode: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
490 settings.special_zmode_compare_less = Config_ReadInt("zmode_compare_less", "Force strict check in Depth buffer test: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
491 settings.special_old_style_adither = Config_ReadInt("old_style_adither", "Apply alpha dither regardless of alpha_dither_mode: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
492 settings.special_n64_z_scale = Config_ReadInt("n64_z_scale", "Scale vertex z value before writing to depth buffer: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
493 settings.special_optimize_texrect = Config_ReadInt("optimize_texrect", "Fast texrect rendering with hwfbe: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
494 settings.special_ignore_aux_copy = Config_ReadInt("ignore_aux_copy", "Do not copy auxiliary frame buffers: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
495 settings.special_hires_buf_clear = Config_ReadInt("hires_buf_clear", "Clear auxiliary texture frame buffers: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
496 settings.special_fb_read_alpha = Config_ReadInt("fb_read_alpha", "Read alpha from framebuffer: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
497 settings.special_useless_is_useless = Config_ReadInt("useless_is_useless", "Handle unchanged fb: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
498 settings.special_fb_crc_mode = Config_ReadInt("fb_crc_mode", "Set frambuffer CRC mode: -1=Game default, 0=disable CRC, 1=fast CRC, 2=safe CRC", -1, TRUE, FALSE);
499 settings.special_filtering = Config_ReadInt("filtering", "Filtering mode: -1=Game default, 0=automatic, 1=force bilinear, 2=force point sampled", -1, TRUE, FALSE);
500 settings.special_fog = Config_ReadInt("fog", "Fog: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
501 settings.special_buff_clear = Config_ReadInt("buff_clear", "Buffer clear on every frame: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
502 settings.special_swapmode = Config_ReadInt("swapmode", "Buffer swapping method: -1=Game default, 0=swap buffers when vertical interrupt has occurred, 1=swap buffers when set of conditions is satisfied. Prevents flicker on some games, 2=mix of first two methods", -1, TRUE, FALSE);
503 settings.special_aspect = Config_ReadInt("aspect", "Aspect ratio: -1=Game default, 0=Force 4:3, 1=Force 16:9, 2=Stretch, 3=Original", -1, TRUE, FALSE);
504 settings.special_lodmode = Config_ReadInt("lodmode", "LOD calculation: -1=Game default, 0=disable. 1=fast, 2=precise", -1, TRUE, FALSE);
505 settings.special_fb_smart = Config_ReadInt("fb_smart", "Smart framebuffer: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
506 settings.special_fb_hires = Config_ReadInt("fb_hires", "Hardware frame buffer emulation: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
507 settings.special_fb_read_always = Config_ReadInt("fb_read_always", "Read framebuffer every frame (may be slow use only for effects that need it e.g. Banjo Kazooie, DK64 transitions): -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
508 settings.special_read_back_to_screen = Config_ReadInt("read_back_to_screen", "Render N64 frame buffer as texture: -1=Game default, 0=disable, 1=mode1, 2=mode2", -1, TRUE, FALSE);
509 settings.special_detect_cpu_write = Config_ReadInt("detect_cpu_write", "Show images written directly by CPU: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
510 settings.special_fb_get_info = Config_ReadInt("fb_get_info", "Get frame buffer info: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
511 settings.special_fb_render = Config_ReadInt("fb_render", "Enable software depth render: -1=Game default, 0=disable. 1=enable", -1, TRUE, FALSE);
517 void ReadSpecialSettings (const char * name)
520 // sprintf(buf, "ReadSpecialSettings. Name: %s\n", name);
524 //detect games which require special hacks
525 if (strstr(name, (const char *)"ZELDA") || strstr(name, (const char *)"MASK"))
526 settings.hacks |= hack_Zelda;
527 else if (strstr(name, (const char *)"ROADSTERS TROPHY"))
528 settings.hacks |= hack_Zelda;
529 else if (strstr(name, (const char *)"Diddy Kong Racing"))
530 settings.hacks |= hack_Diddy;
531 else if (strstr(name, (const char *)"Tonic Trouble"))
532 settings.hacks |= hack_Tonic;
533 else if (strstr(name, (const char *)"All") && strstr(name, (const char *)"Star") && strstr(name, (const char *)"Baseball"))
534 settings.hacks |= hack_ASB;
535 else if (strstr(name, (const char *)"Beetle") || strstr(name, (const char *)"BEETLE") || strstr(name, (const char *)"HSV"))
536 settings.hacks |= hack_BAR;
537 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"))
538 settings.hacks |= hack_ISS64;
539 else if (strstr(name, (const char *)"MARIOKART64"))
540 settings.hacks |= hack_MK64;
541 else if (strstr(name, (const char *)"NITRO64"))
542 settings.hacks |= hack_WCWnitro;
543 else if (strstr(name, (const char *)"CHOPPER_ATTACK") || strstr(name, (const char *)"WILD CHOPPERS"))
544 settings.hacks |= hack_Chopper;
545 else if (strstr(name, (const char *)"Resident Evil II") || strstr(name, (const char *)"BioHazard II"))
546 settings.hacks |= hack_RE2;
547 else if (strstr(name, (const char *)"YOSHI STORY"))
548 settings.hacks |= hack_Yoshi;
549 else if (strstr(name, (const char *)"F-Zero X") || strstr(name, (const char *)"F-ZERO X"))
550 settings.hacks |= hack_Fzero;
551 else if (strstr(name, (const char *)"PAPER MARIO") || strstr(name, (const char *)"MARIO STORY"))
552 settings.hacks |= hack_PMario;
553 else if (strstr(name, (const char *)"TOP GEAR RALLY 2"))
554 settings.hacks |= hack_TGR2;
555 else if (strstr(name, (const char *)"TOP GEAR RALLY"))
556 settings.hacks |= hack_TGR;
557 else if (strstr(name, (const char *)"Top Gear Hyper Bike"))
558 settings.hacks |= hack_Hyperbike;
559 else if (strstr(name, (const char *)"Killer Instinct Gold") || strstr(name, (const char *)"KILLER INSTINCT GOLD"))
560 settings.hacks |= hack_KI;
561 else if (strstr(name, (const char *)"Knockout Kings 2000"))
562 settings.hacks |= hack_Knockout;
563 else if (strstr(name, (const char *)"LEGORacers"))
564 settings.hacks |= hack_Lego;
565 else if (strstr(name, (const char *)"OgreBattle64"))
566 settings.hacks |= hack_Ogre64;
567 else if (strstr(name, (const char *)"Pilot Wings64"))
568 settings.hacks |= hack_Pilotwings;
569 else if (strstr(name, (const char *)"Supercross"))
570 settings.hacks |= hack_Supercross;
571 else if (strstr(name, (const char *)"STARCRAFT 64"))
572 settings.hacks |= hack_Starcraft;
573 else if (strstr(name, (const char *)"BANJO KAZOOIE 2") || strstr(name, (const char *)"BANJO TOOIE"))
574 settings.hacks |= hack_Banjo2;
575 else if (strstr(name, (const char *)"FIFA: RTWC 98") || strstr(name, (const char *)"RoadToWorldCup98"))
576 settings.hacks |= hack_Fifa98;
577 else if (strstr(name, (const char *)"Mega Man 64") || strstr(name, (const char *)"RockMan Dash"))
578 settings.hacks |= hack_Megaman;
579 else if (strstr(name, (const char *)"MISCHIEF MAKERS") || strstr(name, (const char *)"TROUBLE MAKERS"))
580 settings.hacks |= hack_Makers;
581 else if (strstr(name, (const char *)"GOLDENEYE"))
582 settings.hacks |= hack_GoldenEye;
583 else if (strstr(name, (const char *)"PUZZLE LEAGUE"))
584 settings.hacks |= hack_PPL;
586 Ini * ini = Ini::OpenIni();
591 ini->Read(_T("alt_tex_size"), &(settings.alt_tex_size));
592 if (settings.special_alt_tex_size >= 0)
593 settings.alt_tex_size = settings.special_alt_tex_size;
595 ini->Read(_T("use_sts1_only"), &(settings.use_sts1_only));
596 if (settings.special_use_sts1_only >= 0)
597 settings.use_sts1_only = settings.special_use_sts1_only;
599 ini->Read(_T("force_calc_sphere"), &(settings.force_calc_sphere));
600 if (settings.special_force_calc_sphere >= 0)
601 settings.force_calc_sphere = settings.special_force_calc_sphere;
603 ini->Read(_T("correct_viewport"), &(settings.correct_viewport));
604 if (settings.special_correct_viewport >= 0)
605 settings.correct_viewport = settings.special_correct_viewport;
607 ini->Read(_T("increase_texrect_edge"), &(settings.increase_texrect_edge));
608 if (settings.special_increase_texrect_edge >= 0)
609 settings.increase_texrect_edge = settings.special_increase_texrect_edge;
611 ini->Read(_T("decrease_fillrect_edge"), &(settings.decrease_fillrect_edge));
612 if (settings.special_decrease_fillrect_edge >= 0)
613 settings.decrease_fillrect_edge = settings.special_decrease_fillrect_edge;
615 if (ini->Read(_T("texture_correction"), -1) == 0) settings.texture_correction = 0;
616 else settings.texture_correction = 1;
617 if (settings.special_texture_correction >= 0)
618 settings.texture_correction = settings.special_texture_correction;
620 if (ini->Read(_T("pal230"), -1) == 1) settings.pal230 = 1;
621 else settings.pal230 = 0;
622 if (settings.special_pal230 >= 0)
623 settings.pal230 = settings.special_pal230;
625 ini->Read(_T("stipple_mode"), &(settings.stipple_mode));
626 if (settings.special_stipple_mode >= 0)
627 settings.stipple_mode = settings.special_stipple_mode;
629 int stipple_pattern = ini->Read(_T("stipple_pattern"), -1);
630 if (stipple_pattern > 0) settings.stipple_pattern = (wxUint32)stipple_pattern;
631 if (settings.special_stipple_pattern >= 0)
632 stipple_pattern = settings.special_stipple_pattern;
634 ini->Read(_T("force_microcheck"), &(settings.force_microcheck));
635 if (settings.special_force_microcheck >= 0)
636 settings.force_microcheck = settings.special_force_microcheck;
638 ini->Read(_T("force_quad3d"), &(settings.force_quad3d));
639 if (settings.special_force_quad3d >= 0)
640 settings.force_quad3d = settings.special_force_quad3d;
642 ini->Read(_T("clip_zmin"), &(settings.clip_zmin));
643 if (settings.special_clip_zmin >= 0)
644 settings.clip_zmin = settings.special_clip_zmin;
646 ini->Read(_T("clip_zmax"), &(settings.clip_zmax));
647 if (settings.special_clip_zmax >= 0)
648 settings.clip_zmax = settings.special_clip_zmax;
650 ini->Read(_T("fast_crc"), &(settings.fast_crc));
651 if (settings.special_fast_crc >= 0)
652 settings.fast_crc = settings.special_fast_crc;
654 ini->Read(_T("adjust_aspect"), &(settings.adjust_aspect), 1);
655 if (settings.special_adjust_aspect >= 0)
656 settings.adjust_aspect = settings.special_adjust_aspect;
658 ini->Read(_T("zmode_compare_less"), &(settings.zmode_compare_less));
659 if (settings.special_zmode_compare_less >= 0)
660 settings.zmode_compare_less = settings.special_zmode_compare_less;
662 ini->Read(_T("old_style_adither"), &(settings.old_style_adither));
663 if (settings.special_old_style_adither >= 0)
664 settings.old_style_adither = settings.special_old_style_adither;
666 ini->Read(_T("n64_z_scale"), &(settings.n64_z_scale));
667 if (settings.special_n64_z_scale >= 0)
668 settings.n64_z_scale = settings.special_n64_z_scale;
670 if (settings.n64_z_scale)
674 int optimize_texrect = ini->Read(_T("optimize_texrect"), -1);
675 if (settings.special_optimize_texrect >= 0)
676 optimize_texrect = settings.special_optimize_texrect;
678 int ignore_aux_copy = ini->Read(_T("ignore_aux_copy"), -1);
679 if (settings.special_ignore_aux_copy >= 0)
680 ignore_aux_copy = settings.special_ignore_aux_copy;
682 int hires_buf_clear = ini->Read(_T("hires_buf_clear"), -1);
683 if (settings.special_hires_buf_clear >= 0)
684 hires_buf_clear = settings.special_hires_buf_clear;
686 int read_alpha = ini->Read(_T("fb_read_alpha"), -1);
687 if (settings.special_fb_read_alpha >= 0)
688 read_alpha = settings.special_fb_read_alpha;
690 int useless_is_useless = ini->Read(_T("useless_is_useless"), -1);
691 if (settings.special_useless_is_useless >= 0)
692 useless_is_useless = settings.special_useless_is_useless;
694 int fb_crc_mode = ini->Read(_T("fb_crc_mode"), -1);
695 if (settings.special_fb_crc_mode >= 0)
696 fb_crc_mode = settings.special_fb_crc_mode;
699 if (optimize_texrect > 0) settings.frame_buffer |= fb_optimize_texrect;
700 else if (optimize_texrect == 0) settings.frame_buffer &= ~fb_optimize_texrect;
701 if (ignore_aux_copy > 0) settings.frame_buffer |= fb_ignore_aux_copy;
702 else if (ignore_aux_copy == 0) settings.frame_buffer &= ~fb_ignore_aux_copy;
703 if (hires_buf_clear > 0) settings.frame_buffer |= fb_hwfbe_buf_clear;
704 else if (hires_buf_clear == 0) settings.frame_buffer &= ~fb_hwfbe_buf_clear;
705 if (read_alpha > 0) settings.frame_buffer |= fb_read_alpha;
706 else if (read_alpha == 0) settings.frame_buffer &= ~fb_read_alpha;
707 if (useless_is_useless > 0) settings.frame_buffer |= fb_useless_is_useless;
708 else settings.frame_buffer &= ~fb_useless_is_useless;
709 if (fb_crc_mode >= 0) settings.fb_crc_mode = (SETTINGS::FBCRCMODE)fb_crc_mode;
711 // if (settings.custom_ini)
713 ini->Read(_T("filtering"), &(settings.filtering));
714 ini->Read(_T("fog"), &(settings.fog));
715 ini->Read(_T("buff_clear"), &(settings.buff_clear));
716 ini->Read(_T("swapmode"), &(settings.swapmode));
717 int tmp_aspect = ini->Read(_T("aspect"), -1);
718 if (tmp_aspect != 0) settings.aspectmode = tmp_aspect;
719 ini->Read(_T("lodmode"), &(settings.lodmode));
721 ini->Read(_T("autoframeskip"), &(settings.autoframeskip));
722 ini->Read(_T("maxframeskip"), &(settings.maxframeskip));
723 if( settings.autoframeskip == 1 )
724 frameSkipper.setSkips( FrameSkipper::AUTO, settings.maxframeskip );
726 frameSkipper.setSkips( FrameSkipper::MANUAL, settings.maxframeskip );
730 TODO-port: fix resolutions
732 if (ini->Read(_T("resolution"), &resolution))
734 settings.res_data = (wxUint32)resolution;
735 if (settings.res_data >= 0x18) settings.res_data = 12;
736 settings.scr_res_x = settings.res_x = resolutions[settings.res_data][0];
737 settings.scr_res_y = settings.res_y = resolutions[settings.res_data][1];
741 PackedScreenResolution tmpRes = Config_ReadScreenSettings();
742 settings.res_data = tmpRes.resolution;
743 settings.scr_res_x = settings.res_x = tmpRes.width;
744 settings.scr_res_y = settings.res_y = tmpRes.height;
747 int smart_read = ini->Read(_T("fb_smart"), -1);
748 if (settings.special_fb_smart >= 0)
749 smart_read = settings.special_fb_smart;
751 int hires = ini->Read(_T("fb_hires"), -1);
752 if (settings.special_fb_hires >= 0)
753 hires = settings.special_fb_hires;
755 int read_always = ini->Read(_T("fb_read_always"), -1);
756 if (settings.special_fb_read_always >= 0)
757 read_always = settings.special_fb_read_always;
759 int read_back_to_screen = ini->Read(_T("read_back_to_screen"), -1);
760 if (settings.special_read_back_to_screen >= 0)
761 read_back_to_screen = settings.special_read_back_to_screen;
763 int cpu_write_hack = ini->Read(_T("detect_cpu_write"), -1);
764 if (settings.special_detect_cpu_write >= 0)
765 cpu_write_hack = settings.special_detect_cpu_write;
767 int get_fbinfo = ini->Read(_T("fb_get_info"), -1);
768 if (settings.special_fb_get_info >= 0)
769 get_fbinfo = settings.special_fb_get_info;
771 int depth_render = ini->Read(_T("fb_render"), -1);
772 if (settings.special_fb_render >= 0)
773 depth_render = settings.special_fb_render;
775 if (smart_read > 0) settings.frame_buffer |= fb_emulation;
776 else if (smart_read == 0) settings.frame_buffer &= ~fb_emulation;
777 if (hires > 0) settings.frame_buffer |= fb_hwfbe;
778 else if (hires == 0) settings.frame_buffer &= ~fb_hwfbe;
779 if (read_always > 0) settings.frame_buffer |= fb_ref;
780 else if (read_always == 0) settings.frame_buffer &= ~fb_ref;
781 if (read_back_to_screen == 1) settings.frame_buffer |= fb_read_back_to_screen;
782 else if (read_back_to_screen == 2) settings.frame_buffer |= fb_read_back_to_screen2;
783 else if (read_back_to_screen == 0) settings.frame_buffer &= ~(fb_read_back_to_screen|fb_read_back_to_screen2);
784 if (cpu_write_hack > 0) settings.frame_buffer |= fb_cpu_write_hack;
785 else if (cpu_write_hack == 0) settings.frame_buffer &= ~fb_cpu_write_hack;
786 if (get_fbinfo > 0) settings.frame_buffer |= fb_get_info;
787 else if (get_fbinfo == 0) settings.frame_buffer &= ~fb_get_info;
788 if (depth_render > 0) settings.frame_buffer |= fb_depth_render;
789 else if (depth_render == 0) settings.frame_buffer &= ~fb_depth_render;
790 settings.frame_buffer |= fb_motionblur;
792 settings.flame_corona = (settings.hacks & hack_Zelda) && !fb_depth_render_enabled;
795 //TODO-PORT: more ini stuff
796 void WriteSettings (bool saveEmulationSettings)
799 wxConfigBase * ini = OpenIni();
800 if (!ini || !ini->HasGroup(_T("/SETTINGS")))
802 ini->SetPath(_T("/SETTINGS"));
804 ini->Write(_T("card_id"), settings.card_id);
805 ini->Write(_T("lang_id"), settings.lang_id);
806 ini->Write(_T("resolution"), (int)settings.res_data);
807 ini->Write(_T("ssformat"), settings.ssformat);
808 ini->Write(_T("vsync"), settings.vsync);
809 ini->Write(_T("show_fps"), settings.show_fps);
810 ini->Write(_T("clock"), settings.clock);
811 ini->Write(_T("clock_24_hr"), settings.clock_24_hr);
812 ini->Write(_T("advanced_options"), settings.advanced_options);
813 ini->Write(_T("texenh_options"), settings.texenh_options);
815 ini->Write(_T("wrpResolution"), settings.wrpResolution);
816 ini->Write(_T("wrpVRAM"), settings.wrpVRAM);
817 ini->Write(_T("wrpFBO"), settings.wrpFBO);
818 ini->Write(_T("wrpAnisotropic"), settings.wrpAnisotropic);
820 #ifndef _ENDUSER_RELEASE_
821 ini->Write(_T("autodetect_ucode"), settings.autodetect_ucode);
822 ini->Write(_T("ucode"), (int)settings.ucode);
823 ini->Write(_T("wireframe"), settings.wireframe);
824 ini->Write(_T("wfmode"), settings.wfmode);
825 ini->Write(_T("logging"), settings.logging);
826 ini->Write(_T("log_clear"), settings.log_clear);
827 ini->Write(_T("run_in_window"), settings.run_in_window);
828 ini->Write(_T("elogging"), settings.elogging);
829 ini->Write(_T("filter_cache"), settings.filter_cache);
830 ini->Write(_T("unk_as_red"), settings.unk_as_red);
831 ini->Write(_T("log_unk"), settings.log_unk);
832 ini->Write(_T("unk_clear"), settings.unk_clear);
833 #endif //_ENDUSER_RELEASE_
835 #ifdef TEXTURE_FILTER
836 ini->Write(_T("ghq_fltr"), settings.ghq_fltr);
837 ini->Write(_T("ghq_cmpr"), settings.ghq_cmpr);
838 ini->Write(_T("ghq_enht"), settings.ghq_enht);
839 ini->Write(_T("ghq_hirs"), settings.ghq_hirs);
840 ini->Write(_T("ghq_enht_cmpr"), settings.ghq_enht_cmpr);
841 ini->Write(_T("ghq_enht_tile"), settings.ghq_enht_tile);
842 ini->Write(_T("ghq_enht_f16bpp"), settings.ghq_enht_f16bpp);
843 ini->Write(_T("ghq_enht_gz"), settings.ghq_enht_gz);
844 ini->Write(_T("ghq_enht_nobg"), settings.ghq_enht_nobg);
845 ini->Write(_T("ghq_hirs_cmpr"), settings.ghq_hirs_cmpr);
846 ini->Write(_T("ghq_hirs_tile"), settings.ghq_hirs_tile);
847 ini->Write(_T("ghq_hirs_f16bpp"), settings.ghq_hirs_f16bpp);
848 ini->Write(_T("ghq_hirs_gz"), settings.ghq_hirs_gz);
849 ini->Write(_T("ghq_hirs_altcrc"), settings.ghq_hirs_altcrc);
850 ini->Write(_T("ghq_cache_save"), settings.ghq_cache_save);
851 ini->Write(_T("ghq_cache_size"), settings.ghq_cache_size);
852 ini->Write(_T("ghq_hirs_let_texartists_fly"), settings.ghq_hirs_let_texartists_fly);
853 ini->Write(_T("ghq_hirs_dump"), settings.ghq_hirs_dump);
856 if (saveEmulationSettings)
860 wxString S = _T("/");
861 ini->SetPath(S+rdp.RomName);
864 ini->SetPath(_T("/DEFAULT"));
865 ini->Write(_T("filtering"), settings.filtering);
866 ini->Write(_T("fog"), settings.fog);
867 ini->Write(_T("buff_clear"), settings.buff_clear);
868 ini->Write(_T("swapmode"), settings.swapmode);
869 ini->Write(_T("lodmode"), settings.lodmode);
870 ini->Write(_T("aspect"), settings.aspectmode);
872 ini->Write(_T("fb_read_always"), settings.frame_buffer&fb_ref ? 1 : 0l);
873 ini->Write(_T("fb_smart"), settings.frame_buffer & fb_emulation ? 1 : 0l);
874 // ini->Write("motionblur", settings.frame_buffer & fb_motionblur ? 1 : 0);
875 ini->Write(_T("fb_hires"), settings.frame_buffer & fb_hwfbe ? 1 : 0l);
876 ini->Write(_T("fb_get_info"), settings.frame_buffer & fb_get_info ? 1 : 0l);
877 ini->Write(_T("fb_render"), settings.frame_buffer & fb_depth_render ? 1 : 0l);
878 ini->Write(_T("detect_cpu_write"), settings.frame_buffer & fb_cpu_write_hack ? 1 : 0l);
879 if (settings.frame_buffer & fb_read_back_to_screen)
880 ini->Write(_T("read_back_to_screen"), 1);
881 else if (settings.frame_buffer & fb_read_back_to_screen2)
882 ini->Write(_T("read_back_to_screen"), 2);
884 ini->Write(_T("read_back_to_screen"), 0l);
887 wxFileOutputStream os(iniName);
888 ((wxFileConfig*)ini)->Save(os);
892 GRTEXBUFFEREXT grTextureBufferExt = NULL;
893 GRTEXBUFFEREXT grTextureAuxBufferExt = NULL;
894 GRAUXBUFFEREXT grAuxBufferExt = NULL;
895 GRSTIPPLE grStippleModeExt = NULL;
896 GRSTIPPLE grStipplePatternExt = NULL;
897 FxBool (FX_CALL *grKeyPressed)(FxU32) = NULL;
899 int GetTexAddrUMA(int tmu, int texsize)
901 int addr = voodoo.tex_min_addr[0] + voodoo.tmem_ptr[0];
902 voodoo.tmem_ptr[0] += texsize;
903 voodoo.tmem_ptr[1] = voodoo.tmem_ptr[0];
906 int GetTexAddrNonUMA(int tmu, int texsize)
908 int addr = voodoo.tex_min_addr[tmu] + voodoo.tmem_ptr[tmu];
909 voodoo.tmem_ptr[tmu] += texsize;
912 GETTEXADDR GetTexAddr = GetTexAddrNonUMA;
914 // guLoadTextures - used to load the cursor and font textures
915 void guLoadTextures ()
917 if (grTextureBufferExt)
920 if (voodoo.max_tex_size <= 256)
922 grTextureBufferExt( GR_TMU1, voodoo.tex_min_addr[GR_TMU1], GR_LOD_LOG2_256, GR_LOD_LOG2_256,
923 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
924 tbuf_size = 8 * grTexCalcMemRequired(GR_LOD_LOG2_256, GR_LOD_LOG2_256,
925 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565);
927 else if (settings.scr_res_x <= 1024)
929 grTextureBufferExt( GR_TMU0, voodoo.tex_min_addr[GR_TMU0], GR_LOD_LOG2_1024, GR_LOD_LOG2_1024,
930 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
931 tbuf_size = grTexCalcMemRequired(GR_LOD_LOG2_1024, GR_LOD_LOG2_1024,
932 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565);
933 grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT );
934 grBufferClear (0, 0, 0xFFFF);
935 grRenderBuffer( GR_BUFFER_BACKBUFFER );
939 grTextureBufferExt( GR_TMU0, voodoo.tex_min_addr[GR_TMU0], GR_LOD_LOG2_2048, GR_LOD_LOG2_2048,
940 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
941 tbuf_size = grTexCalcMemRequired(GR_LOD_LOG2_2048, GR_LOD_LOG2_2048,
942 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565);
943 grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT );
944 grBufferClear (0, 0, 0xFFFF);
945 grRenderBuffer( GR_BUFFER_BACKBUFFER );
948 rdp.texbufs[0].tmu = GR_TMU0;
949 rdp.texbufs[0].begin = voodoo.tex_min_addr[GR_TMU0];
950 rdp.texbufs[0].end = rdp.texbufs[0].begin+tbuf_size;
951 rdp.texbufs[0].count = 0;
952 rdp.texbufs[0].clear_allowed = TRUE;
953 offset_font = tbuf_size;
954 if (voodoo.num_tmu > 1)
956 rdp.texbufs[1].tmu = GR_TMU1;
957 rdp.texbufs[1].begin = voodoo.tex_UMA ? rdp.texbufs[0].end : voodoo.tex_min_addr[GR_TMU1];
958 rdp.texbufs[1].end = rdp.texbufs[1].begin+tbuf_size;
959 rdp.texbufs[1].count = 0;
960 rdp.texbufs[1].clear_allowed = TRUE;
962 offset_font += tbuf_size;
964 offset_texbuf1 = tbuf_size;
971 wxUint32 *data = (wxUint32*)font;
974 // ** Font texture **
975 wxUint8 *tex8 = (wxUint8*)malloc(256*64);
977 fontTex.smallLodLog2 = fontTex.largeLodLog2 = GR_LOD_LOG2_256;
978 fontTex.aspectRatioLog2 = GR_ASPECT_LOG2_4x1;
979 fontTex.format = GR_TEXFMT_ALPHA_8;
982 // Decompression: [1-bit inverse alpha --> 8-bit alpha]
984 for (i=0; i<0x200; i++)
986 // cur = ~*(data++), byteswapped
988 cur = _byteswap_ulong(~*(data++));
991 cur = ((cur&0xFF)<<24)|(((cur>>8)&0xFF)<<16)|(((cur>>16)&0xFF)<<8)|((cur>>24)&0xFF);
994 for (b=0x80000000; b!=0; b>>=1)
996 if (cur&b) *tex8 = 0xFF;
1002 grTexDownloadMipMap (GR_TMU0,
1003 voodoo.tex_min_addr[GR_TMU0] + offset_font,
1004 GR_MIPMAPLEVELMASK_BOTH,
1007 offset_cursor = offset_font + grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, &fontTex);
1009 free (fontTex.data);
1011 // ** Cursor texture **
1013 data = (wxUint32*)cursor;
1015 wxUint16 *tex16 = (wxUint16*)malloc(32*32*2);
1017 cursorTex.smallLodLog2 = cursorTex.largeLodLog2 = GR_LOD_LOG2_32;
1018 cursorTex.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
1019 cursorTex.format = GR_TEXFMT_ARGB_1555;
1020 cursorTex.data = tex16;
1022 // Conversion: [16-bit 1555 (swapped) --> 16-bit 1555]
1023 for (i=0; i<0x200; i++)
1026 *(tex16++) = (wxUint16)(((cur&0x000000FF)<<8)|((cur&0x0000FF00)>>8));
1027 *(tex16++) = (wxUint16)(((cur&0x00FF0000)>>8)|((cur&0xFF000000)>>24));
1030 grTexDownloadMipMap (GR_TMU0,
1031 voodoo.tex_min_addr[GR_TMU0] + offset_cursor,
1032 GR_MIPMAPLEVELMASK_BOTH,
1035 // Round to higher 16
1036 offset_textures = ((offset_cursor + grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, &cursorTex))
1038 free (cursorTex.data);
1041 #ifdef TEXTURE_FILTER
1042 void DisplayLoadProgress(const wchar_t *format, ...)
1045 wchar_t wbuf[INFO_BUF];
1049 va_start(args, format);
1050 vswprintf(wbuf, INFO_BUF, format, args);
1053 // XXX: convert to multibyte
1054 wcstombs(buf, wbuf, INFO_BUF);
1059 set_message_combiner ();
1060 output (382, 380, 1, "LOADING TEXTURES. PLEASE WAIT...");
1061 int len = min (strlen(buf)*8, 1024);
1062 x = (1024-len)/2.0f;
1063 output (x, 360, 1, buf);
1065 grColorMask (FXTRUE, FXTRUE);
1066 grBufferClear (0, 0, 0xFFFF);
1073 #ifdef TEXTURE_FILTER
1074 wchar_t romname[256];
1075 wchar_t foldername[PATH_MAX + 64];
1076 wchar_t cachename[PATH_MAX + 64];
1081 OPEN_RDP_LOG (); // doesn't matter if opens again; it will check for it
1083 VLOG ("InitGfx ()\n");
1091 // Select the Glide device
1092 grSstSelect (settings.card_id);
1094 // Is mirroring allowed?
1095 const char *extensions = grGetString (GR_EXTENSION);
1097 // Check which SST we are using and initialize stuff
1098 // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1100 GR_SSTTYPE_VOODOO = 0,
1101 GR_SSTTYPE_SST96 = 1,
1102 GR_SSTTYPE_AT3D = 2,
1103 GR_SSTTYPE_Voodoo2 = 3,
1104 GR_SSTTYPE_Banshee = 4,
1105 GR_SSTTYPE_Voodoo3 = 5,
1106 GR_SSTTYPE_Voodoo4 = 6,
1107 GR_SSTTYPE_Voodoo5 = 7
1109 const char *hardware = grGetString(GR_HARDWARE);
1110 unsigned int SST_type = GR_SSTTYPE_VOODOO;
1111 if (strstr(hardware, "Rush")) {
1112 SST_type = GR_SSTTYPE_SST96;
1113 } else if (strstr(hardware, "Voodoo2")) {
1114 SST_type = GR_SSTTYPE_Voodoo2;
1115 } else if (strstr(hardware, "Voodoo Banshee")) {
1116 SST_type = GR_SSTTYPE_Banshee;
1117 } else if (strstr(hardware, "Voodoo3")) {
1118 SST_type = GR_SSTTYPE_Voodoo3;
1119 } else if (strstr(hardware, "Voodoo4")) {
1120 SST_type = GR_SSTTYPE_Voodoo4;
1121 } else if (strstr(hardware, "Voodoo5")) {
1122 SST_type = GR_SSTTYPE_Voodoo5;
1124 // 2Mb Texture boundary
1125 voodoo.has_2mb_tex_boundary = (SST_type < GR_SSTTYPE_Banshee) && !evoodoo;
1126 // use UMA if available
1127 voodoo.tex_UMA = FALSE;
1129 if (strstr(extensions, " TEXUMA ")) {
1130 // we get better texture cache hits with UMA on
1131 grEnable(GR_TEXTURE_UMA_EXT);
1132 voodoo.tex_UMA = TRUE;
1133 LOG ("Using TEXUMA extension.\n");
1136 //TODO-PORT: fullscreen stuff
1137 wxUint32 res_data = settings.res_data;
1138 char strWrapperFullScreenResolutionExt[] = "grWrapperFullScreenResolutionExt";
1141 GRWRAPPERFULLSCREENRESOLUTIONEXT grWrapperFullScreenResolutionExt =
1142 (GRWRAPPERFULLSCREENRESOLUTIONEXT)grGetProcAddress(strWrapperFullScreenResolutionExt);
1143 if (grWrapperFullScreenResolutionExt) {
1144 wxUint32 _width, _height = 0;
1145 settings.res_data = grWrapperFullScreenResolutionExt(&_width, &_height);
1146 settings.scr_res_x = settings.res_x = _width;
1147 settings.scr_res_y = settings.res_y = _height;
1149 res_data = settings.res_data;
1153 GRWRAPPERFULLSCREENRESOLUTIONEXT grWrapperFullScreenResolutionExt =
1154 (GRWRAPPERFULLSCREENRESOLUTIONEXT)grGetProcAddress(strWrapperFullScreenResolutionExt);
1155 if (grWrapperFullScreenResolutionExt != NULL)
1158 TODO-port: fix resolutions
1159 settings.res_data = settings.res_data_org;
1160 settings.scr_res_x = settings.res_x = resolutions[settings.res_data][0];
1161 settings.scr_res_y = settings.res_y = resolutions[settings.res_data][1];
1164 res_data = settings.res_data | 0x80000000;
1169 // Select the window
1171 if (fb_hwfbe_enabled)
1173 char strSstWinOpenExt[] ="grSstWinOpenExt";
1174 GRWINOPENEXT grSstWinOpenExt = (GRWINOPENEXT)grGetProcAddress(strSstWinOpenExt);
1175 if (grSstWinOpenExt)
1176 gfx_context = grSstWinOpenExt ((FxU32)NULL,
1179 GR_COLORFORMAT_RGBA,
1180 GR_ORIGIN_UPPER_LEFT,
1181 fb_emulation_enabled?GR_PIXFMT_RGB_565:GR_PIXFMT_ARGB_8888, //32b color is not compatible with fb emulation
1182 2, // Double-buffering
1183 1); // 1 auxillary buffer
1186 gfx_context = grSstWinOpen ((FxU32)NULL,
1189 GR_COLORFORMAT_RGBA,
1190 GR_ORIGIN_UPPER_LEFT,
1191 2, // Double-buffering
1192 1); // 1 auxillary buffer
1196 ERRLOG("Error setting display mode");
1197 // grSstWinClose (gfx_context);
1203 to_fullscreen = FALSE;
1206 // get the # of TMUs available
1207 grGet (GR_NUM_TMU, 4, (FxI32*)&voodoo.num_tmu);
1208 // get maximal texture size
1209 grGet (GR_MAX_TEXTURE_SIZE, 4, (FxI32*)&voodoo.max_tex_size);
1210 voodoo.sup_large_tex = (voodoo.max_tex_size > 256 && !(settings.hacks & hack_PPL));
1215 GetTexAddr = GetTexAddrUMA;
1216 voodoo.tex_min_addr[0] = voodoo.tex_min_addr[1] = grTexMinAddress(GR_TMU0);
1217 voodoo.tex_max_addr[0] = voodoo.tex_max_addr[1] = grTexMaxAddress(GR_TMU0);
1221 GetTexAddr = GetTexAddrNonUMA;
1222 voodoo.tex_min_addr[0] = grTexMinAddress(GR_TMU0);
1223 voodoo.tex_min_addr[1] = grTexMinAddress(GR_TMU1);
1224 voodoo.tex_max_addr[0] = grTexMaxAddress(GR_TMU0);
1225 voodoo.tex_max_addr[1] = grTexMaxAddress(GR_TMU1);
1228 if (strstr (extensions, "TEXMIRROR") && !(settings.hacks&hack_Zelda)) //zelda's trees suffer from hardware mirroring
1229 voodoo.sup_mirroring = 1;
1231 voodoo.sup_mirroring = 0;
1233 if (strstr (extensions, "TEXFMT")) //VSA100 texture format extension
1234 voodoo.sup_32bit_tex = TRUE;
1236 voodoo.sup_32bit_tex = FALSE;
1238 voodoo.gamma_correction = 0;
1239 if (strstr(extensions, "GETGAMMA"))
1240 grGet(GR_GAMMA_TABLE_ENTRIES, sizeof(voodoo.gamma_table_size), &voodoo.gamma_table_size);
1242 if (fb_hwfbe_enabled)
1244 if (char * extstr = (char*)strstr(extensions, "TEXTUREBUFFER"))
1246 if (!strncmp(extstr, "TEXTUREBUFFER", 13))
1248 char strTextureBufferExt[] = "grTextureBufferExt";
1249 grTextureBufferExt = (GRTEXBUFFEREXT) grGetProcAddress(strTextureBufferExt);
1250 char strTextureAuxBufferExt[] = "grTextureAuxBufferExt";
1251 grTextureAuxBufferExt = (GRTEXBUFFEREXT) grGetProcAddress(strTextureAuxBufferExt);
1252 char strAuxBufferExt[] = "grAuxBufferExt";
1253 grAuxBufferExt = (GRAUXBUFFEREXT) grGetProcAddress(strAuxBufferExt);
1257 settings.frame_buffer &= ~fb_hwfbe;
1260 grTextureBufferExt = 0;
1262 grStippleModeExt = (GRSTIPPLE)grStippleMode;
1263 grStipplePatternExt = (GRSTIPPLE)grStipplePattern;
1265 if (grStipplePatternExt)
1266 grStipplePatternExt(settings.stipple_pattern);
1268 // char strKeyPressedExt[] = "grKeyPressedExt";
1269 // grKeyPressed = (FxBool (FX_CALL *)(FxU32))grGetProcAddress (strKeyPressedExt);
1273 #ifdef SIMULATE_VOODOO1
1275 voodoo.sup_mirroring = 0;
1278 #ifdef SIMULATE_BANSHEE
1280 voodoo.sup_mirroring = 1;
1283 grCoordinateSpace (GR_WINDOW_COORDS);
1284 grVertexLayout (GR_PARAM_XY, offsetof(VERTEX,x), GR_PARAM_ENABLE);
1285 grVertexLayout (GR_PARAM_Q, offsetof(VERTEX,q), GR_PARAM_ENABLE);
1286 grVertexLayout (GR_PARAM_Z, offsetof(VERTEX,z), GR_PARAM_ENABLE);
1287 grVertexLayout (GR_PARAM_ST0, offsetof(VERTEX,coord[0]), GR_PARAM_ENABLE);
1288 grVertexLayout (GR_PARAM_ST1, offsetof(VERTEX,coord[2]), GR_PARAM_ENABLE);
1289 grVertexLayout (GR_PARAM_PARGB, offsetof(VERTEX,b), GR_PARAM_ENABLE);
1291 grCullMode(GR_CULL_NEGATIVE);
1293 if (settings.fog) //"FOGCOORD" extension
1295 if (strstr (extensions, "FOGCOORD"))
1298 guFogGenerateLinear (fog_t, 0.0f, 255.0f);//(float)rdp.fog_multiplier + (float)rdp.fog_offset);//256.0f);
1300 for (int i = 63; i > 0; i--)
1302 if (fog_t[i] - fog_t[i-1] > 63)
1304 fog_t[i-1] = fog_t[i] - 63;
1308 // for (int f = 0; f < 64; f++)
1310 // FRDP("fog[%d]=%d->%f\n", f, fog_t[f], guFogTableIndexToW(f));
1313 grVertexLayout (GR_PARAM_FOG_EXT, offsetof(VERTEX,f), GR_PARAM_ENABLE);
1315 else //not supported
1316 settings.fog = FALSE;
1319 grDepthBufferMode (GR_DEPTHBUFFER_ZBUFFER);
1320 grDepthBufferFunction(GR_CMP_LESS);
1321 grDepthMask(FXTRUE);
1323 settings.res_x = settings.scr_res_x;
1324 settings.res_y = settings.scr_res_y;
1330 grCullMode (GR_CULL_DISABLE);
1331 grDepthBufferMode (GR_DEPTHBUFFER_ZBUFFER);
1332 grDepthBufferFunction (GR_CMP_ALWAYS);
1333 grRenderBuffer(GR_BUFFER_BACKBUFFER);
1334 grColorMask (FXTRUE, FXTRUE);
1335 grDepthMask (FXTRUE);
1336 grBufferClear (0, 0, 0xFFFF);
1338 grBufferClear (0, 0, 0xFFFF);
1339 grDepthMask (FXFALSE);
1340 grTexFilterMode (0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR);
1341 grTexFilterMode (1, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR);
1342 grTexClampMode (0, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_CLAMP);
1343 grTexClampMode (1, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_CLAMP);
1344 grClipWindow (0, 0, settings.scr_res_x, settings.scr_res_y);
1345 rdp.update |= UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
1347 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1348 if (!settings.ghq_use)
1350 settings.ghq_use = settings.ghq_fltr || settings.ghq_enht /*|| settings.ghq_cmpr*/ || settings.ghq_hirs;
1351 if (settings.ghq_use)
1354 int options = texfltr[settings.ghq_fltr]|texenht[settings.ghq_enht]|texcmpr[settings.ghq_cmpr]|texhirs[settings.ghq_hirs];
1355 if (settings.ghq_enht_cmpr)
1356 options |= COMPRESS_TEX;
1357 if (settings.ghq_hirs_cmpr)
1358 options |= COMPRESS_HIRESTEX;
1359 // if (settings.ghq_enht_tile)
1360 // options |= TILE_TEX;
1361 if (settings.ghq_hirs_tile)
1362 options |= TILE_HIRESTEX;
1363 if (settings.ghq_enht_f16bpp)
1364 options |= FORCE16BPP_TEX;
1365 if (settings.ghq_hirs_f16bpp)
1366 options |= FORCE16BPP_HIRESTEX;
1367 if (settings.ghq_enht_gz)
1368 options |= GZ_TEXCACHE;
1369 if (settings.ghq_hirs_gz)
1370 options |= GZ_HIRESTEXCACHE;
1371 if (settings.ghq_cache_save)
1372 options |= (DUMP_TEXCACHE|DUMP_HIRESTEXCACHE);
1373 if (settings.ghq_hirs_let_texartists_fly)
1374 options |= LET_TEXARTISTS_FLY;
1375 if (settings.ghq_hirs_dump)
1376 options |= DUMP_TEX;
1378 ghq_dmptex_toggle_key = 0;
1380 swprintf(romname, sizeof(romname) / sizeof(*romname), L"%hs", rdp.RomName);
1381 swprintf(foldername, sizeof(foldername) / sizeof(*foldername), L"%hs", ConfigGetUserDataPath());
1382 swprintf(cachename, sizeof(cachename) / sizeof(*cachename), L"%hs", ConfigGetUserCachePath());
1384 settings.ghq_use = (int)ext_ghq_init(voodoo.max_tex_size, // max texture width supported by hardware
1385 voodoo.max_tex_size, // max texture height supported by hardware
1386 voodoo.sup_32bit_tex?32:16, // max texture bpp supported by hardware
1388 settings.ghq_cache_size * 1024*1024, // cache texture to system memory
1391 romname, // name of ROM. must be no longer than 256 characters
1392 DisplayLoadProgress);
1395 if (settings.ghq_use && strstr (extensions, "TEXMIRROR"))
1396 voodoo.sup_mirroring = 1;
1404 VLOG("ReleaseGfx ()\n");
1406 // Restore gamma settings
1407 if (voodoo.gamma_correction)
1409 if (voodoo.gamma_table_r)
1410 grLoadGammaTable(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b);
1412 guGammaCorrectionRGB(1.3f, 1.3f, 1.3f); //1.3f is default 3dfx gamma for everything but desktop
1413 voodoo.gamma_correction = 0;
1417 grSstWinClose (gfx_context);
1423 rdp.window_changed = TRUE;
1426 // new API code begins here!
1432 EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int front)
1434 VLOG("CALL ReadScreen2 ()\n");
1435 *width = settings.res_x;
1436 *height = settings.res_y;
1439 BYTE * line = (BYTE*)dest;
1442 for (wxUint32 y=0; y<settings.res_y; y++)
1444 for (wxUint32 x=0; x<settings.res_x; x++)
1451 // LOG ("ReadScreen. not in the fullscreen!\n");
1452 WARNLOG("[Glide64] Cannot save screenshot in windowed mode?\n");
1458 info.size = sizeof(GrLfbInfo_t);
1459 if (grLfbLock (GR_LFB_READ_ONLY,
1460 GR_BUFFER_FRONTBUFFER,
1461 GR_LFBWRITEMODE_888,
1462 GR_ORIGIN_UPPER_LEFT,
1466 // Copy the screen, let's hope this works.
1467 for (wxUint32 y=0; y<settings.res_y; y++)
1469 BYTE *ptr = (BYTE*) info.lfbPtr + (info.strideInBytes * y);
1470 for (wxUint32 x=0; x<settings.res_x; x++)
1472 line[x*3] = ptr[2]; // red
1473 line[x*3+1] = ptr[1]; // green
1474 line[x*3+2] = ptr[0]; // blue
1477 line += settings.res_x * 3;
1480 // Unlock the frontbuffer
1481 grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER);
1483 VLOG ("ReadScreen. Success.\n");
1487 EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
1488 void (*DebugCallback)(void *, int, const char *))
1490 VLOG("CALL PluginStartup ()\n");
1491 l_DebugCallback = DebugCallback;
1492 l_DebugCallContext = Context;
1494 /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */
1495 ptr_CoreGetAPIVersions CoreAPIVersionFunc;
1496 CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
1497 if (CoreAPIVersionFunc == NULL)
1499 ERRLOG("Core emulator broken; no CoreAPIVersionFunc() function found.");
1500 return M64ERR_INCOMPATIBLE;
1502 int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
1503 (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
1504 if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
1506 ERRLOG("Emulator core Config API incompatible with this plugin");
1507 return M64ERR_INCOMPATIBLE;
1509 if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000))
1511 ERRLOG("Emulator core Video Extension API incompatible with this plugin");
1512 return M64ERR_INCOMPATIBLE;
1515 ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
1516 ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
1517 ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
1518 ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
1519 ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
1520 ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
1521 ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
1522 ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
1523 ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
1524 ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
1525 ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
1527 ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath");
1528 ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath");
1529 ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath");
1530 ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath");
1532 if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter ||
1533 !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
1534 !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
1535 !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath)
1537 ERRLOG("Couldn't connect to Core configuration functions");
1538 return M64ERR_INCOMPATIBLE;
1541 /* Get the core Video Extension function pointers from the library handle */
1542 CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init");
1543 CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit");
1544 CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes");
1545 CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode");
1546 CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption");
1547 CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen");
1548 CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow");
1549 CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress");
1550 CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute");
1551 CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers");
1553 if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode ||
1554 !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_ResizeWindow || !CoreVideo_GL_GetProcAddress ||
1555 !CoreVideo_GL_SetAttribute || !CoreVideo_GL_SwapBuffers)
1557 ERRLOG("Couldn't connect to Core video functions");
1558 return M64ERR_INCOMPATIBLE;
1561 const char *configDir = ConfigGetSharedDataFilepath("Glide64mk2.ini");
1564 SetConfigDir(configDir);
1566 return M64ERR_SUCCESS;
1570 ERRLOG("Couldn't find Glide64mk2.ini");
1571 return M64ERR_FILES;
1575 EXPORT m64p_error CALL PluginShutdown(void)
1577 VLOG("CALL PluginShutdown ()\n");
1578 return M64ERR_SUCCESS;
1581 EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
1583 VLOG("CALL PluginGetVersion ()\n");
1584 /* set version info */
1585 if (PluginType != NULL)
1586 *PluginType = M64PLUGIN_GFX;
1588 if (PluginVersion != NULL)
1589 *PluginVersion = PLUGIN_VERSION;
1591 if (APIVersion != NULL)
1592 *APIVersion = VIDEO_PLUGIN_API_VERSION;
1594 if (PluginNamePtr != NULL)
1595 *PluginNamePtr = PLUGIN_NAME;
1597 if (Capabilities != NULL)
1602 return M64ERR_SUCCESS;
1605 /******************************************************************
1606 Function: CaptureScreen
1607 Purpose: This function dumps the current frame to a file
1608 input: pointer to the directory to save the file to
1610 *******************************************************************/
1611 EXPORT void CALL CaptureScreen ( char * Directory )
1614 strcpy (capture_path, Directory);
1617 /******************************************************************
1618 Function: ChangeWindow
1619 Purpose: to change the window between fullscreen and window
1620 mode. If the window was in fullscreen this should
1621 change the screen to window mode and vice vesa.
1624 *******************************************************************/
1625 //#warning ChangeWindow unimplemented
1626 EXPORT void CALL ChangeWindow (void)
1628 VLOG ("ChangeWindow()\n");
1634 to_fullscreen = TRUE;
1635 ev_fullscreen = TRUE;
1638 ShowWindow( gfx.hStatusBar, SW_HIDE );
1639 ShowCursor( FALSE );
1644 ev_fullscreen = FALSE;
1649 ShowWindow( gfx.hStatusBar, SW_SHOW );
1650 SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
1656 // Go to fullscreen at next dlist
1657 // This is for compatibility with 1964, which reloads the plugin
1658 // when switching to fullscreen
1661 to_fullscreen = TRUE;
1664 ShowWindow( gfx.hStatusBar, SW_HIDE );
1665 ShowCursor( FALSE );
1674 ShowWindow( gfx.hStatusBar, SW_SHOW );
1675 // SetWindowLong fixes the following Windows XP Banshee issues:
1676 // 1964 crash error when loading another rom.
1677 // All N64 emu's minimize, restore crashes.
1678 SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
1685 /******************************************************************
1687 Purpose: This function is called when the emulator is closing
1688 down allowing the dll to de-initialise.
1691 *******************************************************************/
1692 void CALL CloseDLL (void)
1694 VLOG ("CloseDLL ()\n");
1696 // re-set the old window proc
1697 #ifdef WINPROC_OVERRIDE
1698 SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
1702 if (hhkLowLevelKybd)
1704 UnhookWindowsHookEx(hhkLowLevelKybd);
1705 hhkLowLevelKybd = 0;
1711 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1712 if (settings.ghq_use)
1715 settings.ghq_use = 0;
1722 delete[] voodoo.gamma_table_r;
1723 voodoo.gamma_table_r = 0;
1724 delete[] voodoo.gamma_table_g;
1725 voodoo.gamma_table_g = 0;
1726 delete[] voodoo.gamma_table_b;
1727 voodoo.gamma_table_b = 0;
1730 /******************************************************************
1732 Purpose: This function is optional function that is provided
1733 to allow the user to test the dll
1734 input: a handle to the window that calls this function
1736 *******************************************************************/
1737 void CALL DllTest ( HWND hParent )
1741 /******************************************************************
1742 Function: DrawScreen
1743 Purpose: This function is called when the emulator receives a
1744 WM_PAINT message. This allows the gfx to fit in when
1745 it is being used in the desktop.
1748 *******************************************************************/
1749 void CALL DrawScreen (void)
1751 VLOG ("DrawScreen ()\n");
1754 /******************************************************************
1755 Function: GetDllInfo
1756 Purpose: This function allows the emulator to gather information
1757 about the dll by filling in the PluginInfo structure.
1758 input: a pointer to a PLUGIN_INFO stucture that needs to be
1759 filled by the function. (see def above)
1761 *******************************************************************/
1762 void CALL GetDllInfo ( PLUGIN_INFO * PluginInfo )
1764 VLOG ("GetDllInfo ()\n");
1765 PluginInfo->Version = 0x0103; // Set to 0x0103
1766 PluginInfo->Type = PLUGIN_TYPE_GFX; // Set to PLUGIN_TYPE_GFX
1767 sprintf (PluginInfo->Name, "Glide64mk2 " G64_VERSION RELTIME); // Name of the DLL
1769 // If DLL supports memory these memory options then set them to TRUE or FALSE
1770 // if it does not support it
1771 PluginInfo->NormalMemory = TRUE; // a normal wxUint8 array
1772 PluginInfo->MemoryBswaped = TRUE; // a normal wxUint8 array where the memory has been pre
1773 // bswap on a dword (32 bits) boundry
1777 BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER counter)
1781 /* generic routine */
1782 gettimeofday( &tv, NULL );
1783 counter->QuadPart = (LONGLONG)tv.tv_usec + (LONGLONG)tv.tv_sec * 1000000;
1787 BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER frequency)
1789 frequency->s.LowPart= 1000000;
1790 frequency->s.HighPart= 0;
1795 /******************************************************************
1796 Function: InitiateGFX
1797 Purpose: This function is called when the DLL is started to give
1798 information from the emulator that the n64 graphics
1799 uses. This is not called from the emulation thread.
1800 Input: Gfx_Info is passed to this function which is defined
1802 Output: TRUE on success
1803 FALSE on failure to initialise
1805 ** note on interrupts **:
1806 To generate an interrupt set the appropriate bit in MI_INTR_REG
1807 and then call the function CheckInterrupts to tell the emulator
1808 that there is a waiting interrupt.
1809 *******************************************************************/
1811 EXPORT int CALL InitiateGFX (GFX_INFO Gfx_Info)
1813 VLOG ("InitiateGFX (*)\n");
1816 // Assume scale of 1 for debug purposes
1820 memset (&settings, 0, sizeof(SETTINGS));
1822 char name[21] = "DEFAULT";
1823 ReadSpecialSettings (name);
1824 settings.res_data_org = settings.res_data;
1826 QueryPerformanceFrequency (&perf_freq);
1827 QueryPerformanceCounter (&fps_last);
1830 debug_init (); // Initialize debugger
1834 #ifdef WINPROC_OVERRIDE
1835 // [H.Morii] inject our own winproc so that "alt-enter to fullscreen"
1836 // message is shown when the emulator window is activated.
1837 WNDPROC curWndProc = (WNDPROC)GetWindowLong(gfx.hWnd, GWL_WNDPROC);
1838 if (curWndProc && curWndProc != (WNDPROC)WndProc) {
1839 oldWndProc = (WNDPROC)SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)WndProc);
1848 if (fb_depth_render_enabled)
1851 char strConfigWrapperExt[] = "grConfigWrapperExt";
1852 GRCONFIGWRAPPEREXT grConfigWrapperExt = (GRCONFIGWRAPPEREXT)grGetProcAddress(strConfigWrapperExt);
1853 if (grConfigWrapperExt)
1854 grConfigWrapperExt(settings.wrpResolution, settings.wrpVRAM * 1024 * 1024, settings.wrpFBO, settings.wrpAnisotropic);
1858 const char *extensions = grGetString (GR_EXTENSION);
1860 if (strstr (extensions, "EVOODOO"))
1863 voodoo.has_2mb_tex_boundary = 0;
1867 voodoo.has_2mb_tex_boundary = 1;
1873 /******************************************************************
1874 Function: MoveScreen
1875 Purpose: This function is called in response to the emulator
1876 receiving a WM_MOVE passing the xpos and ypos passed
1878 input: xpos - the x-coordinate of the upper-left corner of the
1879 client area of the window.
1880 ypos - y-coordinate of the upper-left corner of the
1881 client area of the window.
1883 *******************************************************************/
1884 EXPORT void CALL MoveScreen (int xpos, int ypos)
1886 rdp.window_changed = TRUE;
1889 /******************************************************************
1890 Function: ResizeVideoOutput
1891 Purpose: This function is called to force us to resize our output OpenGL window.
1892 This is currently unsupported, and should never be called because we do
1893 not pass the RESIZABLE flag to VidExt_SetVideoMode when initializing.
1894 input: new width and height
1896 *******************************************************************/
1897 EXPORT void CALL ResizeVideoOutput(int Width, int Height)
1901 /******************************************************************
1903 Purpose: This function is called when a rom is closed.
1906 *******************************************************************/
1907 EXPORT void CALL RomClosed (void)
1909 VLOG ("RomClosed ()\n");
1910 printf("RomClosed ()\n");
1914 rdp.window_changed = TRUE;
1916 // if (fullscreen && evoodoo)//*SEB*
1920 static void CheckDRAMSize()
1925 test = gfx.RDRAM[0x007FFFFF] + 1;
1936 sprintf (out_buf, "Detected RDRAM size: %08lx\n", BMASK);
1941 /******************************************************************
1943 Purpose: This function is called when a rom is open. (from the
1947 *******************************************************************/
1948 EXPORT int CALL RomOpen (void)
1950 VLOG ("RomOpen ()\n");
1953 ucode_error_report = TRUE; // allowed to report ucode errors
1956 // Get the country code & translate to NTSC(0) or PAL(1)
1957 wxUint16 code = ((wxUint16*)gfx.HEADER)[0x1F^1];
1959 if (code == 0x4400) region = 1; // Germany (PAL)
1960 if (code == 0x4500) region = 0; // USA (NTSC)
1961 if (code == 0x4A00) region = 0; // Japan (NTSC)
1962 if (code == 0x5000) region = 1; // Europe (PAL)
1963 if (code == 0x5500) region = 0; // Australia (NTSC)
1966 frameSkipper.setTargetFPS(region == 1 ? 50 : 60);
1969 char name[21] = "DEFAULT";
1970 ReadSpecialSettings (name);
1972 // get the name of the ROM
1973 for (int i=0; i<20; i++)
1974 name[i] = gfx.HEADER[(32+i)^3];
1977 // remove all trailing spaces
1978 while (name[strlen(name)-1] == ' ')
1979 name[strlen(name)-1] = 0;
1981 strncpy(rdp.RomName, name, sizeof(name));
1982 ReadSpecialSettings (name);
1991 // ** EVOODOO EXTENSIONS **
1997 const char *extensions = grGetString (GR_EXTENSION);
2002 if (strstr (extensions, "EVOODOO"))
2011 if (strstr (extensions, "ROMNAME"))
2013 char strSetRomName[] = "grSetRomName";
2014 void (FX_CALL *grSetRomName)(char*);
2015 grSetRomName = (void (FX_CALL *)(char*))grGetProcAddress (strSetRomName);
2016 grSetRomName (name);
2022 EXPORT void CALL RomResumed(void)
2025 frameSkipper.start();
2029 /******************************************************************
2031 Purpose: Useally once Dlists are started being displayed, cfb is
2032 ignored. This function tells the dll to start displaying
2036 *******************************************************************/
2037 bool no_dlist = true;
2038 EXPORT void CALL ShowCFB (void)
2041 VLOG ("ShowCFB ()\n");
2044 EXPORT void CALL SetRenderingCallback(void (*callback)(int))
2046 VLOG("CALL SetRenderingCallback (*)\n");
2047 renderCallback = callback;
2052 LRDP("drawViRegBG\n");
2053 const wxUint32 VIwidth = *gfx.VI_WIDTH_REG;
2054 FB_TO_SCREEN_INFO fb_info;
2055 fb_info.width = VIwidth;
2056 fb_info.height = (wxUint32)rdp.vi_height;
2057 if (fb_info.height == 0)
2059 LRDP("Image height = 0 - skipping\n");
2064 fb_info.lr_x = VIwidth - 1;
2065 // fb_info.lr_x = (wxUint32)rdp.vi_width - 1;
2067 fb_info.lr_y = fb_info.height - 1;
2069 fb_info.addr = *gfx.VI_ORIGIN_REG;
2070 fb_info.size = *gfx.VI_STATUS_REG & 3;
2071 rdp.last_bg = fb_info.addr;
2073 bool drawn = DrawFrameBufferToScreen(fb_info);
2074 if (settings.hacks&hack_Lego && drawn)
2076 rdp.updatescreen = 1;
2078 DrawFrameBufferToScreen(fb_info);
2084 void drawNoFullscreenMessage();
2086 void DrawFrameBuffer ()
2090 drawNoFullscreenMessage();
2097 grDepthMask (FXTRUE);
2098 grColorMask (FXTRUE, FXTRUE);
2099 grBufferClear (0, 0, 0xFFFF);
2105 /******************************************************************
2106 Function: UpdateScreen
2107 Purpose: This function is called in response to a vsync of the
2108 screen were the VI bit in MI_INTR_REG has already been
2112 *******************************************************************/
2113 wxUint32 update_screen_count = 0;
2114 EXPORT void CALL UpdateScreen (void)
2117 //printf("UpdateScreen()\n");
2118 frameSkipper.update();
2121 if (CheckKeyPressed(G64_VK_SPACE, 0x0001))
2127 sprintf (out_buf, "UpdateScreen (). Origin: %08x, Old origin: %08x, width: %d\n", *gfx.VI_ORIGIN_REG, rdp.vi_org_reg, *gfx.VI_WIDTH_REG);
2131 wxUint32 width = (*gfx.VI_WIDTH_REG) << 1;
2132 if (fullscreen && (*gfx.VI_ORIGIN_REG > width))
2133 update_screen_count++;
2134 //TODO-PORT: wx times
2136 // vertical interrupt has occurred, increment counter
2139 // Check frames per second
2140 LARGE_INTEGER difference;
2141 QueryPerformanceCounter (&fps_next);
2142 difference.QuadPart = fps_next.QuadPart - fps_last.QuadPart;
2143 float diff_secs = (float)((double)difference.QuadPart / (double)perf_freq.QuadPart);
2144 if (diff_secs > 0.5f)
2146 fps = (float)(fps_count / diff_secs);
2147 vi = (float)(vi_count / diff_secs);
2148 ntsc_percent = vi / 0.6f;
2149 pal_percent = vi / 0.5f;
2150 fps_last = fps_next;
2156 wxUint32 limit = (settings.hacks&hack_Lego) ? 15 : 30;
2158 if (frameSkipper.willSkipNext())
2162 // if (!frameSkipper.hasSkipped())
2163 if (!frameSkipper.willSkipNext())
2165 if ((settings.frame_buffer&fb_cpu_write_hack) && (update_screen_count > limit) && (rdp.last_bg == 0))
2167 LRDP("DirectCPUWrite hack!\n");
2168 update_screen_count = 0;
2178 if( *gfx.VI_ORIGIN_REG > width )
2181 LRDP("ChangeSize done\n");
2183 if (!frameSkipper.willSkipNext())
2186 LRDP("DrawFrameBuffer done\n");
2187 rdp.updatescreen = 1;
2194 if (!frameSkipper.willSkipNext())
2196 if (settings.swapmode == 0)
2200 static void DrawWholeFrameBufferToScreen()
2202 static wxUint32 toScreenCI = 0;
2203 if (rdp.ci_width < 200)
2205 if (rdp.cimg == toScreenCI)
2207 toScreenCI = rdp.cimg;
2208 FB_TO_SCREEN_INFO fb_info;
2209 fb_info.addr = rdp.cimg;
2210 fb_info.size = rdp.ci_size;
2211 fb_info.width = rdp.ci_width;
2212 fb_info.height = rdp.ci_height;
2213 if (fb_info.height == 0)
2216 fb_info.lr_x = rdp.ci_width-1;
2218 fb_info.lr_y = rdp.ci_height-1;
2220 DrawFrameBufferToScreen(fb_info);
2221 if (!(settings.frame_buffer & fb_ref))
2222 memset(gfx.RDRAM+rdp.cimg, 0, (rdp.ci_width*rdp.ci_height)<<rdp.ci_size>>1);
2225 static void GetGammaTable()
2227 char strGetGammaTableExt[] = "grGetGammaTableExt";
2228 void (FX_CALL *grGetGammaTableExt)(FxU32, FxU32*, FxU32*, FxU32*) =
2229 (void (FX_CALL *)(FxU32, FxU32*, FxU32*, FxU32*))grGetProcAddress(strGetGammaTableExt);
2230 if (grGetGammaTableExt)
2232 voodoo.gamma_table_r = new FxU32[voodoo.gamma_table_size];
2233 voodoo.gamma_table_g = new FxU32[voodoo.gamma_table_size];
2234 voodoo.gamma_table_b = new FxU32[voodoo.gamma_table_size];
2235 grGetGammaTableExt(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b);
2240 wxUint32 curframe = 0;
2241 void newSwapBuffers()
2244 //frameSkipper.newFrame();
2245 //bool skipped = false;
2246 //printf("newSwapBuffers()\n");
2247 bool skipped = frameSkipper.willSkipNext();
2248 //bool skipped = frameSkipper.hasSkipped();
2250 if (!rdp.updatescreen) {
2253 if (settings.frame_buffer & fb_read_back_to_screen2)
2254 DrawWholeFrameBufferToScreen();
2255 frameSkipper.newFrame();
2261 rdp.updatescreen = 0;
2265 // Allow access to the whole screen
2268 rdp.update |= UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
2269 grClipWindow (0, 0, settings.scr_res_x, settings.scr_res_y);
2270 grDepthBufferFunction (GR_CMP_ALWAYS);
2271 grDepthMask (FXFALSE);
2272 grCullMode (GR_CULL_DISABLE);
2274 if ((settings.show_fps & 0xF) || settings.clock)
2275 set_message_combiner ();
2277 float y = (float)settings.res_y;
2278 if (settings.show_fps & 0x0F)
2280 if (settings.show_fps & 4)
2283 output (0, y, 0, "%d%% ", (int)pal_percent);
2285 output (0, y, 0, "%d%% ", (int)ntsc_percent);
2288 if (settings.show_fps & 2)
2290 output (0, y, 0, "VI/s: %.02f ", vi);
2293 if (settings.show_fps & 1)
2294 output (0, y, 0, "FPS: %.02f ", fps);
2300 if (settings.clock_24_hr)
2304 tm *cur_time = localtime (<ime);
2306 sprintf (out_buf, "%.2d:%.2d:%.2d", cur_time->tm_hour, cur_time->tm_min, cur_time->tm_sec);
2314 tm *cur_time = localtime (<ime);
2316 if (cur_time->tm_hour >= 12)
2318 strcpy (ampm, "PM");
2319 if (cur_time->tm_hour != 12)
2320 cur_time->tm_hour -= 12;
2322 if (cur_time->tm_hour == 0)
2323 cur_time->tm_hour = 12;
2325 if (cur_time->tm_hour >= 10)
2326 sprintf (out_buf, "%.5s %s", asctime(cur_time) + 11, ampm);
2328 sprintf (out_buf, " %.4s %s", asctime(cur_time) + 12, ampm);
2330 output ((float)(settings.res_x - 68), y, 0, out_buf, 0);
2333 if (CheckKeyPressed(G64_VK_BACK, 0x0001))
2335 hotkey_info.hk_filtering = 100;
2336 if (settings.filtering < 2)
2337 settings.filtering++;
2339 settings.filtering = 0;
2341 if ((abs((int)(frame_count - curframe)) > 3 ) && CheckKeyPressed(G64_VK_ALT, 0x8000)) //alt +
2343 if (CheckKeyPressed(G64_VK_B, 0x8000)) //b
2345 hotkey_info.hk_motionblur = 100;
2346 hotkey_info.hk_ref = 0;
2347 curframe = frame_count;
2348 settings.frame_buffer ^= fb_motionblur;
2350 else if (CheckKeyPressed(G64_VK_V, 0x8000)) //v
2352 hotkey_info.hk_ref = 100;
2353 hotkey_info.hk_motionblur = 0;
2354 curframe = frame_count;
2355 settings.frame_buffer ^= fb_ref;
2358 if (settings.buff_clear && (hotkey_info.hk_ref || hotkey_info.hk_motionblur || hotkey_info.hk_filtering))
2360 set_message_combiner ();
2364 if (hotkey_info.hk_ref)
2366 if (settings.frame_buffer & fb_ref)
2367 message = strcat(buf, "FB READ ALWAYS: ON");
2369 message = strcat(buf, "FB READ ALWAYS: OFF");
2370 hotkey_info.hk_ref--;
2372 if (hotkey_info.hk_motionblur)
2374 if (settings.frame_buffer & fb_motionblur)
2375 message = strcat(buf, " MOTION BLUR: ON");
2377 message = strcat(buf, " MOTION BLUR: OFF");
2378 hotkey_info.hk_motionblur--;
2380 if (hotkey_info.hk_filtering)
2382 switch (settings.filtering)
2385 message = strcat(buf, " FILTERING MODE: AUTOMATIC");
2388 message = strcat(buf, " FILTERING MODE: FORCE BILINEAR");
2391 message = strcat(buf, " FILTERING MODE: FORCE POINT-SAMPLED");
2394 hotkey_info.hk_filtering--;
2396 output (120.0f, (float)settings.res_y, 0, message, 0);
2403 // Make the directory if it doesn't exist
2404 if (!wxDirExists(capture_path))
2405 wxMkdir(capture_path);
2407 wxString romName = rdp.RomName;
2408 romName.Replace(wxT(" "), wxT("_"), true);
2409 romName.Replace(wxT(":"), wxT(";"), true);
2411 for (int i=1; ; i++)
2413 path = capture_path;
2414 path += wxT("Glide64mk2_");
2419 path << i << wxT(".") << ScreenShotFormats[settings.ssformat].extension;
2420 if (!wxFileName::FileExists(path))
2424 const wxUint32 offset_x = (wxUint32)rdp.offset_x;
2425 const wxUint32 offset_y = (wxUint32)rdp.offset_y;
2426 const wxUint32 image_width = settings.scr_res_x - offset_x*2;
2427 const wxUint32 image_height = settings.scr_res_y - offset_y*2;
2430 info.size = sizeof(GrLfbInfo_t);
2431 if (grLfbLock (GR_LFB_READ_ONLY,
2432 GR_BUFFER_BACKBUFFER,
2433 GR_LFBWRITEMODE_565,
2434 GR_ORIGIN_UPPER_LEFT,
2438 wxUint8 *ssimg = (wxUint8*)malloc(image_width * image_height * 3); // will be free in wxImage destructor
2440 wxUint32 offset_src = info.strideInBytes * offset_y;
2443 if (info.writeMode == GR_LFBWRITEMODE_8888)
2446 for (wxUint32 y = 0; y < image_height; y++)
2448 wxUint32 *ptr = (wxUint32*)((wxUint8*)info.lfbPtr + offset_src);
2450 for (wxUint32 x = 0; x < image_width; x++)
2453 ssimg[sspos++] = (wxUint8)((col >> 16) & 0xFF);
2454 ssimg[sspos++] = (wxUint8)((col >> 8) & 0xFF);
2455 ssimg[sspos++] = (wxUint8)(col & 0xFF);
2457 offset_src += info.strideInBytes;
2463 for (wxUint32 y = 0; y < image_height; y++)
2465 wxUint16 *ptr = (wxUint16*)((wxUint8*)info.lfbPtr + offset_src);
2467 for (wxUint32 x = 0; x < image_width; x++)
2470 ssimg[sspos++] = (wxUint8)((float)(col >> 11) / 31.0f * 255.0f);
2471 ssimg[sspos++] = (wxUint8)((float)((col >> 5) & 0x3F) / 63.0f * 255.0f);
2472 ssimg[sspos++] = (wxUint8)((float)(col & 0x1F) / 31.0f * 255.0f);
2474 offset_src += info.strideInBytes;
2477 // Unlock the backbuffer
2478 grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER);
2479 wxImage screenshot(image_width, image_height, ssimg);
2480 screenshot.SaveFile(path, ScreenShotFormats[settings.ssformat].type);
2486 // Capture the screen if debug capture is set
2487 if (_debugger.capture)
2489 // Allocate the screen
2490 _debugger.screen = new wxUint8 [(settings.res_x*settings.res_y) << 1];
2492 // Lock the backbuffer (already rendered)
2494 info.size = sizeof(GrLfbInfo_t);
2495 while (!grLfbLock (GR_LFB_READ_ONLY,
2496 GR_BUFFER_BACKBUFFER,
2497 GR_LFBWRITEMODE_565,
2498 GR_ORIGIN_UPPER_LEFT,
2502 wxUint32 offset_src=0, offset_dst=0;
2505 for (wxUint32 y=0; y<settings.res_y; y++)
2507 if (info.writeMode == GR_LFBWRITEMODE_8888)
2509 wxUint32 *src = (wxUint32*)((wxUint8*)info.lfbPtr + offset_src);
2510 wxUint16 *dst = (wxUint16*)(_debugger.screen + offset_dst);
2513 for (unsigned int x = 0; x < settings.res_x; x++)
2516 r = (wxUint8)((col >> 19) & 0x1F);
2517 g = (wxUint8)((col >> 10) & 0x3F);
2518 b = (wxUint8)((col >> 3) & 0x1F);
2519 dst[x] = (r<<11)|(g<<5)|b;
2524 memcpy (_debugger.screen + offset_dst, (wxUint8*)info.lfbPtr + offset_src, settings.res_x << 1);
2526 offset_dst += settings.res_x << 1;
2527 offset_src += info.strideInBytes;
2530 // Unlock the backbuffer
2531 grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER);
2534 if (fullscreen && debugging)
2537 debug_cacheviewer ();
2544 if (settings.frame_buffer & fb_read_back_to_screen)
2545 DrawWholeFrameBufferToScreen();
2549 if (fb_hwfbe_enabled && !(settings.hacks&hack_RE2) && !evoodoo)
2550 grAuxBufferExt( GR_BUFFER_AUXBUFFER );
2559 grBufferSwap (settings.vsync);
2565 if (*gfx.VI_STATUS_REG&0x08) //gamma correction is used
2567 if (!voodoo.gamma_correction)
2569 if (voodoo.gamma_table_size && !voodoo.gamma_table_r)
2570 GetGammaTable(); //save initial gamma tables
2571 guGammaCorrectionRGB(2.0f, 2.0f, 2.0f); //with gamma=2.0 gamma table is the same, as in N64
2572 voodoo.gamma_correction = 1;
2577 if (voodoo.gamma_correction)
2579 if (voodoo.gamma_table_r)
2580 grLoadGammaTable(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b);
2582 guGammaCorrectionRGB(1.3f, 1.3f, 1.3f); //1.3f is default 3dfx gamma for everything but desktop
2583 voodoo.gamma_correction = 0;
2588 if (_debugger.capture)
2596 if (debugging || settings.wireframe || settings.buff_clear || (settings.hacks&hack_PPL && settings.ucode == 6))
2598 if (settings.hacks&hack_RE2 && fb_depth_render_enabled)
2599 grDepthMask (FXFALSE);
2601 grDepthMask (FXTRUE);
2602 grBufferClear (0, 0, 0xFFFF);
2604 /* //let the game to clear the buffers
2607 grDepthMask (FXTRUE);
2608 grColorMask (FXFALSE, FXFALSE);
2609 grBufferClear (0, 0, 0xFFFF);
2610 grColorMask (FXTRUE, FXTRUE);
2618 if (settings.frame_buffer & fb_read_back_to_screen2)
2619 DrawWholeFrameBufferToScreen();
2623 frameSkipper.newFrame();
2626 // Open/close debugger?
2627 if (CheckKeyPressed(G64_VK_SCROLL, 0x0001))
2631 //if (settings.scr_res_x == 1024 && settings.scr_res_y == 768)
2635 // Recalculate screen size, don't resize screen
2636 settings.res_x = (wxUint32)(settings.scr_res_x * 0.625f);
2637 settings.res_y = (wxUint32)(settings.scr_res_y * 0.625f);
2646 settings.res_x = settings.scr_res_x;
2647 settings.res_y = settings.scr_res_y;
2654 if (/*fullscreen && */debugging && CheckKeyPressed(G64_VK_INSERT, 0x0001))
2656 _debugger.capture = 1;
2663 /******************************************************************
2664 Function: ViStatusChanged
2665 Purpose: This function is called to notify the dll that the
2666 ViStatus registers value has been changed.
2669 *******************************************************************/
2670 EXPORT void CALL ViStatusChanged (void)
2674 /******************************************************************
2675 Function: ViWidthChanged
2676 Purpose: This function is called to notify the dll that the
2677 ViWidth registers value has been changed.
2680 *******************************************************************/
2681 EXPORT void CALL ViWidthChanged (void)
2685 #ifdef WINPROC_OVERRIDE
2686 LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2690 case WM_ACTIVATEAPP:
2691 if (wParam == TRUE && !fullscreen) rdp.window_changed = TRUE;
2694 if (!fullscreen) rdp.window_changed = TRUE;
2698 SetWindowLong (gfx.hWnd, GWL_WNDPROC, (long)oldWndProc);
2702 return CallWindowProc(oldWndProc, hwnd, msg, wParam, lParam);
2708 int CheckKeyPressed(int key, int mask)
2710 static Glide64Keys g64Keys;
2711 if (settings.use_hotkeys == 0)
2714 return (GetAsyncKeyState(g64Keys[key]) & mask);
2717 return grKeyPressed(g64Keys[key]);
2724 int k_ctl=0, k_alt=0, k_del=0;
2726 LRESULT CALLBACK LowLevelKeyboardProc(int nCode,
2727 WPARAM wParam, LPARAM lParam)
2729 if (!fullscreen) return CallNextHookEx(NULL, nCode, wParam, lParam);
2735 if (nCode == HC_ACTION)
2738 case WM_KEYUP: case WM_SYSKEYUP:
2739 p = (PKBDLLHOOKSTRUCT) lParam;
2740 if (p->vkCode == 162) k_ctl = 0;
2741 if (p->vkCode == 164) k_alt = 0;
2742 if (p->vkCode == 46) k_del = 0;
2745 case WM_KEYDOWN: case WM_SYSKEYDOWN:
2746 p = (PKBDLLHOOKSTRUCT) lParam;
2747 if (p->vkCode == 162) k_ctl = 1;
2748 if (p->vkCode == 164) k_alt = 1;
2749 if (p->vkCode == 46) k_del = 1;
2754 ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
2755 ((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
2756 ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0)) ||
2757 (k_ctl && k_alt && k_del);
2771 return CallNextHookEx(NULL, nCode, wParam, lParam);
2776 // DllMain - called when the DLL is loaded, use this to get the DLL's instance
2779 class wxDLLApp : public wxApp
2782 virtual bool OnInit();
2785 IMPLEMENT_APP_NO_MAIN(wxDLLApp)
2787 bool wxDLLApp::OnInit()
2789 /* if (mutexProcessDList == NULL)
2790 mutexProcessDList = new wxMutex(wxMUTEX_DEFAULT);*/
2791 wxImage::AddHandler(new wxPNGHandler);
2792 wxImage::AddHandler(new wxJPEGHandler);
2797 int __attribute__ ((constructor)) DllLoad(void);
2798 int __attribute__ ((destructor)) DllUnload(void);
2801 // Called when the library is loaded and before dlopen() returns
2806 wxEntryStart(argc, argv);
2808 return wxTheApp->CallOnInit() ? TRUE : FALSE;
2812 // Called when the library is unloaded and before dlclose() returns
2822 extern "C" int WINAPI DllMain (HINSTANCE hinstDLL,
2826 sprintf (out_buf, "DllMain (%08lx - %d)\n", hinstDLL, fdwReason);
2829 if (fdwReason == DLL_PROCESS_ATTACH)
2831 wxSetInstance(hinstDLL);
2834 else if (fdwReason == DLL_PROCESS_DETACH)
2836 if (GFXWindow != NULL)
2837 GFXWindow->SetHWND(NULL);
2843 void CALL ReadScreen(void **dest, int *width, int *height)
2845 *width = settings.res_x;
2846 *height = settings.res_y;
2847 wxUint8 * buff = (wxUint8*)malloc(settings.res_x * settings.res_y * 3);
2848 wxUint8 * line = buff;
2849 *dest = (void*)buff;
2853 for (wxUint32 y=0; y<settings.res_y; y++)
2855 for (wxUint32 x=0; x<settings.res_x; x++)
2862 LOG ("ReadScreen. not in the fullscreen!\n");
2867 info.size = sizeof(GrLfbInfo_t);
2868 if (grLfbLock (GR_LFB_READ_ONLY,
2869 GR_BUFFER_FRONTBUFFER,
2870 GR_LFBWRITEMODE_565,
2871 GR_ORIGIN_UPPER_LEFT,
2875 wxUint32 offset_src=info.strideInBytes*(settings.scr_res_y-1);
2879 if (info.writeMode == GR_LFBWRITEMODE_8888)
2882 for (wxUint32 y=0; y<settings.res_y; y++)
2884 wxUint32 *ptr = (wxUint32*)((wxUint8*)info.lfbPtr + offset_src);
2885 for (wxUint32 x=0; x<settings.res_x; x++)
2888 r = (wxUint8)((col >> 16) & 0xFF);
2889 g = (wxUint8)((col >> 8) & 0xFF);
2890 b = (wxUint8)(col & 0xFF);
2895 line += settings.res_x * 3;
2896 offset_src -= info.strideInBytes;
2902 for (wxUint32 y=0; y<settings.res_y; y++)
2904 wxUint16 *ptr = (wxUint16*)((wxUint8*)info.lfbPtr + offset_src);
2905 for (wxUint32 x=0; x<settings.res_x; x++)
2908 r = (wxUint8)((float)(col >> 11) / 31.0f * 255.0f);
2909 g = (wxUint8)((float)((col >> 5) & 0x3F) / 63.0f * 255.0f);
2910 b = (wxUint8)((float)(col & 0x1F) / 31.0f * 255.0f);
2915 line += settings.res_x * 3;
2916 offset_src -= info.strideInBytes;
2919 // Unlock the frontbuffer
2920 grLfbUnlock (GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER);
2922 LOG ("ReadScreen. Success.\n");