/* * Glide64 - Glide video plugin for Nintendo 64 emulators. * Copyright (c) 2002 Dave2001 * Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ //**************************************************************** // // Glide64 - Glide Plugin for Nintendo 64 emulators // Project started on December 29th, 2001 // // Authors: // Dave2001, original author, founded the project in 2001, left it in 2002 // Gugaman, joined the project in 2002, left it in 2002 // Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002 // Hiroshi 'KoolSmoky' Morii, joined the project in 2007 // //**************************************************************** // // To modify Glide64: // * 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. // * 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. // //**************************************************************** #include #include #include "Gfx_1.3.h" #include "Version.h" #include #include #include #include #include #include #include #include "Config.h" #include "Util.h" #include "3dmath.h" #include "Debugger.h" #include "Combine.h" #include "TexCache.h" #include "CRC.h" #include "FBtoScreen.h" #include "DepthBufferRender.h" #include "trace.h" #ifdef TEXTURE_FILTER // Hiroshi Morii #include int ghq_dmptex_toggle_key = 0; #endif GFX_INFO gfx; int to_fullscreen = FALSE; int GfxInitDone = FALSE; bool g_romopen = false; GrContext_t gfx_context = 0; int debugging = FALSE; int exception = FALSE; int evoodoo = 0; int ev_fullscreen = 0; #ifdef _WIN32 HINSTANCE hinstDLL = NULL; #endif #ifdef ALTTAB_FIX HHOOK hhkLowLevelKybd = NULL; LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); #endif #ifdef PERFORMANCE int64 perf_cur; int64 perf_next; #endif #ifdef FPS HighResTimeStamp fps_last; HighResTimeStamp fps_next; float fps = 0.0f; uint32_t fps_count = 0; uint32_t vi_count = 0; float vi = 0.0f; uint32_t region = 0; float ntsc_percent = 0.0f; float pal_percent = 0.0f; #endif // Resolutions, MUST be in the correct order (SST1VID.H) uint32_t resolutions[0x18][2] = { { 320, 200 }, { 320, 240 }, { 400, 256 }, { 512, 384 }, { 640, 200 }, { 640, 350 }, { 640, 400 }, { 640, 480 }, { 800, 600 }, { 960, 720 }, { 856, 480 }, { 512, 256 }, { 1024, 768 }, { 1280, 1024 }, { 1600, 1200 }, { 400, 300 }, // 0x10 { 1152, 864 }, { 1280, 960 }, { 1600, 1024 }, { 1792, 1344 }, { 1856, 1392 }, { 1920, 1440 }, { 2048, 1536 }, { 2048, 2048 } }; // ref rate // 60=0x0, 70=0x1, 72=0x2, 75=0x3, 80=0x4, 90=0x5, 100=0x6, 85=0x7, 120=0x8, none=0xff unsigned int BMASK = 0x7FFFFF; // Reality display processor structure RDP rdp; CSettings * g_settings; HOTKEY_INFO hotkey_info; VOODOO voodoo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; GrTexInfo fontTex; GrTexInfo cursorTex; uint32_t offset_font = 0; uint32_t offset_cursor = 0; uint32_t offset_textures = 0; uint32_t offset_texbuf1 = 0; int capture_screen = 0; std::string capture_path; void _ChangeSize() { rdp.scale_1024 = g_settings->scr_res_x / 1024.0f; rdp.scale_768 = g_settings->scr_res_y / 768.0f; // float res_scl_x = (float)g_settings->res_x / 320.0f; float res_scl_y = (float)g_settings->res_y / 240.0f; uint32_t scale_x = *gfx.VI_X_SCALE_REG & 0xFFF; if (!scale_x) return; uint32_t scale_y = *gfx.VI_Y_SCALE_REG & 0xFFF; if (!scale_y) return; float fscale_x = (float)scale_x / 1024.0f; float fscale_y = (float)scale_y / 2048.0f; uint32_t dwHStartReg = *gfx.VI_H_START_REG; uint32_t dwVStartReg = *gfx.VI_V_START_REG; uint32_t hstart = dwHStartReg >> 16; uint32_t hend = dwHStartReg & 0xFFFF; // dunno... but sometimes this happens if (hend == hstart) hend = (int)(*gfx.VI_WIDTH_REG / fscale_x); uint32_t vstart = dwVStartReg >> 16; uint32_t vend = dwVStartReg & 0xFFFF; rdp.vi_width = (hend - hstart) * fscale_x; rdp.vi_height = (vend - vstart) * fscale_y * 1.0126582f; float aspect = (g_settings->adjust_aspect && (fscale_y > fscale_x) && (rdp.vi_width > rdp.vi_height)) ? fscale_x / fscale_y : 1.0f; WriteTrace(TraceResolution, TraceDebug, "hstart: %d, hend: %d, vstart: %d, vend: %d", hstart, hend, vstart, vend); WriteTrace(TraceResolution, TraceDebug, "size: %d x %d", (int)rdp.vi_width, (int)rdp.vi_height); rdp.scale_x = (float)g_settings->res_x / rdp.vi_width; if (region > 0 && g_settings->pal230) { // odd... but pal games seem to want 230 as height... rdp.scale_y = res_scl_y * (230.0f / rdp.vi_height) * aspect; } else { rdp.scale_y = (float)g_settings->res_y / rdp.vi_height * aspect; } // rdp.offset_x = g_settings->offset_x * res_scl_x; // rdp.offset_y = g_settings->offset_y * res_scl_y; //rdp.offset_x = 0; // rdp.offset_y = 0; rdp.offset_y = ((float)g_settings->res_y - rdp.vi_height * rdp.scale_y) * 0.5f; if (((uint32_t)rdp.vi_width <= (*gfx.VI_WIDTH_REG) / 2) && (rdp.vi_width > rdp.vi_height)) rdp.scale_y *= 0.5f; rdp.scissor_o.ul_x = 0; rdp.scissor_o.ul_y = 0; rdp.scissor_o.lr_x = (uint32_t)rdp.vi_width; rdp.scissor_o.lr_y = (uint32_t)rdp.vi_height; rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR; } void ChangeSize() { if (debugging) { _ChangeSize(); return; } switch (g_settings->aspectmode) { case 0: //4:3 if (g_settings->scr_res_x >= g_settings->scr_res_y * 4.0f / 3.0f) { g_settings->res_y = g_settings->scr_res_y; g_settings->res_x = (uint32_t)(g_settings->res_y * 4.0f / 3.0f); } else { g_settings->res_x = g_settings->scr_res_x; g_settings->res_y = (uint32_t)(g_settings->res_x / 4.0f * 3.0f); } break; case 1: //16:9 if (g_settings->scr_res_x >= g_settings->scr_res_y * 16.0f / 9.0f) { g_settings->res_y = g_settings->scr_res_y; g_settings->res_x = (uint32_t)(g_settings->res_y * 16.0f / 9.0f); } else { g_settings->res_x = g_settings->scr_res_x; g_settings->res_y = (uint32_t)(g_settings->res_x / 16.0f * 9.0f); } break; default: //stretch or original g_settings->res_x = g_settings->scr_res_x; g_settings->res_y = g_settings->scr_res_y; } _ChangeSize(); rdp.offset_x = (g_settings->scr_res_x - g_settings->res_x) / 2.0f; float offset_y = (g_settings->scr_res_y - g_settings->res_y) / 2.0f; g_settings->res_x += (uint32_t)rdp.offset_x; g_settings->res_y += (uint32_t)offset_y; rdp.offset_y += offset_y; if (g_settings->aspectmode == 3) // original { rdp.scale_x = rdp.scale_y = 1.0f; rdp.offset_x = (g_settings->scr_res_x - rdp.vi_width) / 2.0f; rdp.offset_y = (g_settings->scr_res_y - rdp.vi_height) / 2.0f; } // g_settings->res_x = g_settings->scr_res_x; // g_settings->res_y = g_settings->scr_res_y; } void ConfigWrapper() { grConfigWrapperExt( #ifdef ANDROID g_settings->wrpVRAM * 1024 * 1024, g_settings->wrpFBO, g_settings->wrpAnisotropic #else g_settings->wrpResolution, g_settings->wrpVRAM * 1024 * 1024, g_settings->wrpFBO, g_settings->wrpAnisotropic #endif ); } void UseUnregisteredSetting(int /*SettingID*/) { #ifdef _WIN32 DebugBreak(); #endif } #ifdef ANDROID extern int g_width, g_height; #endif void ReadSettings() { g_settings->card_id = GetSetting(Set_CardId); #ifdef ANDROID g_settings->scr_res_x = g_settings->res_x = g_width; g_settings->scr_res_y = g_settings->res_y = g_height; #else g_settings->res_data = (uint32_t)GetSetting(Set_Resolution); if (g_settings->res_data >= 24) g_settings->res_data = 12; g_settings->scr_res_x = g_settings->res_x = resolutions[g_settings->res_data][0]; g_settings->scr_res_y = g_settings->res_y = resolutions[g_settings->res_data][1]; g_settings->wrpResolution = GetSetting(Set_wrpResolution); #endif g_settings->vsync = GetSetting(Set_vsync); g_settings->ssformat = (uint8_t)GetSetting(Set_ssformat); g_settings->show_fps = (uint8_t)GetSetting(Set_ShowFps); g_settings->clock = GetSetting(Set_clock); g_settings->clock_24_hr = GetSetting(Set_clock_24_hr); #ifdef ANDROID g_settings->rotate = GetSetting(Set_Rotate); #endif g_settings->advanced_options = Set_basic_mode ? !GetSystemSetting(Set_basic_mode) : 0; g_settings->texenh_options = GetSetting(Set_texenh_options); g_settings->use_hotkeys = GetSetting(Set_hotkeys); g_settings->wrpVRAM = GetSetting(Set_wrpVRAM); g_settings->wrpFBO = GetSetting(Set_wrpFBO); g_settings->wrpAnisotropic = GetSetting(Set_wrpAnisotropic); #ifndef _ENDUSER_RELEASE_ g_settings->autodetect_ucode = GetSetting(Set_autodetect_ucode); g_settings->ucode = GetSetting(Set_ucode); g_settings->wireframe = GetSetting(Set_wireframe); g_settings->wfmode = GetSetting(Set_wfmode); g_settings->logging = GetSetting(Set_logging); g_settings->log_clear = GetSetting(Set_log_clear); g_settings->run_in_window = GetSetting(Set_run_in_window); g_settings->elogging = GetSetting(Set_elogging); g_settings->filter_cache = GetSetting(Set_filter_cache); g_settings->unk_as_red = GetSetting(Set_unk_as_red); g_settings->log_unk = GetSetting(Set_log_unk); g_settings->unk_clear = GetSetting(Set_unk_clear); #else g_settings->autodetect_ucode = TRUE; g_settings->ucode = 2; g_settings->wireframe = FALSE; g_settings->wfmode = 0; g_settings->logging = FALSE; g_settings->log_clear = FALSE; g_settings->run_in_window = FALSE; g_settings->elogging = FALSE; g_settings->filter_cache = FALSE; g_settings->unk_as_red = FALSE; g_settings->log_unk = FALSE; g_settings->unk_clear = FALSE; #endif #ifdef TEXTURE_FILTER char texture_dir[260]; memset(texture_dir, 0, sizeof(texture_dir)); GetSystemSettingSz(Set_texture_dir, texture_dir, sizeof(texture_dir)); g_settings->texture_dir = texture_dir; g_settings->ghq_fltr = (uint8_t)GetSetting(Set_ghq_fltr); g_settings->ghq_cmpr = (uint8_t)GetSetting(Set_ghq_cmpr); g_settings->ghq_enht = (uint8_t)GetSetting(Set_ghq_enht); g_settings->ghq_hirs = (uint8_t)GetSetting(Set_ghq_hirs); g_settings->ghq_enht_cmpr = GetSetting(Set_ghq_enht_cmpr); g_settings->ghq_enht_tile = GetSetting(Set_ghq_enht_tile); g_settings->ghq_enht_f16bpp = GetSetting(Set_ghq_enht_f16bpp); g_settings->ghq_enht_gz = GetSetting(Set_ghq_enht_gz); g_settings->ghq_enht_nobg = GetSetting(Set_ghq_enht_nobg); g_settings->ghq_hirs_cmpr = GetSetting(Set_ghq_hirs_cmpr); g_settings->ghq_hirs_tile = GetSetting(Set_ghq_hirs_tile); g_settings->ghq_hirs_f16bpp = GetSetting(Set_ghq_hirs_f16bpp); g_settings->ghq_hirs_gz = GetSetting(Set_ghq_hirs_gz); g_settings->ghq_hirs_altcrc = GetSetting(Set_ghq_hirs_altcrc); g_settings->ghq_cache_save = GetSetting(Set_ghq_cache_save); g_settings->ghq_cache_size = GetSetting(Set_ghq_cache_size); g_settings->ghq_hirs_let_texartists_fly = GetSetting(Set_ghq_hirs_let_texartists_fly); g_settings->ghq_hirs_dump = GetSetting(Set_ghq_hirs_dump); #endif ConfigWrapper(); } void ReadSpecialSettings(const char * name) { g_settings->hacks = 0; //detect games which require special hacks if (strstr(name, (const char *)"ZELDA")) g_settings->hacks |= (hack_Zelda | hack_OoT); else if (strstr(name, (const char *)"MASK")) g_settings->hacks |= hack_Zelda; else if (strstr(name, (const char *)"ROADSTERS TROPHY")) g_settings->hacks |= hack_Zelda; else if (strstr(name, (const char *)"Diddy Kong Racing")) g_settings->hacks |= hack_Diddy; else if (strstr(name, (const char *)"Tonic Trouble")) g_settings->hacks |= hack_Tonic; else if (strstr(name, (const char *)"All") && strstr(name, (const char *)"Star") && strstr(name, (const char *)"Baseball")) g_settings->hacks |= hack_ASB; else if (strstr(name, (const char *)"Beetle") || strstr(name, (const char *)"BEETLE") || strstr(name, (const char *)"HSV")) g_settings->hacks |= hack_BAR; 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")) g_settings->hacks |= hack_ISS64; else if (strstr(name, (const char *)"MARIOKART64")) g_settings->hacks |= hack_MK64; else if (strstr(name, (const char *)"NITRO64")) g_settings->hacks |= hack_WCWnitro; else if (strstr(name, (const char *)"CHOPPER_ATTACK") || strstr(name, (const char *)"WILD CHOPPERS")) g_settings->hacks |= hack_Chopper; else if (strstr(name, (const char *)"Resident Evil II") || strstr(name, (const char *)"BioHazard II")) g_settings->hacks |= hack_RE2; else if (strstr(name, (const char *)"YOSHI STORY")) g_settings->hacks |= hack_Yoshi; else if (strstr(name, (const char *)"F-Zero X") || strstr(name, (const char *)"F-ZERO X")) g_settings->hacks |= hack_Fzero; else if (strstr(name, (const char *)"PAPER MARIO") || strstr(name, (const char *)"MARIO STORY")) g_settings->hacks |= hack_PMario; else if (strstr(name, (const char *)"TOP GEAR RALLY 2")) g_settings->hacks |= hack_TGR2; else if (strstr(name, (const char *)"TOP GEAR RALLY")) g_settings->hacks |= hack_TGR; else if (strstr(name, (const char *)"Top Gear Hyper Bike")) g_settings->hacks |= hack_Hyperbike; else if (strstr(name, (const char *)"Killer Instinct Gold") || strstr(name, (const char *)"KILLER INSTINCT GOLD")) g_settings->hacks |= hack_KI; else if (strstr(name, (const char *)"Knockout Kings 2000")) g_settings->hacks |= hack_Knockout; else if (strstr(name, (const char *)"LEGORacers")) g_settings->hacks |= hack_Lego; else if (strstr(name, (const char *)"OgreBattle64")) g_settings->hacks |= hack_Ogre64; else if (strstr(name, (const char *)"Pilot Wings64")) g_settings->hacks |= hack_Pilotwings; else if (strstr(name, (const char *)"Supercross")) g_settings->hacks |= hack_Supercross; else if (strstr(name, (const char *)"STARCRAFT 64")) g_settings->hacks |= hack_Starcraft; else if (strstr(name, (const char *)"BANJO KAZOOIE 2") || strstr(name, (const char *)"BANJO TOOIE")) g_settings->hacks |= hack_Banjo2; else if (strstr(name, (const char *)"FIFA: RTWC 98") || strstr(name, (const char *)"RoadToWorldCup98")) g_settings->hacks |= hack_Fifa98; else if (strstr(name, (const char *)"Mega Man 64") || strstr(name, (const char *)"RockMan Dash")) g_settings->hacks |= hack_Megaman; else if (strstr(name, (const char *)"MISCHIEF MAKERS") || strstr(name, (const char *)"TROUBLE MAKERS")) g_settings->hacks |= hack_Makers; else if (strstr(name, (const char *)"GOLDENEYE")) g_settings->hacks |= hack_GoldenEye; else if (strstr(name, (const char *)"PUZZLE LEAGUE")) g_settings->hacks |= hack_PPL; g_settings->alt_tex_size = GetSetting(Set_alt_tex_size); g_settings->use_sts1_only = GetSetting(Set_use_sts1_only); g_settings->force_calc_sphere = GetSetting(Set_force_calc_sphere); g_settings->correct_viewport = GetSetting(Set_correct_viewport); g_settings->increase_texrect_edge = GetSetting(Set_increase_texrect_edge); g_settings->decrease_fillrect_edge = GetSetting(Set_decrease_fillrect_edge); g_settings->texture_correction = GetSetting(Set_texture_correction) == 0 ? 0 : 1; g_settings->pal230 = GetSetting(Set_pal230) == 1 ? 1 : 0; g_settings->stipple_mode = GetSetting(Set_stipple_mode); int stipple_pattern = GetSetting(Set_stipple_pattern); g_settings->stipple_pattern = stipple_pattern > 0 ? (uint32_t)stipple_pattern : 0x3E0F83E0; g_settings->force_microcheck = GetSetting(Set_force_microcheck); g_settings->force_quad3d = GetSetting(Set_force_quad3d); g_settings->clip_zmin = GetSetting(Set_clip_zmin); g_settings->clip_zmax = GetSetting(Set_clip_zmax); g_settings->fast_crc = GetSetting(Set_fast_crc); g_settings->adjust_aspect = GetSetting(Set_adjust_aspect); g_settings->zmode_compare_less = GetSetting(Set_zmode_compare_less); g_settings->old_style_adither = GetSetting(Set_old_style_adither); g_settings->n64_z_scale = GetSetting(Set_n64_z_scale); ZLUT_init(); //frame buffer int optimize_texrect = GetSetting(g_romopen ? Set_optimize_texrect : Set_optimize_texrect_default); int ignore_aux_copy = GetSetting(Set_ignore_aux_copy); int hires_buf_clear = GetSetting(Set_hires_buf_clear); int read_alpha = GetSetting(Set_fb_read_alpha); int useless_is_useless = GetSetting(Set_useless_is_useless); int fb_crc_mode = GetSetting(Set_fb_crc_mode); if (optimize_texrect > 0) g_settings->frame_buffer |= fb_optimize_texrect; else if (optimize_texrect == 0) g_settings->frame_buffer &= ~fb_optimize_texrect; if (ignore_aux_copy > 0) g_settings->frame_buffer |= fb_ignore_aux_copy; else if (ignore_aux_copy == 0) g_settings->frame_buffer &= ~fb_ignore_aux_copy; if (hires_buf_clear > 0) g_settings->frame_buffer |= fb_hwfbe_buf_clear; else if (hires_buf_clear == 0) g_settings->frame_buffer &= ~fb_hwfbe_buf_clear; if (read_alpha > 0) g_settings->frame_buffer |= fb_read_alpha; else if (read_alpha == 0) g_settings->frame_buffer &= ~fb_read_alpha; if (useless_is_useless > 0) g_settings->frame_buffer |= fb_useless_is_useless; else g_settings->frame_buffer &= ~fb_useless_is_useless; if (fb_crc_mode >= 0) g_settings->fb_crc_mode = (CSettings::FBCRCMODE)fb_crc_mode; g_settings->filtering = GetSetting(g_romopen ? Set_filtering : Set_filtering_default); g_settings->fog = GetSetting(g_romopen ? Set_fog : Set_fog_default); g_settings->buff_clear = GetSetting(g_romopen ? Set_buff_clear : Set_buff_clear_default); g_settings->swapmode = GetSetting(g_romopen ? Set_swapmode : Set_swapmode_default); g_settings->aspectmode = GetSetting(g_romopen ? Set_aspect : Set_aspect_default); g_settings->lodmode = GetSetting(g_romopen ? Set_lodmode : Set_lodmode_default); #ifdef _WIN32 g_settings->res_data = GetSetting(Set_Resolution); if (g_settings->res_data < 0 || g_settings->res_data >= 0x18) g_settings->res_data = 12; g_settings->scr_res_x = g_settings->res_x = resolutions[g_settings->res_data][0]; g_settings->scr_res_y = g_settings->res_y = resolutions[g_settings->res_data][1]; #endif //frame buffer int smart_read = GetSetting(g_romopen ? Set_fb_smart : Set_fb_smart_default); int hires = GetSetting(g_romopen ? Set_fb_hires : Set_fb_hires_default); int read_always = GetSetting(g_romopen ? Set_fb_read_always : Set_fb_read_always_default); int read_back_to_screen = GetSetting(g_romopen ? Set_read_back_to_screen : Set_read_back_to_screen_default); int cpu_write_hack = GetSetting(g_romopen ? Set_detect_cpu_write : Set_detect_cpu_write_default); int get_fbinfo = GetSetting(g_romopen ? Set_fb_get_info : Set_fb_get_info_default); int depth_render = GetSetting(g_romopen ? Set_fb_render : Set_fb_render_default); if (smart_read > 0) g_settings->frame_buffer |= fb_emulation; else if (smart_read == 0) g_settings->frame_buffer &= ~fb_emulation; if (hires > 0) g_settings->frame_buffer |= fb_hwfbe; else if (hires == 0) g_settings->frame_buffer &= ~fb_hwfbe; if (read_always > 0) g_settings->frame_buffer |= fb_ref; else if (read_always == 0) g_settings->frame_buffer &= ~fb_ref; if (read_back_to_screen == 1) g_settings->frame_buffer |= fb_read_back_to_screen; else if (read_back_to_screen == 2) g_settings->frame_buffer |= fb_read_back_to_screen2; else if (read_back_to_screen == 0) g_settings->frame_buffer &= ~(fb_read_back_to_screen | fb_read_back_to_screen2); if (cpu_write_hack > 0) g_settings->frame_buffer |= fb_cpu_write_hack; else if (cpu_write_hack == 0) g_settings->frame_buffer &= ~fb_cpu_write_hack; if (get_fbinfo > 0) g_settings->frame_buffer |= fb_get_info; else if (get_fbinfo == 0) g_settings->frame_buffer &= ~fb_get_info; if (depth_render > 0) g_settings->frame_buffer |= fb_depth_render; else if (depth_render == 0) g_settings->frame_buffer &= ~fb_depth_render; g_settings->frame_buffer |= fb_motionblur; g_settings->flame_corona = (g_settings->hacks & hack_Zelda) && !fb_depth_render_enabled; } void WriteSettings(void) { SetSetting(Set_CardId, g_settings->card_id); #ifdef _WIN32 SetSetting(Set_Resolution, (int)g_settings->res_data); SetSetting(Set_wrpResolution, g_settings->wrpResolution); #endif SetSetting(Set_ssformat, g_settings->ssformat); SetSetting(Set_vsync, g_settings->vsync); SetSetting(Set_ShowFps, g_settings->show_fps); SetSetting(Set_clock, g_settings->clock); SetSetting(Set_clock_24_hr, g_settings->clock_24_hr); #ifdef ANDROID SetSetting(Set_Rotate, g_settings->rotate); #endif //SetSetting(Set_advanced_options,g_settings->advanced_options); SetSetting(Set_texenh_options, g_settings->texenh_options); SetSetting(Set_wrpVRAM, g_settings->wrpVRAM); SetSetting(Set_wrpFBO, g_settings->wrpFBO); SetSetting(Set_wrpAnisotropic, g_settings->wrpAnisotropic); #ifndef _ENDUSER_RELEASE_ SetSetting(Set_autodetect_ucode, g_settings->autodetect_ucode); SetSetting(Set_ucode, (int)g_settings->ucode); SetSetting(Set_wireframe, g_settings->wireframe); SetSetting(Set_wfmode, g_settings->wfmode); SetSetting(Set_logging, g_settings->logging); SetSetting(Set_log_clear, g_settings->log_clear); SetSetting(Set_run_in_window,g_settings->run_in_window); SetSetting(Set_elogging,g_settings->elogging); SetSetting(Set_filter_cache,g_settings->filter_cache); SetSetting(Set_unk_as_red,g_settings->unk_as_red); SetSetting(Set_log_unk,g_settings->log_unk); SetSetting(Set_unk_clear, g_settings->unk_clear); #endif //_ENDUSER_RELEASE_ #ifdef TEXTURE_FILTER SetSetting(Set_ghq_fltr, g_settings->ghq_fltr); SetSetting(Set_ghq_cmpr, g_settings->ghq_cmpr); SetSetting(Set_ghq_enht, g_settings->ghq_enht); SetSetting(Set_ghq_hirs, g_settings->ghq_hirs); SetSetting(Set_ghq_enht_cmpr, g_settings->ghq_enht_cmpr); SetSetting(Set_ghq_enht_tile, g_settings->ghq_enht_tile); SetSetting(Set_ghq_enht_f16bpp, g_settings->ghq_enht_f16bpp); SetSetting(Set_ghq_enht_gz, g_settings->ghq_enht_gz); SetSetting(Set_ghq_enht_nobg, g_settings->ghq_enht_nobg); SetSetting(Set_ghq_hirs_cmpr, g_settings->ghq_hirs_cmpr); SetSetting(Set_ghq_hirs_tile, g_settings->ghq_hirs_tile); SetSetting(Set_ghq_hirs_f16bpp, g_settings->ghq_hirs_f16bpp); SetSetting(Set_ghq_hirs_gz, g_settings->ghq_hirs_gz); SetSetting(Set_ghq_hirs_altcrc, g_settings->ghq_hirs_altcrc); SetSetting(Set_ghq_cache_save, g_settings->ghq_cache_save); SetSetting(Set_ghq_cache_size, g_settings->ghq_cache_size); SetSetting(Set_ghq_hirs_let_texartists_fly, g_settings->ghq_hirs_let_texartists_fly); SetSetting(Set_ghq_hirs_dump, g_settings->ghq_hirs_dump); #endif SetSetting(g_romopen ? Set_filtering : Set_filtering_default, g_settings->filtering); SetSetting(g_romopen ? Set_fog : Set_fog_default, g_settings->fog); SetSetting(g_romopen ? Set_buff_clear : Set_buff_clear_default, g_settings->buff_clear); SetSetting(g_romopen ? Set_swapmode : Set_swapmode_default, g_settings->swapmode); SetSetting(g_romopen ? Set_lodmode : Set_lodmode_default, g_settings->lodmode); SetSetting(g_romopen ? Set_aspect : Set_aspect_default, g_settings->aspectmode); SetSetting(g_romopen ? Set_fb_read_always : Set_fb_read_always_default, g_settings->frame_buffer&fb_ref ? 1 : 0); SetSetting(g_romopen ? Set_fb_smart : Set_fb_smart_default, g_settings->frame_buffer & fb_emulation ? 1 : 0); SetSetting(g_romopen ? Set_fb_hires : Set_fb_hires_default, g_settings->frame_buffer & fb_hwfbe ? 1 : 0); SetSetting(g_romopen ? Set_fb_get_info : Set_fb_get_info_default, g_settings->frame_buffer & fb_get_info ? 1 : 0); SetSetting(g_romopen ? Set_fb_render : Set_fb_render_default, g_settings->frame_buffer & fb_depth_render ? 1 : 0); SetSetting(g_romopen ? Set_detect_cpu_write : Set_detect_cpu_write_default, g_settings->frame_buffer & fb_cpu_write_hack ? 1 : 0); if (g_settings->frame_buffer & fb_read_back_to_screen) { SetSetting(g_romopen ? Set_read_back_to_screen : Set_read_back_to_screen_default, 1); } else if (g_settings->frame_buffer & fb_read_back_to_screen2) { SetSetting(g_romopen ? Set_read_back_to_screen : Set_read_back_to_screen_default, 2); } else { SetSetting(g_romopen ? Set_read_back_to_screen : Set_read_back_to_screen_default, 0); } FlushSettings(); } GRSTIPPLE grStippleModeExt = NULL; GRSTIPPLE grStipplePatternExt = NULL; FxBool(FX_CALL *grKeyPressed)(FxU32) = NULL; int GetTexAddrUMA(int /*tmu*/, int texsize) { int addr = voodoo.tex_min_addr[0] + voodoo.tmem_ptr[0]; voodoo.tmem_ptr[0] += texsize; voodoo.tmem_ptr[1] = voodoo.tmem_ptr[0]; return addr; } int GetTexAddrNonUMA(int tmu, int texsize) { int addr = voodoo.tex_min_addr[tmu] + voodoo.tmem_ptr[tmu]; voodoo.tmem_ptr[tmu] += texsize; return addr; } GETTEXADDR GetTexAddr = GetTexAddrNonUMA; // guLoadTextures - used to load the cursor and font textures void guLoadTextures() { int tbuf_size = 0; if (voodoo.max_tex_size <= 256) { grTextureBufferExt(GR_TMU1, voodoo.tex_min_addr[GR_TMU1], GR_LOD_LOG2_256, GR_LOD_LOG2_256, GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH); tbuf_size = 8 * grTexCalcMemRequired(GR_LOD_LOG2_256, GR_LOD_LOG2_256, GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565); } else if (g_settings->scr_res_x <= 1024) { grTextureBufferExt(GR_TMU0, voodoo.tex_min_addr[GR_TMU0], GR_LOD_LOG2_1024, GR_LOD_LOG2_1024, GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH); tbuf_size = grTexCalcMemRequired(GR_LOD_LOG2_1024, GR_LOD_LOG2_1024, GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565); grRenderBuffer(GR_BUFFER_TEXTUREBUFFER_EXT); grBufferClear(0, 0, 0xFFFF); grRenderBuffer(GR_BUFFER_BACKBUFFER); } else { grTextureBufferExt(GR_TMU0, voodoo.tex_min_addr[GR_TMU0], GR_LOD_LOG2_2048, GR_LOD_LOG2_2048, GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH); tbuf_size = grTexCalcMemRequired(GR_LOD_LOG2_2048, GR_LOD_LOG2_2048, GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565); grRenderBuffer(GR_BUFFER_TEXTUREBUFFER_EXT); grBufferClear(0, 0, 0xFFFF); grRenderBuffer(GR_BUFFER_BACKBUFFER); } rdp.texbufs[0].tmu = GR_TMU0; rdp.texbufs[0].begin = voodoo.tex_min_addr[GR_TMU0]; rdp.texbufs[0].end = rdp.texbufs[0].begin + tbuf_size; rdp.texbufs[0].count = 0; rdp.texbufs[0].clear_allowed = TRUE; offset_font = tbuf_size; if (voodoo.num_tmu > 1) { rdp.texbufs[1].tmu = GR_TMU1; rdp.texbufs[1].begin = voodoo.tex_UMA ? rdp.texbufs[0].end : voodoo.tex_min_addr[GR_TMU1]; rdp.texbufs[1].end = rdp.texbufs[1].begin + tbuf_size; rdp.texbufs[1].count = 0; rdp.texbufs[1].clear_allowed = TRUE; if (voodoo.tex_UMA) offset_font += tbuf_size; else offset_texbuf1 = tbuf_size; } #include "font.h" uint32_t *data = (uint32_t*)font; uint32_t cur; // ** Font texture ** uint8_t *tex8 = (uint8_t*)malloc(256 * 64); fontTex.smallLodLog2 = fontTex.largeLodLog2 = GR_LOD_LOG2_256; fontTex.aspectRatioLog2 = GR_ASPECT_LOG2_4x1; fontTex.format = GR_TEXFMT_ALPHA_8; fontTex.data = tex8; // Decompression: [1-bit inverse alpha --> 8-bit alpha] uint32_t i, b; for (i = 0; i < 0x200; i++) { // cur = ~*(data++), byteswapped #ifdef __VISUALC__ cur = _byteswap_ulong(~*(data++)); #else cur = ~*(data++); cur = ((cur & 0xFF) << 24) | (((cur >> 8) & 0xFF) << 16) | (((cur >> 16) & 0xFF) << 8) | ((cur >> 24) & 0xFF); #endif for (b = 0x80000000; b != 0; b >>= 1) { if (cur&b) *tex8 = 0xFF; else *tex8 = 0x00; tex8++; } } grTexDownloadMipMap(GR_TMU0, voodoo.tex_min_addr[GR_TMU0] + offset_font, GR_MIPMAPLEVELMASK_BOTH, &fontTex); offset_cursor = offset_font + grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &fontTex); free(fontTex.data); // ** Cursor texture ** #include "cursor.h" data = (uint32_t*)cursor; uint16_t *tex16 = (uint16_t*)malloc(32 * 32 * 2); cursorTex.smallLodLog2 = cursorTex.largeLodLog2 = GR_LOD_LOG2_32; cursorTex.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; cursorTex.format = GR_TEXFMT_ARGB_1555; cursorTex.data = tex16; // Conversion: [16-bit 1555 (swapped) --> 16-bit 1555] for (i = 0; i < 0x200; i++) { cur = *(data++); *(tex16++) = (uint16_t)(((cur & 0x000000FF) << 8) | ((cur & 0x0000FF00) >> 8)); *(tex16++) = (uint16_t)(((cur & 0x00FF0000) >> 8) | ((cur & 0xFF000000) >> 24)); } grTexDownloadMipMap(GR_TMU0, voodoo.tex_min_addr[GR_TMU0] + offset_cursor, GR_MIPMAPLEVELMASK_BOTH, &cursorTex); // Round to higher 16 offset_textures = ((offset_cursor + grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &cursorTex)) & 0xFFFFFFF0) + 16; free(cursorTex.data); } #ifdef TEXTURE_FILTER void DisplayLoadProgress(const wchar_t *format, ...) { va_list args; wchar_t wbuf[INFO_BUF]; char buf[INFO_BUF]; // process input va_start(args, format); vswprintf(wbuf, INFO_BUF, format, args); va_end(args); // XXX: convert to multibyte wcstombs(buf, wbuf, INFO_BUF); float x; set_message_combiner(); output(382, 380, 1, "LOADING TEXTURES. PLEASE WAIT..."); int len = minval((int)strlen(buf) * 8, 1024); x = (1024 - len) / 2.0f; output(x, 360, 1, buf); grBufferSwap(0); grColorMask(FXTRUE, FXTRUE); grBufferClear(0, 0, 0xFFFF); } #endif int InitGfx() { if (GfxInitDone) { ReleaseGfx(); } WriteTrace(TraceGlide64, TraceDebug, "-"); debugging = FALSE; rdp_reset(); // Initialize Glide grGlideInit(); // Select the Glide device grSstSelect(g_settings->card_id); // Is mirroring allowed? const char *extensions = grGetString(GR_EXTENSION); // Check which SST we are using and initialize stuff // Hiroshi Morii enum { GR_SSTTYPE_VOODOO = 0, GR_SSTTYPE_SST96 = 1, GR_SSTTYPE_AT3D = 2, GR_SSTTYPE_Voodoo2 = 3, GR_SSTTYPE_Banshee = 4, GR_SSTTYPE_Voodoo3 = 5, GR_SSTTYPE_Voodoo4 = 6, GR_SSTTYPE_Voodoo5 = 7 }; const char *hardware = grGetString(GR_HARDWARE); unsigned int SST_type = GR_SSTTYPE_VOODOO; if (strstr(hardware, "Rush")) { SST_type = GR_SSTTYPE_SST96; } else if (strstr(hardware, "Voodoo2")) { SST_type = GR_SSTTYPE_Voodoo2; } else if (strstr(hardware, "Voodoo Banshee")) { SST_type = GR_SSTTYPE_Banshee; } else if (strstr(hardware, "Voodoo3")) { SST_type = GR_SSTTYPE_Voodoo3; } else if (strstr(hardware, "Voodoo4")) { SST_type = GR_SSTTYPE_Voodoo4; } else if (strstr(hardware, "Voodoo5")) { SST_type = GR_SSTTYPE_Voodoo5; } // 2Mb Texture boundary voodoo.has_2mb_tex_boundary = (SST_type < GR_SSTTYPE_Banshee) && !evoodoo; // use UMA if available voodoo.tex_UMA = FALSE; //* if (strstr(extensions, " TEXUMA ")) { // we get better texture cache hits with UMA on grEnable(GR_TEXTURE_UMA_EXT); voodoo.tex_UMA = TRUE; WriteTrace(TraceGlide64, TraceDebug, "Using TEXUMA extension"); } //*/ #ifndef ANDROID uint32_t res_data = g_settings->res_data; if (ev_fullscreen) { uint32_t _width, _height = 0; g_settings->res_data = grWrapperFullScreenResolutionExt((FxU32*)&_width, (FxU32*)&_height); g_settings->scr_res_x = g_settings->res_x = _width; g_settings->scr_res_y = g_settings->res_y = _height; res_data = g_settings->res_data; } else if (evoodoo) { g_settings->res_data = g_settings->res_data_org; g_settings->scr_res_x = g_settings->res_x = resolutions[g_settings->res_data][0]; g_settings->scr_res_y = g_settings->res_y = resolutions[g_settings->res_data][1]; res_data = g_settings->res_data | 0x80000000; } gfx_context = grSstWinOpen(gfx.hWnd, res_data, GR_REFRESH_60Hz, GR_COLORFORMAT_RGBA, GR_ORIGIN_UPPER_LEFT, 2, 1); if (!gfx_context) { #ifdef _WIN32 MessageBox(gfx.hWnd, "Error setting display mode", "Error", MB_OK | MB_ICONEXCLAMATION); #else fprintf(stderr, "Error setting display mode\n"); #endif grGlideShutdown(); return FALSE; } #else gfx_context = grSstWinOpen(GR_REFRESH_60Hz, GR_COLORFORMAT_RGBA, GR_ORIGIN_UPPER_LEFT, 2, 1); g_settings->scr_res_x = g_settings->res_x = g_width; g_settings->scr_res_y = g_settings->res_y = g_height; #endif GfxInitDone = TRUE; to_fullscreen = FALSE; #ifdef __WINDOWS__ if (ev_fullscreen) { if (gfx.hStatusBar) ShowWindow(gfx.hStatusBar, SW_HIDE); ShowCursor(FALSE); } #endif // get the # of TMUs available grGet(GR_NUM_TMU, 4, (FxI32*)&voodoo.num_tmu); // get maximal texture size grGet(GR_MAX_TEXTURE_SIZE, 4, (FxI32*)&voodoo.max_tex_size); voodoo.sup_large_tex = (voodoo.max_tex_size > 256 && !(g_settings->hacks & hack_PPL)); //num_tmu = 1; if (voodoo.tex_UMA) { GetTexAddr = GetTexAddrUMA; voodoo.tex_min_addr[0] = voodoo.tex_min_addr[1] = grTexMinAddress(GR_TMU0); voodoo.tex_max_addr[0] = voodoo.tex_max_addr[1] = grTexMaxAddress(GR_TMU0); } else { GetTexAddr = GetTexAddrNonUMA; voodoo.tex_min_addr[0] = grTexMinAddress(GR_TMU0); voodoo.tex_min_addr[1] = grTexMinAddress(GR_TMU1); voodoo.tex_max_addr[0] = grTexMaxAddress(GR_TMU0); voodoo.tex_max_addr[1] = grTexMaxAddress(GR_TMU1); } if (strstr(extensions, "TEXMIRROR") && !(g_settings->hacks&hack_Zelda)) //zelda's trees suffer from hardware mirroring voodoo.sup_mirroring = 1; else voodoo.sup_mirroring = 0; if (strstr(extensions, "TEXFMT")) //VSA100 texture format extension voodoo.sup_32bit_tex = TRUE; else voodoo.sup_32bit_tex = FALSE; voodoo.gamma_correction = 0; if (strstr(extensions, "GETGAMMA")) grGet(GR_GAMMA_TABLE_ENTRIES, sizeof(voodoo.gamma_table_size), &voodoo.gamma_table_size); grStippleModeExt = (GRSTIPPLE)grStippleMode; grStipplePatternExt = (GRSTIPPLE)grStipplePattern; if (grStipplePatternExt) grStipplePatternExt(g_settings->stipple_pattern); char strKeyPressedExt[] = "grKeyPressedExt"; grKeyPressed = (FxBool(FX_CALL *)(FxU32))grGetProcAddress(strKeyPressedExt); InitCombine(); #ifdef SIMULATE_VOODOO1 voodoo.num_tmu = 1; voodoo.sup_mirroring = 0; #endif #ifdef SIMULATE_BANSHEE voodoo.num_tmu = 1; voodoo.sup_mirroring = 1; #endif grCoordinateSpace(GR_WINDOW_COORDS); grVertexLayout(GR_PARAM_XY, offsetof(VERTEX, x), GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_Q, offsetof(VERTEX, q), GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_Z, offsetof(VERTEX, z), GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_ST0, offsetof(VERTEX, coord[0]), GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_ST1, offsetof(VERTEX, coord[2]), GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_PARGB, offsetof(VERTEX, b), GR_PARAM_ENABLE); grCullMode(GR_CULL_NEGATIVE); if (g_settings->fog) //"FOGCOORD" extension { if (strstr(extensions, "FOGCOORD")) { GrFog_t fog_t[64]; guFogGenerateLinear(fog_t, 0.0f, 255.0f);//(float)rdp.fog_multiplier + (float)rdp.fog_offset);//256.0f); for (int i = 63; i > 0; i--) { if (fog_t[i] - fog_t[i - 1] > 63) { fog_t[i - 1] = fog_t[i] - 63; } } fog_t[0] = 0; // for (int f = 0; f < 64; f++) // { // WriteTrace(TraceRDP, TraceDebug, "fog[%d]=%d->%f", f, fog_t[f], guFogTableIndexToW(f)); // } grFogTable(fog_t); grVertexLayout(GR_PARAM_FOG_EXT, offsetof(VERTEX, f), GR_PARAM_ENABLE); } else //not supported g_settings->fog = FALSE; } grDepthBufferMode(GR_DEPTHBUFFER_ZBUFFER); grDepthBufferFunction(GR_CMP_LESS); grDepthMask(FXTRUE); g_settings->res_x = g_settings->scr_res_x; g_settings->res_y = g_settings->scr_res_y; ChangeSize(); guLoadTextures(); ClearCache(); grCullMode(GR_CULL_DISABLE); grDepthBufferMode(GR_DEPTHBUFFER_ZBUFFER); grDepthBufferFunction(GR_CMP_ALWAYS); grRenderBuffer(GR_BUFFER_BACKBUFFER); grColorMask(FXTRUE, FXTRUE); grDepthMask(FXTRUE); grBufferClear(0, 0, 0xFFFF); grBufferSwap(0); grBufferClear(0, 0, 0xFFFF); grDepthMask(FXFALSE); grTexFilterMode(0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR); grTexFilterMode(1, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR); grTexClampMode(0, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_CLAMP); grTexClampMode(1, GR_TEXTURECLAMP_CLAMP, GR_TEXTURECLAMP_CLAMP); grClipWindow(0, 0, g_settings->scr_res_x, g_settings->scr_res_y); rdp.update |= UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE; #ifdef TEXTURE_FILTER // Hiroshi Morii if (!g_settings->ghq_use) { g_settings->ghq_use = g_settings->ghq_fltr || g_settings->ghq_enht /*|| g_settings->ghq_cmpr*/ || g_settings->ghq_hirs; if (g_settings->ghq_use) { /* Plugin path */ int options = texfltr[g_settings->ghq_fltr] | texenht[g_settings->ghq_enht] | texcmpr[g_settings->ghq_cmpr] | texhirs[g_settings->ghq_hirs]; if (g_settings->ghq_enht_cmpr) options |= COMPRESS_TEX; if (g_settings->ghq_hirs_cmpr) options |= COMPRESS_HIRESTEX; // if (g_settings->ghq_enht_tile) // options |= TILE_TEX; if (g_settings->ghq_hirs_tile) options |= TILE_HIRESTEX; if (g_settings->ghq_enht_f16bpp) options |= FORCE16BPP_TEX; if (g_settings->ghq_hirs_f16bpp) options |= FORCE16BPP_HIRESTEX; if (g_settings->ghq_enht_gz) options |= GZ_TEXCACHE; if (g_settings->ghq_hirs_gz) options |= GZ_HIRESTEXCACHE; if (g_settings->ghq_cache_save) options |= (DUMP_TEXCACHE | DUMP_HIRESTEXCACHE); if (g_settings->ghq_hirs_let_texartists_fly) options |= LET_TEXARTISTS_FLY; if (g_settings->ghq_hirs_dump) options |= DUMP_TEX; ghq_dmptex_toggle_key = 0; g_settings->ghq_use = (int)ext_ghq_init(voodoo.max_tex_size, // max texture width supported by hardware voodoo.max_tex_size, // max texture height supported by hardware voodoo.sup_32bit_tex ? 32 : 16, // max texture bpp supported by hardware options, g_settings->ghq_cache_size * 1024 * 1024, // cache texture to system memory g_settings->texture_dir.c_str(), rdp.RomName, // name of ROM. must be no longer than 256 characters DisplayLoadProgress); } } if (g_settings->ghq_use && strstr(extensions, "TEXMIRROR")) voodoo.sup_mirroring = 1; #endif return TRUE; } void ReleaseGfx() { WriteTrace(TraceGlide64, TraceDebug, "-"); // Restore gamma settings if (voodoo.gamma_correction) { if (voodoo.gamma_table_r) grLoadGammaTable(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b); else guGammaCorrectionRGB(1.3f, 1.3f, 1.3f); //1.3f is default 3dfx gamma for everything but desktop voodoo.gamma_correction = 0; } // Release graphics grSstWinClose(gfx_context); // Shutdown glide grGlideShutdown(); GfxInitDone = FALSE; rdp.window_changed = TRUE; } #ifdef _WIN32 CriticalSection * g_ProcessDListCS = NULL; extern "C" int WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID /*lpReserved*/) { if (fdwReason == DLL_PROCESS_ATTACH) { hinstDLL = hinst; SetupTrace(); if (g_ProcessDListCS == NULL) { g_ProcessDListCS = new CriticalSection(); } ConfigInit(hinst); } else if (fdwReason == DLL_PROCESS_DETACH) { if (g_ProcessDListCS) { delete g_ProcessDListCS; } ConfigCleanup(); } return TRUE; } #endif void CALL ReadScreen(void **dest, int *width, int *height) { *width = g_settings->res_x; *height = g_settings->res_y; uint8_t * buff = (uint8_t*)malloc(g_settings->res_x * g_settings->res_y * 3); uint8_t * line = buff; *dest = (void*)buff; GrLfbInfo_t info; info.size = sizeof(GrLfbInfo_t); if (grLfbLock(GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER, GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) { uint32_t offset_src = info.strideInBytes*(g_settings->scr_res_y - 1); // Copy the screen uint8_t r, g, b; if (info.writeMode == GR_LFBWRITEMODE_8888) { uint32_t col; for (uint32_t y = 0; y < g_settings->res_y; y++) { uint32_t *ptr = (uint32_t*)((uint8_t*)info.lfbPtr + offset_src); for (uint32_t x = 0; x < g_settings->res_x; x++) { col = *(ptr++); r = (uint8_t)((col >> 16) & 0xFF); g = (uint8_t)((col >> 8) & 0xFF); b = (uint8_t)(col & 0xFF); line[x * 3] = b; line[x * 3 + 1] = g; line[x * 3 + 2] = r; } line += g_settings->res_x * 3; offset_src -= info.strideInBytes; } } else { uint16_t col; for (uint32_t y = 0; y < g_settings->res_y; y++) { uint16_t *ptr = (uint16_t*)((uint8_t*)info.lfbPtr + offset_src); for (uint32_t x = 0; x < g_settings->res_x; x++) { col = *(ptr++); r = (uint8_t)((float)(col >> 11) / 31.0f * 255.0f); g = (uint8_t)((float)((col >> 5) & 0x3F) / 63.0f * 255.0f); b = (uint8_t)((float)(col & 0x1F) / 31.0f * 255.0f); line[x * 3] = b; line[x * 3 + 1] = g; line[x * 3 + 2] = r; } line += g_settings->res_x * 3; offset_src -= info.strideInBytes; } } // Unlock the frontbuffer grLfbUnlock(GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER); } WriteTrace(TraceGlide64, TraceDebug, "Success"); } /****************************************************************** Function: CaptureScreen Purpose: This function dumps the current frame to a file input: pointer to the directory to save the file to output: none *******************************************************************/ EXPORT void CALL CaptureScreen(char * Directory) { capture_screen = 1; capture_path = Directory; } /****************************************************************** Function: ChangeWindow Purpose: to change the window between fullscreen and window mode. If the window was in fullscreen this should change the screen to window mode and vice vesa. input: none output: none *******************************************************************/ EXPORT void CALL ChangeWindow(void) { WriteTrace(TraceGlide64, TraceDebug, "-"); if (evoodoo) { if (!ev_fullscreen) { to_fullscreen = TRUE; ev_fullscreen = TRUE; #ifdef __WINDOWS__ if (gfx.hStatusBar) ShowWindow(gfx.hStatusBar, SW_HIDE); ShowCursor(FALSE); #endif } else { ev_fullscreen = FALSE; InitGfx(); #ifdef __WINDOWS__ ShowCursor(TRUE); if (gfx.hStatusBar) { ShowWindow(gfx.hStatusBar, SW_SHOW); } SetWindowLongPtr(gfx.hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); #endif } } else { // Go to fullscreen at next dlist // This is for compatibility with 1964, which reloads the plugin // when switching to fullscreen if (!GfxInitDone) { to_fullscreen = TRUE; #ifdef __WINDOWS__ if (gfx.hStatusBar) ShowWindow(gfx.hStatusBar, SW_HIDE); ShowCursor(FALSE); #endif } else { ReleaseGfx(); #ifdef __WINDOWS__ ShowCursor(TRUE); if (gfx.hStatusBar) ShowWindow(gfx.hStatusBar, SW_SHOW); // SetWindowLong fixes the following Windows XP Banshee issues: // 1964 crash error when loading another rom. // All N64 emu's minimize, restore crashes. SetWindowLongPtr(gfx.hWnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc); #endif } } } /****************************************************************** Function: CloseDLL Purpose: This function is called when the emulator is closing down allowing the dll to de-initialise. input: none output: none *******************************************************************/ void CALL CloseDLL(void) { WriteTrace(TraceGlide64, TraceDebug, "-"); #ifdef ALTTAB_FIX if (hhkLowLevelKybd) { UnhookWindowsHookEx(hhkLowLevelKybd); hhkLowLevelKybd = 0; } #endif //CLOSELOG (); #ifdef TEXTURE_FILTER // Hiroshi Morii if (g_settings->ghq_use) { ext_ghq_shutdown(); g_settings->ghq_use = 0; } #endif if (g_settings) { delete g_settings; g_settings = NULL; } ReleaseGfx(); ZLUT_release(); ClearCache(); delete[] voodoo.gamma_table_r; voodoo.gamma_table_r = 0; delete[] voodoo.gamma_table_g; voodoo.gamma_table_g = 0; delete[] voodoo.gamma_table_b; voodoo.gamma_table_b = 0; } /****************************************************************** Function: DllTest Purpose: This function is optional function that is provided to allow the user to test the dll input: a handle to the window that calls this function output: none *******************************************************************/ void CALL DllTest(HWND /*hParent*/) { } /****************************************************************** Function: DrawScreen Purpose: This function is called when the emulator receives a WM_PAINT message. This allows the gfx to fit in when it is being used in the desktop. input: none output: none *******************************************************************/ void CALL DrawScreen(void) { WriteTrace(TraceGlide64, TraceDebug, "-"); } /****************************************************************** Function: GetDllInfo Purpose: This function allows the emulator to gather information about the dll by filling in the PluginInfo structure. input: a pointer to a PLUGIN_INFO stucture that needs to be filled by the function. (see def above) output: none *******************************************************************/ void CALL GetDllInfo(PLUGIN_INFO * PluginInfo) { PluginInfo->Version = 0x0104; // Set to 0x0104 PluginInfo->Type = PLUGIN_TYPE_GFX; // Set to PLUGIN_TYPE_GFX #ifdef _DEBUG sprintf(PluginInfo->Name, "Glide64 For PJ64 (Debug): %s", VER_FILE_VERSION_STR); #else sprintf(PluginInfo->Name, "Glide64 For PJ64: %s", VER_FILE_VERSION_STR); #endif // If DLL supports memory these memory options then set them to TRUE or FALSE // if it does not support it PluginInfo->NormalMemory = FALSE; // a normal uint8_t array PluginInfo->MemoryBswaped = TRUE; // a normal uint8_t array where the memory has been pre // bswap on a dword (32 bits) boundry } /****************************************************************** Function: InitiateGFX Purpose: This function is called when the DLL is started to give information from the emulator that the n64 graphics uses. This is not called from the emulation thread. Input: Gfx_Info is passed to this function which is defined above. Output: TRUE on success FALSE on failure to initialise ** note on interrupts **: To generate an interrupt set the appropriate bit in MI_INTR_REG and then call the function CheckInterrupts to tell the emulator that there is a waiting interrupt. *******************************************************************/ int CALL InitiateGFX(GFX_INFO Gfx_Info) { WriteTrace(TraceInterface, TraceDebug, "Start"); voodoo.num_tmu = 2; // Assume scale of 1 for debug purposes rdp.scale_x = 1.0f; rdp.scale_y = 1.0f; g_settings = new CSettings; ReadSettings(); char name[21] = "DEFAULT"; ReadSpecialSettings(name); #ifndef ANDROID g_settings->res_data_org = g_settings->res_data; #endif #ifdef FPS fps_last.SetToNow(); #endif debug_init(); // Initialize debugger gfx = Gfx_Info; util_init(); math_init(); TexCacheInit(); CRC_BuildTable(); CountCombine(); ZLUT_init(); grConfigWrapperExt( #ifdef ANDROID g_settings->wrpVRAM * 1024 * 1024, g_settings->wrpFBO, g_settings->wrpAnisotropic #else g_settings->wrpResolution, g_settings->wrpVRAM * 1024 * 1024, g_settings->wrpFBO, g_settings->wrpAnisotropic #endif ); grGlideInit(); grSstSelect(0); const char *extensions = grGetString(GR_EXTENSION); grGlideShutdown(); if (strstr(extensions, "EVOODOO")) { evoodoo = 1; voodoo.has_2mb_tex_boundary = 0; } else { evoodoo = 0; voodoo.has_2mb_tex_boundary = 1; } return TRUE; } /****************************************************************** Function: MoveScreen Purpose: This function is called in response to the emulator receiving a WM_MOVE passing the xpos and ypos passed from that message. input: xpos - the x-coordinate of the upper-left corner of the client area of the window. ypos - y-coordinate of the upper-left corner of the client area of the window. output: none *******************************************************************/ void CALL MoveScreen(int xpos, int ypos) { xpos = xpos; ypos = ypos; WriteTrace(TraceGlide64, TraceDebug, "xpos: %d ypos: %d", xpos, ypos); rdp.window_changed = TRUE; } #ifdef _WIN32 int GetCurrentResIndex(void); #endif void CALL PluginLoaded(void) { SetModuleName("default"); Set_basic_mode = FindSystemSettingId("Basic Mode"); Set_texture_dir = FindSystemSettingId("Dir:Texture"); Set_log_flush = FindSystemSettingId("Log Auto Flush"); Set_log_dir = FindSystemSettingId("Dir:Log"); SetupTrace(); WriteTrace(TraceInterface, TraceDebug, "Start"); SetModuleName("Glide64"); general_setting(Set_CardId, "card_id", 0); #ifdef _WIN32 general_setting(Set_Resolution, "resolution", 7); general_setting(Set_wrpResolution, "wrpResolution", GetCurrentResIndex()); #endif general_setting(Set_vsync, "vsync", 1); general_setting(Set_ssformat, "ssformat", 1); general_setting(Set_ShowFps, "show_fps", 0); general_setting(Set_clock, "clock", 0); general_setting(Set_clock_24_hr, "clock_24_hr", 0); general_setting(Set_texenh_options, "texenh_options", 0); general_setting(Set_hotkeys, "hotkeys", 1); general_setting(Set_wrpVRAM, "wrpVRAM", 0); #ifndef ANDROID general_setting(Set_wrpFBO, "wrpFBO", 0); #else general_setting(Set_Rotate, "rotate", 0); general_setting(Set_wrpFBO, "wrpFBO", 1); #endif general_setting(Set_wrpAnisotropic, "wrpAnisotropic", 0); general_setting(Set_autodetect_ucode, "autodetect_ucode", 1); general_setting(Set_ucode, "ucode", 2); general_setting(Set_wireframe, "wireframe", 0); general_setting(Set_wfmode, "wfmode", 1); general_setting(Set_logging, "logging", 0); general_setting(Set_log_clear, "log_clear", 0); general_setting(Set_run_in_window, "run_in_window", 0); general_setting(Set_elogging, "elogging", 0); general_setting(Set_filter_cache, "filter_cache", 0); general_setting(Set_unk_as_red, "unk_as_red", 0); general_setting(Set_log_unk, "log_unk", 0); general_setting(Set_unk_clear, "unk_clear", 0); general_setting(Set_ghq_fltr, "ghq_fltr", 0); general_setting(Set_ghq_cmpr, "ghq_cmpr", 0); general_setting(Set_ghq_enht, "ghq_enht", 0); general_setting(Set_ghq_hirs, "ghq_hirs", 0); general_setting(Set_ghq_enht_cmpr, "ghq_enht_cmpr", 0); general_setting(Set_ghq_enht_tile, "ghq_enht_tile", 0); general_setting(Set_ghq_enht_f16bpp, "ghq_enht_f16bpp", 0); general_setting(Set_ghq_enht_gz, "ghq_enht_gz", 1); general_setting(Set_ghq_enht_nobg, "ghq_enht_nobg", 0); general_setting(Set_ghq_hirs_cmpr, "ghq_hirs_cmpr", 0); general_setting(Set_ghq_hirs_tile, "ghq_hirs_tile", 0); general_setting(Set_ghq_hirs_f16bpp, "ghq_hirs_f16bpp", 0); general_setting(Set_ghq_hirs_gz, "ghq_hirs_gz", 1); general_setting(Set_ghq_hirs_altcrc, "ghq_hirs_altcrc", 1); general_setting(Set_ghq_cache_save, "ghq_cache_save", 1); general_setting(Set_ghq_cache_size, "ghq_cache_size", 0); general_setting(Set_ghq_hirs_let_texartists_fly, "ghq_hirs_let_texartists_fly", 0); general_setting(Set_ghq_hirs_dump, "ghq_hirs_dump", 0); general_setting(Set_optimize_texrect_default, "optimize_texrect", 1); general_setting(Set_filtering_default, "filtering", 0); general_setting(Set_lodmode_default, "lodmode", 0); general_setting(Set_fog_default, "fog", 1); general_setting(Set_buff_clear_default, "buff_clear", 1); general_setting(Set_swapmode_default, "swapmode", 1); general_setting(Set_aspect_default, "aspect", 0); general_setting(Set_fb_smart_default, "fb_smart", 1); general_setting(Set_fb_hires_default, "fb_hires", 1); general_setting(Set_fb_read_always_default, "fb_read_always", 0); general_setting(Set_read_back_to_screen_default, "read_back_to_screen", 0); general_setting(Set_detect_cpu_write_default, "detect_cpu_write", 0); general_setting(Set_fb_get_info_default, "fb_get_info", 0); general_setting(Set_fb_render_default, "fb_render", 0); game_setting(Set_alt_tex_size, "alt_tex_size", 0); game_setting(Set_use_sts1_only, "use_sts1_only", 0); game_setting(Set_force_calc_sphere, "force_calc_sphere", 0); game_setting(Set_correct_viewport, "correct_viewport", 0); game_setting(Set_increase_texrect_edge, "increase_texrect_edge", 0); game_setting(Set_decrease_fillrect_edge, "decrease_fillrect_edge", 0); game_setting(Set_texture_correction, "texture_correction", 1); game_setting(Set_pal230, "pal230", 0); game_setting(Set_stipple_mode, "stipple_mode", 2); game_setting(Set_stipple_pattern, "stipple_pattern", 0x3E0F83E0); game_setting(Set_force_microcheck, "force_microcheck", 0); game_setting(Set_force_quad3d, "force_quad3d", 0); game_setting(Set_clip_zmin, "clip_zmin", 0); game_setting(Set_clip_zmax, "clip_zmax", 1); game_setting(Set_fast_crc, "fast_crc", 1); game_setting(Set_adjust_aspect, "adjust_aspect", 1); game_setting(Set_zmode_compare_less, "zmode_compare_less", 0); game_setting(Set_old_style_adither, "old_style_adither", 0); game_setting(Set_n64_z_scale, "n64_z_scale", 0); game_setting_default(Set_optimize_texrect, "optimize_texrect", Set_optimize_texrect_default); game_setting(Set_ignore_aux_copy, "ignore_aux_copy", (unsigned int)-1); game_setting(Set_hires_buf_clear, "hires_buf_clear", 1); game_setting(Set_fb_read_alpha, "fb_read_alpha", 0); game_setting(Set_useless_is_useless, "useless_is_useless", (unsigned int)-1); game_setting(Set_fb_crc_mode, "fb_crc_mode", 1); game_setting_default(Set_filtering, "filtering", Set_filtering_default); game_setting_default(Set_fog, "fog", Set_fog_default); game_setting_default(Set_buff_clear, "buff_clear", Set_buff_clear_default); game_setting_default(Set_swapmode, "swapmode", Set_swapmode_default); game_setting_default(Set_aspect, "aspect", Set_aspect_default); game_setting_default(Set_lodmode, "lodmode", Set_lodmode_default); game_setting_default(Set_fb_smart, "fb_smart", Set_fb_smart_default); game_setting_default(Set_fb_hires, "fb_hires", Set_fb_hires_default); game_setting_default(Set_fb_read_always, "fb_read_always", Set_fb_read_always_default); game_setting_default(Set_read_back_to_screen, "read_back_to_screen", Set_read_back_to_screen_default); game_setting_default(Set_detect_cpu_write, "detect_cpu_write", Set_detect_cpu_write_default); game_setting_default(Set_fb_get_info, "fb_get_info", Set_fb_get_info_default); game_setting_default(Set_fb_render, "fb_render", Set_fb_render_default); WriteTrace(TraceInterface, TraceDebug, "Done"); } #ifdef ANDROID void vbo_disable(void); #endif /****************************************************************** Function: RomClosed Purpose: This function is called when a rom is closed. input: none output: none *******************************************************************/ void CALL RomClosed(void) { WriteTrace(TraceGlide64, TraceDebug, "-"); #ifdef ANDROID vbo_disable(); #endif rdp.window_changed = TRUE; g_romopen = FALSE; if (evoodoo) { ReleaseGfx(); } } static void CheckDRAMSize() { uint32_t test; GLIDE64_TRY { test = gfx.RDRAM[0x007FFFFF] + 1; } GLIDE64_CATCH { test = 0; } if (test) BMASK = 0x7FFFFF; else BMASK = WMASK; #ifdef LOGGING sprintf(out_buf, "Detected RDRAM size: %08lx", BMASK); LOG(out_buf); #endif } /****************************************************************** Function: RomOpen Purpose: This function is called when a rom is open. (from the emulation thread) input: none output: none *******************************************************************/ void CALL RomOpen(void) { WriteTrace(TraceGlide64, TraceDebug, "-"); no_dlist = true; g_romopen = TRUE; ucode_error_report = TRUE; // allowed to report ucode errors rdp_reset(); // Get the country code & translate to NTSC(0) or PAL(1) uint16_t code = ((uint16_t*)gfx.HEADER)[0x1F ^ 1]; if (code == 0x4400) region = 1; // Germany (PAL) if (code == 0x4500) region = 0; // USA (NTSC) if (code == 0x4A00) region = 0; // Japan (NTSC) if (code == 0x5000) region = 1; // Europe (PAL) if (code == 0x5500) region = 0; // Australia (NTSC) // get the name of the ROM char name[21]; for (int i = 0; i < 20; i++) { char ch; const char invalid_ch = '?'; /* Some Japanese games use wide chars. */ ch = (char)gfx.HEADER[(32 + i) ^ 3]; if (ch == '\0') ch = ' '; if (ch < ' ') ch = invalid_ch; if (ch > '~') ch = invalid_ch; name[i] = ch; } name[20] = '\0'; // remove all trailing spaces while (name[strlen(name) - 1] == ' ') { name[strlen(name) - 1] = 0; } if (g_settings->ghq_use && strcmp(rdp.RomName, name) != 0) { ext_ghq_shutdown(); g_settings->ghq_use = 0; } strcpy(rdp.RomName, name); ReadSpecialSettings(name); ClearCache(); CheckDRAMSize(); // ** EVOODOO EXTENSIONS ** if (!GfxInitDone) { grGlideInit(); grSstSelect(0); } const char *extensions = grGetString(GR_EXTENSION); grGlideShutdown(); if (strstr(extensions, "EVOODOO")) evoodoo = 1; else evoodoo = 0; if (evoodoo) InitGfx(); if (strstr(extensions, "ROMNAME")) { char strSetRomName[] = "grSetRomName"; void (FX_CALL *grSetRomName)(char*); grSetRomName = (void (FX_CALL *)(char*))grGetProcAddress(strSetRomName); grSetRomName(name); } // ** } /****************************************************************** Function: ShowCFB Purpose: Useally once Dlists are started being displayed, cfb is ignored. This function tells the dll to start displaying them again. input: none output: none *******************************************************************/ bool no_dlist = true; void CALL ShowCFB(void) { WriteTrace(TraceGlide64, TraceDebug, "-"); no_dlist = true; } void drawViRegBG() { WriteTrace(TraceGlide64, TraceDebug, "start"); const uint32_t VIwidth = *gfx.VI_WIDTH_REG; FB_TO_SCREEN_INFO fb_info; fb_info.width = VIwidth; fb_info.height = (uint32_t)rdp.vi_height; if (fb_info.height == 0) { WriteTrace(TraceRDP, TraceDebug, "Image height = 0 - skipping"); return; } fb_info.ul_x = 0; fb_info.lr_x = VIwidth - 1; // fb_info.lr_x = (uint32_t)rdp.vi_width - 1; fb_info.ul_y = 0; fb_info.lr_y = fb_info.height - 1; fb_info.opaque = 1; fb_info.addr = *gfx.VI_ORIGIN_REG; fb_info.size = *gfx.VI_STATUS_REG & 3; rdp.last_bg = fb_info.addr; bool drawn = DrawFrameBufferToScreen(fb_info); if (g_settings->hacks&hack_Lego && drawn) { rdp.updatescreen = 1; newSwapBuffers(); DrawFrameBufferToScreen(fb_info); } WriteTrace(TraceGlide64, TraceDebug, "done"); } static void DrawFrameBuffer() { if (to_fullscreen) GoToFullScreen(); grDepthMask(FXTRUE); grColorMask(FXTRUE, FXTRUE); grBufferClear(0, 0, 0xFFFF); drawViRegBG(); } /****************************************************************** Function: UpdateScreen Purpose: This function is called in response to a vsync of the screen were the VI bit in MI_INTR_REG has already been set input: none output: none *******************************************************************/ uint32_t update_screen_count = 0; void CALL UpdateScreen(void) { WriteTrace(TraceGlide64, TraceDebug, "Origin: %08x, Old origin: %08x, width: %d", *gfx.VI_ORIGIN_REG, rdp.vi_org_reg, *gfx.VI_WIDTH_REG); uint32_t width = (*gfx.VI_WIDTH_REG) << 1; if (*gfx.VI_ORIGIN_REG > width) { update_screen_count++; } #ifdef FPS // vertical interrupt has occurred, increment counter vi_count++; // Check frames per second fps_next.SetToNow(); double diff_secs = (double)(fps_next.GetMicroSeconds() - fps_last.GetMicroSeconds()) / 1000000; if (diff_secs > 0.5f) { fps = (float)(fps_count / diff_secs); vi = (float)(vi_count / diff_secs); ntsc_percent = vi / 0.6f; pal_percent = vi / 0.5f; fps_last = fps_next; fps_count = 0; vi_count = 0; } #endif //* uint32_t limit = (g_settings->hacks&hack_Lego) ? 15 : 30; if ((g_settings->frame_buffer&fb_cpu_write_hack) && (update_screen_count > limit) && (rdp.last_bg == 0)) { WriteTrace(TraceRDP, TraceDebug, "DirectCPUWrite hack!"); update_screen_count = 0; no_dlist = true; ClearCache(); UpdateScreen(); return; } //*/ //* if (no_dlist) { if (*gfx.VI_ORIGIN_REG > width) { ChangeSize(); WriteTrace(TraceRDP, TraceDebug, "ChangeSize done"); DrawFrameBuffer(); WriteTrace(TraceRDP, TraceDebug, "DrawFrameBuffer done"); rdp.updatescreen = 1; newSwapBuffers(); } return; } //*/ if (g_settings->swapmode == 0) newSwapBuffers(); } static void DrawWholeFrameBufferToScreen() { static uint32_t toScreenCI = 0; if (rdp.ci_width < 200) return; if (rdp.cimg == toScreenCI) return; toScreenCI = rdp.cimg; FB_TO_SCREEN_INFO fb_info; fb_info.addr = rdp.cimg; fb_info.size = rdp.ci_size; fb_info.width = rdp.ci_width; fb_info.height = rdp.ci_height; if (fb_info.height == 0) return; fb_info.ul_x = 0; fb_info.lr_x = rdp.ci_width - 1; fb_info.ul_y = 0; fb_info.lr_y = rdp.ci_height - 1; fb_info.opaque = 0; DrawFrameBufferToScreen(fb_info); if (!(g_settings->frame_buffer & fb_ref)) memset(gfx.RDRAM + rdp.cimg, 0, (rdp.ci_width*rdp.ci_height) << rdp.ci_size >> 1); } static void GetGammaTable() { char strGetGammaTableExt[] = "grGetGammaTableExt"; void (FX_CALL *grGetGammaTableExt)(FxU32, FxU32*, FxU32*, FxU32*) = (void (FX_CALL *)(FxU32, FxU32*, FxU32*, FxU32*))grGetProcAddress(strGetGammaTableExt); if (grGetGammaTableExt) { voodoo.gamma_table_r = new FxU32[voodoo.gamma_table_size]; voodoo.gamma_table_g = new FxU32[voodoo.gamma_table_size]; voodoo.gamma_table_b = new FxU32[voodoo.gamma_table_size]; grGetGammaTableExt(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b); } } void write_png_file(const char* file_name, int width, int height, uint8_t *buffer) { /* create file */ FILE *fp = fopen(file_name, "wb"); if (!fp) { WriteTrace(TracePNG, TraceError, "File %s could not be opened for writing", file_name); return; } /* initialize stuff */ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { WriteTrace(TracePNG, TraceError, "png_create_write_struct failed"); fclose(fp); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { WriteTrace(TracePNG, TraceError, "png_create_info_struct failed"); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); return; } if (setjmp(png_jmpbuf(png_ptr))) { WriteTrace(TracePNG, TraceError, "Error during init_io"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return; } png_init_io(png_ptr, fp); /* write header */ if (setjmp(png_jmpbuf(png_ptr))) { WriteTrace(TracePNG, TraceError, "Error during writing header"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return; } png_byte bit_depth = 8; png_byte color_type = PNG_COLOR_TYPE_RGB; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); /* write bytes */ if (setjmp(png_jmpbuf(png_ptr))) { WriteTrace(TracePNG, TraceError, "Error during writing bytes"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return; } int pixel_size = 3; int p = 0; png_bytep * row_pointers = (png_bytep*)malloc(sizeof(png_bytep)* height); for (int y = 0; y < height; y++) { row_pointers[y] = (png_byte*)malloc(width*pixel_size); for (int x = 0; x < width; x++) { row_pointers[y][x*pixel_size + 0] = buffer[p++]; row_pointers[y][x*pixel_size + 1] = buffer[p++]; row_pointers[y][x*pixel_size + 2] = buffer[p++]; } } png_write_image(png_ptr, row_pointers); // cleanup heap allocation for (int y = 0; y < height; y++) { free(row_pointers[y]); } free(row_pointers); /* end write */ if (setjmp(png_jmpbuf(png_ptr))) { WriteTrace(TracePNG, TraceError, "Error during end of write"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return; } png_write_end(png_ptr, NULL); fclose(fp); } uint32_t curframe = 0; void newSwapBuffers() { if (!rdp.updatescreen) return; rdp.updatescreen = 0; WriteTrace(TraceRDP, TraceDebug, "swapped"); rdp.update |= UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE; grClipWindow(0, 0, g_settings->scr_res_x, g_settings->scr_res_y); grDepthBufferFunction(GR_CMP_ALWAYS); grDepthMask(FXFALSE); grCullMode(GR_CULL_DISABLE); if ((g_settings->show_fps & 0xF) || g_settings->clock) set_message_combiner(); #ifdef FPS float y = 0;//(float)g_settings->res_y; if (g_settings->show_fps & 0x0F) { if (g_settings->show_fps & 4) { if (region) // PAL output(0, y, 1, "%d%% ", (int)pal_percent); else output(0, y, 1, "%d%% ", (int)ntsc_percent); y += 16; } if (g_settings->show_fps & 2) { output(0, y, 1, "VI/s: %.02f ", vi); y += 16; } if (g_settings->show_fps & 1) output(0, y, 1, "FPS: %.02f ", fps); } #endif if (g_settings->clock) { if (g_settings->clock_24_hr) { output(956.0f, 0, 1, CDateTime().Format("%H:%M:%S").c_str(), 0); } else { output(930.0f, 0, 1, CDateTime().Format("%I:%M:%S %p").c_str(), 0); } } //hotkeys //if (CheckKeyPressed(G64_VK_BACK, 0x0001)) //{ //hotkey_info.hk_filtering = 100; //if (g_settings->filtering < 2) //g_settings->filtering++; //else //g_settings->filtering = 0; //} if ((abs((int)(frame_count - curframe)) > 3) && CheckKeyPressed(G64_VK_ALT, 0x8000)) //alt + { if (CheckKeyPressed(G64_VK_B, 0x8000)) //b { hotkey_info.hk_motionblur = 100; hotkey_info.hk_ref = 0; curframe = frame_count; g_settings->frame_buffer ^= fb_motionblur; } else if (CheckKeyPressed(G64_VK_V, 0x8000)) //v { hotkey_info.hk_ref = 100; hotkey_info.hk_motionblur = 0; curframe = frame_count; g_settings->frame_buffer ^= fb_ref; } } if (g_settings->buff_clear && (hotkey_info.hk_ref || hotkey_info.hk_motionblur || hotkey_info.hk_filtering)) { set_message_combiner(); char buf[256]; buf[0] = 0; char * message = 0; if (hotkey_info.hk_ref) { if (g_settings->frame_buffer & fb_ref) message = strcat(buf, "FB READ ALWAYS: ON"); else message = strcat(buf, "FB READ ALWAYS: OFF"); hotkey_info.hk_ref--; } if (hotkey_info.hk_motionblur) { if (g_settings->frame_buffer & fb_motionblur) message = strcat(buf, " MOTION BLUR: ON"); else message = strcat(buf, " MOTION BLUR: OFF"); hotkey_info.hk_motionblur--; } if (hotkey_info.hk_filtering) { switch (g_settings->filtering) { case 0: message = strcat(buf, " FILTERING MODE: AUTOMATIC"); break; case 1: message = strcat(buf, " FILTERING MODE: FORCE BILINEAR"); break; case 2: message = strcat(buf, " FILTERING MODE: FORCE POINT-SAMPLED"); break; } hotkey_info.hk_filtering--; } output(120.0f, 0.0f, 1, message, 0); } if (capture_screen) { CPath path(capture_path); if (!path.DirectoryExists()) { path.DirectoryCreate(); } stdstr romName = rdp.RomName; romName.Replace(" ", "_"); romName.Replace(":", ";"); if (g_settings->ssformat >= NumOfFormats) { g_settings->ssformat = 0; } for (int i = 1;; i++) { stdstr_f filename("Glide64_%s_%s%d.%s", romName.c_str(), i < 10 ? "0" : "", i, ScreenShotFormats[g_settings->ssformat].extension); path.SetNameExtension(filename.c_str()); if (!path.Exists()) { break; } } const uint32_t offset_x = (uint32_t)rdp.offset_x; const uint32_t offset_y = (uint32_t)rdp.offset_y; const uint32_t image_width = g_settings->scr_res_x - offset_x * 2; const uint32_t image_height = g_settings->scr_res_y - offset_y * 2; GrLfbInfo_t info; info.size = sizeof(GrLfbInfo_t); if (grLfbLock(GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) { AUTO_PTR ssimg_buffer(new uint8_t[image_width * image_height * 3]); uint8_t * ssimg = ssimg_buffer.get(); int sspos = 0; uint32_t offset_src = info.strideInBytes * offset_y; // Copy the screen if (info.writeMode == GR_LFBWRITEMODE_8888) { uint32_t col; for (uint32_t y = 0; y < image_height; y++) { uint32_t *ptr = (uint32_t*)((uint8_t*)info.lfbPtr + offset_src); ptr += offset_x; for (uint32_t x = 0; x < image_width; x++) { col = *(ptr++); ssimg[sspos++] = (uint8_t)((col >> 16) & 0xFF); ssimg[sspos++] = (uint8_t)((col >> 8) & 0xFF); ssimg[sspos++] = (uint8_t)(col & 0xFF); } offset_src += info.strideInBytes; } } else { uint16_t col; for (uint32_t y = 0; y < image_height; y++) { uint16_t *ptr = (uint16_t*)((uint8_t*)info.lfbPtr + offset_src); ptr += offset_x; for (uint32_t x = 0; x < image_width; x++) { col = *(ptr++); ssimg[sspos++] = (uint8_t)((float)(col >> 11) / 31.0f * 255.0f); ssimg[sspos++] = (uint8_t)((float)((col >> 5) & 0x3F) / 63.0f * 255.0f); ssimg[sspos++] = (uint8_t)((float)(col & 0x1F) / 31.0f * 255.0f); } offset_src += info.strideInBytes; } } // Unlock the backbuffer grLfbUnlock(GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER); if (ScreenShotFormats[g_settings->ssformat].type == rdpBITMAP_TYPE_PNG) { write_png_file(path, image_width, image_height, ssimg); } capture_screen = 0; } } // Capture the screen if debug capture is set if (_debugger.capture) { // Allocate the screen _debugger.screen = new uint8_t[(g_settings->res_x*g_settings->res_y) << 1]; // Lock the backbuffer (already rendered) GrLfbInfo_t info; info.size = sizeof(GrLfbInfo_t); while (!grLfbLock(GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)); uint32_t offset_src = 0, offset_dst = 0; // Copy the screen for (uint32_t y = 0; y < g_settings->res_y; y++) { if (info.writeMode == GR_LFBWRITEMODE_8888) { uint32_t *src = (uint32_t*)((uint8_t*)info.lfbPtr + offset_src); uint16_t *dst = (uint16_t*)(_debugger.screen + offset_dst); uint8_t r, g, b; uint32_t col; for (unsigned int x = 0; x < g_settings->res_x; x++) { col = src[x]; r = (uint8_t)((col >> 19) & 0x1F); g = (uint8_t)((col >> 10) & 0x3F); b = (uint8_t)((col >> 3) & 0x1F); dst[x] = (r << 11) | (g << 5) | b; } } else { memcpy(_debugger.screen + offset_dst, (uint8_t*)info.lfbPtr + offset_src, g_settings->res_x << 1); } offset_dst += g_settings->res_x << 1; offset_src += info.strideInBytes; } // Unlock the backbuffer grLfbUnlock(GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER); } if (debugging) { debug_keys(); debug_cacheviewer(); debug_mouse(); } if (g_settings->frame_buffer & fb_read_back_to_screen) DrawWholeFrameBufferToScreen(); if (fb_hwfbe_enabled && !(g_settings->hacks&hack_RE2) && !evoodoo) grAuxBufferExt(GR_BUFFER_AUXBUFFER); WriteTrace(TraceGlide64, TraceDebug, "BUFFER SWAPPED"); grBufferSwap(g_settings->vsync); fps_count++; if (*gfx.VI_STATUS_REG & 0x08) //gamma correction is used { if (!voodoo.gamma_correction) { if (voodoo.gamma_table_size && !voodoo.gamma_table_r) GetGammaTable(); //save initial gamma tables guGammaCorrectionRGB(2.0f, 2.0f, 2.0f); //with gamma=2.0 gamma table is the same, as in N64 voodoo.gamma_correction = 1; } } else { if (voodoo.gamma_correction) { if (voodoo.gamma_table_r) grLoadGammaTable(voodoo.gamma_table_size, voodoo.gamma_table_r, voodoo.gamma_table_g, voodoo.gamma_table_b); else guGammaCorrectionRGB(1.3f, 1.3f, 1.3f); //1.3f is default 3dfx gamma for everything but desktop voodoo.gamma_correction = 0; } } if (_debugger.capture) debug_capture(); if (debugging || g_settings->wireframe || g_settings->buff_clear || (g_settings->hacks&hack_PPL && g_settings->ucode == 6)) { if (g_settings->hacks&hack_RE2 && fb_depth_render_enabled) grDepthMask(FXFALSE); else grDepthMask(FXTRUE); grBufferClear(0, 0, 0xFFFF); } /* //let the game to clear the buffers else { grDepthMask (FXTRUE); grColorMask (FXFALSE, FXFALSE); grBufferClear (0, 0, 0xFFFF); grColorMask (FXTRUE, FXTRUE); } */ if (g_settings->frame_buffer & fb_read_back_to_screen2) { DrawWholeFrameBufferToScreen(); } frame_count++; // Open/close debugger? if (CheckKeyPressed(G64_VK_SCROLL, 0x0001)) { if (!debugging) { //if (g_settings->scr_res_x == 1024 && g_settings->scr_res_y == 768) { debugging = 1; // Recalculate screen size, don't resize screen g_settings->res_x = (uint32_t)(g_settings->scr_res_x * 0.625f); g_settings->res_y = (uint32_t)(g_settings->scr_res_y * 0.625f); ChangeSize(); } } else { debugging = 0; g_settings->res_x = g_settings->scr_res_x; g_settings->res_y = g_settings->scr_res_y; ChangeSize(); } } // Debug capture? if (/*fullscreen && */debugging && CheckKeyPressed(G64_VK_INSERT, 0x0001)) { _debugger.capture = 1; } } /****************************************************************** Function: ViStatusChanged Purpose: This function is called to notify the dll that the ViStatus registers value has been changed. input: none output: none *******************************************************************/ void CALL ViStatusChanged(void) { } /****************************************************************** Function: ViWidthChanged Purpose: This function is called to notify the dll that the ViWidth registers value has been changed. input: none output: none *******************************************************************/ void CALL ViWidthChanged(void) { } #ifdef ANDROID /****************************************************************** Function: SurfaceCreated Purpose: this function is called when the surface is created. input: none output: none *******************************************************************/ void CALL SurfaceCreated(void) { } /****************************************************************** Function: SurfaceChanged Purpose: this function is called when the surface is has changed. input: none output: none *******************************************************************/ void init_combiner(); void CALL SurfaceChanged(int width, int height) { g_width = width; g_height = height; } #endif int CheckKeyPressed(int key, int mask) { static Glide64Keys g64Keys; if (g_settings->use_hotkeys == 0) return 0; #ifdef __WINDOWS__ return (GetAsyncKeyState(g64Keys[key]) & mask); #else if (grKeyPressed) return grKeyPressed(g64Keys[key]); return 0; #endif } #ifdef ALTTAB_FIX int k_ctl = 0, k_alt = 0, k_del = 0; LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if (!fullscreen) return CallNextHookEx(NULL, nCode, wParam, lParam); int TabKey = FALSE; PKBDLLHOOKSTRUCT p; if (nCode == HC_ACTION) { switch (wParam) { case WM_KEYUP: case WM_SYSKEYUP: p = (PKBDLLHOOKSTRUCT) lParam; if (p->vkCode == 162) k_ctl = 0; if (p->vkCode == 164) k_alt = 0; if (p->vkCode == 46) k_del = 0; goto do_it; case WM_KEYDOWN: case WM_SYSKEYDOWN: p = (PKBDLLHOOKSTRUCT) lParam; if (p->vkCode == 162) k_ctl = 1; if (p->vkCode == 164) k_alt = 1; if (p->vkCode == 46) k_del = 1; goto do_it; do_it: TabKey = ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) || ((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0)) || ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0)) || (k_ctl && k_alt && k_del); break; } } if (TabKey) { k_ctl = 0; k_alt = 0; k_del = 0; ReleaseGfx (); } return CallNextHookEx(NULL, nCode, wParam, lParam); } #endif #ifdef ANDROID void Android_JNI_SwapWindow() { gfx.SwapBuffers(); } #endif