Added aspect ratio option to RICE GLES1.1
[mupen64plus-pandora.git] / source / rice_gles / src / Config.cpp
1 /*
2 Copyright (C) 2003 Rice1964
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17
18 */
19
20 #include <vector>
21 #include <fstream>
22
23 #include <stdlib.h>
24
25 #define M64P_PLUGIN_PROTOTYPES 1
26 #include "osal_preproc.h"
27 #include "m64p_types.h"
28 #include "m64p_plugin.h"
29 #include "m64p_config.h"
30
31 #include "Config.h"
32 #include "Debugger.h"
33 #include "DeviceBuilder.h"
34 #include "RenderBase.h"
35 #include "TextureManager.h"
36 #include "Video.h"
37
38 #define INI_FILE        "RiceVideoLinux.ini"
39
40 static m64p_handle l_ConfigVideoRice = NULL;
41 static m64p_handle l_ConfigVideoGeneral = NULL;
42
43 static int FindIniEntry(uint32 dwCRC1, uint32 dwCRC2, uint8 nCountryID, char* szName, int PrintInfo); 
44
45 const char *frameBufferSettings[] =
46 {
47 "None (default)",
48 "Hide Framebuffer Effects",
49 "Basic Framebuffer",
50 "Basic & Write Back",
51 "Write Back & Reload",
52 "Write Back Every Frame",
53 "With Emulator",
54 "Basic Framebuffer & With Emulator",
55 "With Emulator Read Only",
56 "With Emulator Write Only",
57 };
58
59 const int resolutions[][2] =
60 {
61 {320, 240},
62 {400, 300},
63 {480, 360},
64 {512, 384},
65 {640, 480},
66 {800, 480},
67 {800, 600},
68 {1024, 768},
69 {1152, 864},
70 {1280, 960},
71 {1400, 1050},
72 {1600, 1200},
73 {1920, 1440},
74 {2048, 1536},
75 };
76 const int numberOfResolutions = sizeof(resolutions)/sizeof(int)/2;
77
78 const char* resolutionsS[] =
79 {
80 "320 x 240",
81 "400 x 300",
82 "480 x 360",
83 "512 x 384",
84 "640 x 480",
85 "800 x 480",
86 "800 x 600",
87 "1024 x 768",
88 "1152 x 864",
89 "1280 x 960",
90 "1400 x 1050",
91 "1600 x 1200",
92 "1920 x 1440",
93 "2048 x 1536"
94 };
95
96 const char *frameBufferWriteBackControlSettings[] =
97 {
98 "Every Frame (default)",
99 "Every 2 Frames",
100 "Every 3 Frames",
101 "Every 4 Frames",
102 "Every 5 Frames",
103 "Every 6 Frames",
104 "Every 7 Frames",
105 "Every 8 Frames",
106 };
107
108 const char *renderToTextureSettings[] =
109 {
110 "None (default)",
111 "Hide Render-to-texture Effects",
112 "Basic Render-to-texture",
113 "Basic & Write Back",
114 "Write Back & Reload",
115 };
116
117 const char *screenUpdateSettings[] =
118 {
119 "At VI origin update",
120 "At VI origin change",
121 "At CI change",
122 "At the 1st CI change",
123 "At the 1st drawing",
124 "Before clear the screen",
125 "At VI origin update after screen is drawn (default)",
126 };
127
128 WindowSettingStruct windowSetting;
129 GlobalOptions options;
130 RomOptions defaultRomOptions;
131 RomOptions currentRomOptions;
132 FrameBufferOptions frameBufferOptions;
133 std::vector<IniSection> IniSections;
134 bool    bIniIsChanged = false;
135 char    szIniFileName[300];
136
137 SettingInfo TextureQualitySettings[] =
138 {
139 {"Default", FORCE_DEFAULT_FILTER},
140 {"32-bit Texture", FORCE_POINT_FILTER},
141 {"16-bit Texture", FORCE_LINEAR_FILTER},
142 };
143
144 SettingInfo ForceTextureFilterSettings[] =
145 {
146 {"N64 Default Texture Filter",  FORCE_DEFAULT_FILTER},
147 {"Force Nearest Filter (faster, low quality)", FORCE_POINT_FILTER},
148 {"Force Linear Filter (slower, better quality)", FORCE_LINEAR_FILTER},
149 };
150
151 SettingInfo TextureEnhancementSettings[] =
152 {
153 {"N64 original texture (No enhancement)", TEXTURE_NO_ENHANCEMENT},
154 {"2x (Double the texture size)", TEXTURE_2X_ENHANCEMENT},
155 {"2xSaI", TEXTURE_2XSAI_ENHANCEMENT},
156 {"hq2x", TEXTURE_HQ2X_ENHANCEMENT},
157 {"lq2x", TEXTURE_LQ2X_ENHANCEMENT},
158 {"hq4x", TEXTURE_HQ4X_ENHANCEMENT},
159 {"Sharpen", TEXTURE_SHARPEN_ENHANCEMENT},
160 {"Sharpen More", TEXTURE_SHARPEN_MORE_ENHANCEMENT},
161 };
162
163 SettingInfo TextureEnhancementControlSettings[] =
164 {
165 {"Normal", TEXTURE_ENHANCEMENT_NORMAL},
166 {"Smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_1},
167 {"Less smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_2},
168 {"2xSaI smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_3},
169 {"Less 2xSaI smooth", TEXTURE_ENHANCEMENT_WITH_SMOOTH_FILTER_4},
170 };
171
172 SettingInfo colorQualitySettings[] =
173 {
174 {"16-bit", TEXTURE_FMT_A4R4G4B4},
175 {"32-bit (def)", TEXTURE_FMT_A8R8G8B8},
176 };
177
178 const char* strDXDeviceDescs[] = { "HAL", "REF" };
179
180 SettingInfo openGLDepthBufferSettings[] =
181 {
182 {"16-bit (def)", 16},
183 {"32-bit", 32},
184 };
185
186 RenderEngineSetting OpenGLRenderSettings[] =
187 {
188 {"To Fit Your Video Card", OGL_DEVICE},
189 {"OpenGL 1.1 (Lowest)",  OGL_1_1_DEVICE},
190 {"OpenGL 1.2/1.3", OGL_1_2_DEVICE},
191 {"OpenGL 1.4", OGL_1_4_DEVICE},
192 {"OpenGL 1.4, the 2nd combiner",  OGL_1_4_V2_DEVICE},
193 {"OpenGL for Nvidia TNT or better", OGL_TNT2_DEVICE},
194 {"OpenGL for Nvidia GeForce or better ", NVIDIA_OGL_DEVICE},
195 {"OpenGL Fragment Program Extension", OGL_FRAGMENT_PROGRAM},
196 };
197
198 SettingInfo OnScreenDisplaySettings[] =
199 {
200 {"Display Nothing", ONSCREEN_DISPLAY_NOTHING},
201 {"Display DList Per Second", ONSCREEN_DISPLAY_DLIST_PER_SECOND},
202 {"Display Frame Per Second", ONSCREEN_DISPLAY_FRAME_PER_SECOND},
203 {"Display Debug Information Only", ONSCREEN_DISPLAY_DEBUG_INFORMATION_ONLY},
204 {"Display Messages From CPU Core Only", ONSCREEN_DISPLAY_TEXT_FROM_CORE_ONLY},
205 {"Display DList Per Second With Core Msgs", ONSCREEN_DISPLAY_DLIST_PER_SECOND_WITH_CORE_MSG},
206 {"Display Frame Per Second With Core Msgs", ONSCREEN_DISPLAY_FRAME_PER_SECOND_WITH_CORE_MSG},
207 {"Display Debug Information With Core Msgs", ONSCREEN_DISPLAY_DEBUG_INFORMATION_WITH_CORE_MSG},
208 };
209
210 const int numberOfOpenGLRenderEngineSettings = sizeof(OpenGLRenderSettings)/sizeof(RenderEngineSetting);
211
212 void GenerateFrameBufferOptions(void)
213 {
214     if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE )
215     {
216         // OpenGL does not support much yet
217         if( currentRomOptions.N64FrameBufferEmuType != FRM_BUF_NONE )
218             currentRomOptions.N64FrameBufferEmuType = FRM_BUF_IGNORE;
219         if( currentRomOptions.N64RenderToTextureEmuType != TXT_BUF_NONE )
220             currentRomOptions.N64RenderToTextureEmuType = TXT_BUF_IGNORE;
221     }
222
223     frameBufferOptions.bUpdateCIInfo            = false;
224
225     frameBufferOptions.bCheckBackBufs           = false;
226     frameBufferOptions.bWriteBackBufToRDRAM     = false;
227     frameBufferOptions.bLoadBackBufFromRDRAM    = false;
228
229     frameBufferOptions.bIgnore                  = true;
230
231     frameBufferOptions.bSupportRenderTextures           = false;
232     frameBufferOptions.bCheckRenderTextures         = false;
233     frameBufferOptions.bRenderTextureWriteBack          = false;
234     frameBufferOptions.bLoadRDRAMIntoRenderTexture      = false;
235
236     frameBufferOptions.bProcessCPUWrite         = false;
237     frameBufferOptions.bProcessCPURead          = false;
238     frameBufferOptions.bAtEachFrameUpdate       = false;
239     frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown      = false;
240
241     switch( currentRomOptions.N64FrameBufferEmuType )
242     {
243     case FRM_BUF_NONE:
244         break;
245     case FRM_BUF_COMPLETE:
246         frameBufferOptions.bAtEachFrameUpdate       = true;
247         frameBufferOptions.bProcessCPUWrite         = true;
248         frameBufferOptions.bProcessCPURead          = true;
249         frameBufferOptions.bUpdateCIInfo            = true;
250         break;
251     case FRM_BUF_WRITEBACK_AND_RELOAD:
252         frameBufferOptions.bLoadBackBufFromRDRAM    = true;
253     case FRM_BUF_BASIC_AND_WRITEBACK:
254         frameBufferOptions.bWriteBackBufToRDRAM     = true;
255     case FRM_BUF_BASIC:
256         frameBufferOptions.bCheckBackBufs           = true;
257     case FRM_BUF_IGNORE:
258         frameBufferOptions.bUpdateCIInfo            = true;
259         break;
260     case FRM_BUF_BASIC_AND_WITH_EMULATOR:
261         // Banjo Kazooie
262         frameBufferOptions.bCheckBackBufs           = true;
263     case FRM_BUF_WITH_EMULATOR:
264         frameBufferOptions.bUpdateCIInfo            = true;
265         frameBufferOptions.bProcessCPUWrite         = true;
266         frameBufferOptions.bProcessCPURead          = true;
267         break;
268     case FRM_BUF_WITH_EMULATOR_READ_ONLY:
269         frameBufferOptions.bUpdateCIInfo            = true;
270         frameBufferOptions.bProcessCPURead          = true;
271         break;
272     case FRM_BUF_WITH_EMULATOR_WRITE_ONLY:
273         frameBufferOptions.bUpdateCIInfo            = true;
274         frameBufferOptions.bProcessCPUWrite         = true;
275         break;
276     }
277
278     switch( currentRomOptions.N64RenderToTextureEmuType )
279     {
280     case TXT_BUF_NONE:
281         frameBufferOptions.bSupportRenderTextures           = false;
282         break;
283     case TXT_BUF_WRITE_BACK_AND_RELOAD:
284         frameBufferOptions.bLoadRDRAMIntoRenderTexture      = true;
285     case TXT_BUF_WRITE_BACK:
286         frameBufferOptions.bRenderTextureWriteBack          = true;
287     case TXT_BUF_NORMAL:
288         frameBufferOptions.bCheckRenderTextures         = true;
289         frameBufferOptions.bIgnore                  = false;
290     case TXT_BUF_IGNORE:
291         frameBufferOptions.bUpdateCIInfo            = true;
292         frameBufferOptions.bSupportRenderTextures           = true;
293         break;
294     }
295
296     if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_CI_CHANGE )
297     {
298         frameBufferOptions.bUpdateCIInfo = true;
299     }
300 }
301
302 BOOL InitConfiguration(void)
303 {
304     if (ConfigOpenSection("Video-General", &l_ConfigVideoGeneral) != M64ERR_SUCCESS)
305     {
306         DebugMessage(M64MSG_ERROR, "Unable to open Video-General configuration section");
307         return FALSE;
308     }
309     if (ConfigOpenSection("Video-Rice", &l_ConfigVideoRice) != M64ERR_SUCCESS)
310     {
311         DebugMessage(M64MSG_ERROR, "Unable to open Video-Rice configuration section");
312         return FALSE;
313     }
314
315     ConfigSetDefaultBool(l_ConfigVideoGeneral, "Fullscreen", 1, "Use fullscreen mode if True, or windowed mode if False ");
316     ConfigSetDefaultInt(l_ConfigVideoGeneral, "ScreenWidth", 640, "Width of output window or fullscreen width");
317     ConfigSetDefaultInt(l_ConfigVideoGeneral, "ScreenHeight", 480, "Height of output window or fullscreen height");
318     ConfigSetDefaultBool(l_ConfigVideoGeneral, "VerticalSync", 0, "If true, activate the SDL_GL_SWAP_CONTROL attribute");
319
320     ConfigSetDefaultInt(l_ConfigVideoRice, "FrameBufferSetting", FRM_BUF_NONE, "Frame Buffer Emulation (0=ROM default, 1=disable)");
321     ConfigSetDefaultInt(l_ConfigVideoRice, "FrameBufferWriteBackControl", FRM_BUF_WRITEBACK_NORMAL, "Frequency to write back the frame buffer (0=every frame, 1=every other frame, etc)");
322     ConfigSetDefaultInt(l_ConfigVideoRice, "RenderToTexture", TXT_BUF_NONE, "Render-to-texture emulation (0=none, 1=ignore, 2=normal, 3=write back, 4=write back and reload)");
323 #if defined(WIN32)
324     ConfigSetDefaultInt(l_ConfigVideoRice, "ScreenUpdateSetting", SCREEN_UPDATE_AT_1ST_CI_CHANGE, "Control when the screen will be updated (0=ROM default, 1=VI origin update, 2=VI origin change, 3=CI change, 4=first CI change, 5=first primitive draw, 6=before screen clear, 7=after screen drawn)");  // SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN
325 #else
326     ConfigSetDefaultInt(l_ConfigVideoRice, "ScreenUpdateSetting", SCREEN_UPDATE_AT_VI_UPDATE, "Control when the screen will be updated (0=ROM default, 1=VI origin update, 2=VI origin change, 3=CI change, 4=first CI change, 5=first primitive draw, 6=before screen clear, 7=after screen drawn)");  // SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN
327 #endif
328     ConfigSetDefaultBool(l_ConfigVideoRice, "NormalAlphaBlender", FALSE, "Force to use normal alpha blender");
329     ConfigSetDefaultBool(l_ConfigVideoRice, "FastTextureLoading", FALSE, "Use a faster algorithm to speed up texture loading and CRC computation");
330     ConfigSetDefaultBool(l_ConfigVideoRice, "AccurateTextureMapping", TRUE, "Use different texture coordinate clamping code");
331     ConfigSetDefaultBool(l_ConfigVideoRice, "InN64Resolution", FALSE, "Force emulated frame buffers to be in N64 native resolution");
332     ConfigSetDefaultBool(l_ConfigVideoRice, "SaveVRAM", FALSE, "Try to reduce Video RAM usage (should never be used)");
333     ConfigSetDefaultBool(l_ConfigVideoRice, "DoubleSizeForSmallTxtrBuf", FALSE, "Enable this option to have better render-to-texture quality");
334     ConfigSetDefaultBool(l_ConfigVideoRice, "DefaultCombinerDisable", FALSE, "Force to use normal color combiner");
335
336     ConfigSetDefaultBool(l_ConfigVideoRice, "EnableHacks", TRUE, "Enable game-specific settings from INI file");
337     ConfigSetDefaultBool(l_ConfigVideoRice, "WinFrameMode", FALSE, "If enabled, graphics will be drawn in WinFrame mode instead of solid and texture mode");
338     ConfigSetDefaultBool(l_ConfigVideoRice, "FullTMEMEmulation", FALSE, "N64 Texture Memory Full Emulation (may fix some games, may break others)");
339     ConfigSetDefaultBool(l_ConfigVideoRice, "OpenGLVertexClipper", FALSE, "Enable vertex clipper for fog operations");
340     ConfigSetDefaultBool(l_ConfigVideoRice, "EnableSSE", TRUE, "Enable/Disable SSE optimizations for capable CPUs");
341     ConfigSetDefaultBool(l_ConfigVideoRice, "EnableVertexShader", FALSE, "Use GPU vertex shader");
342     ConfigSetDefaultBool(l_ConfigVideoRice, "SkipFrame", FALSE, "If this option is enabled, the plugin will skip every other frame");
343     ConfigSetDefaultBool(l_ConfigVideoRice, "TexRectOnly", FALSE, "If enabled, texture enhancement will be done only for TxtRect ucode");
344     ConfigSetDefaultBool(l_ConfigVideoRice, "SmallTextureOnly", FALSE, "If enabled, texture enhancement will be done only for textures width+height<=128");
345     ConfigSetDefaultBool(l_ConfigVideoRice, "LoadHiResCRCOnly", TRUE, "Select hi-resolution textures based only on the CRC and ignore format+size information (Glide64 compatibility)");
346     ConfigSetDefaultBool(l_ConfigVideoRice, "LoadHiResTextures", FALSE, "Enable hi-resolution texture file loading");
347     ConfigSetDefaultBool(l_ConfigVideoRice, "DumpTexturesToFiles", FALSE, "Enable texture dumping");
348     ConfigSetDefaultBool(l_ConfigVideoRice, "ShowFPS", FALSE, "Display On-screen FPS");
349
350     ConfigSetDefaultInt(l_ConfigVideoRice, "Mipmapping", 2, "Use Mipmapping? 0=no, 1=nearest, 2=bilinear, 3=trilinear");
351     ConfigSetDefaultInt(l_ConfigVideoRice, "FogMethod", 0, "Enable, Disable or Force fog generation (0=Disable, 1=Enable n64 choose, 2=Force Fog)");
352     ConfigSetDefaultInt(l_ConfigVideoRice, "ForceTextureFilter", 0, "Force to use texture filtering or not (0=auto: n64 choose, 1=force no filtering, 2=force filtering)");
353     ConfigSetDefaultInt(l_ConfigVideoRice, "TextureEnhancement", 0, "Primary texture enhancement filter (0=None, 1=2X, 2=2XSAI, 3=HQ2X, 4=LQ2X, 5=HQ4X, 6=Sharpen, 7=Sharpen More, 8=External, 9=Mirrored)");
354     ConfigSetDefaultInt(l_ConfigVideoRice, "TextureEnhancementControl", 0, "Secondary texture enhancement filter (0 = none, 1-4 = filtered)");
355     ConfigSetDefaultInt(l_ConfigVideoRice, "TextureQuality", TXT_QUALITY_DEFAULT, "Color bit depth to use for textures (0=default, 1=32 bits, 2=16 bits)");
356     ConfigSetDefaultInt(l_ConfigVideoRice, "OpenGLDepthBufferSetting", 16, "Z-buffer depth (only 16 or 32)");
357     ConfigSetDefaultInt(l_ConfigVideoRice, "MultiSampling", 0, "Enable/Disable MultiSampling (0=off, 2,4,8,16=quality)");
358     ConfigSetDefaultInt(l_ConfigVideoRice, "ColorQuality", TEXTURE_FMT_A8R8G8B8, "Color bit depth for rendering window (0=32 bits, 1=16 bits)");
359     ConfigSetDefaultInt(l_ConfigVideoRice, "OpenGLRenderSetting", OGL_DEVICE, "OpenGL level to support (0=auto, 1=OGL_1.1, 2=OGL_1.2, 3=OGL_1.3, 4=OGL_1.4, 5=OGL_1.4_V2, 6=OGL_TNT2, 7=NVIDIA_OGL, 8=OGL_FRAGMENT_PROGRAM)");
360     ConfigSetDefaultInt(l_ConfigVideoRice, "AnisotropicFiltering", 0, "Enable/Disable Anisotropic Filtering for Mipmapping (0=no filtering, 2-16=quality). This is uneffective if Mipmapping is 0. If the given value is to high to be supported by your graphic card, the value will be the highest value your graphic card can support. Better result with Trilinear filtering");
361     return TRUE;
362 }
363
364 bool isMMXSupported() 
365
366     int IsMMXSupported = 0; 
367    
368 #if !defined(__GNUC__) && !defined(NO_ASM)
369     __asm 
370     { 
371         mov eax,1   // CPUID level 1 
372         cpuid       // EDX = feature flag 
373         and edx,0x800000        // test bit 23 of feature flag 
374         mov IsMMXSupported,edx  // != 0 if MMX is supported 
375     } 
376 #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM)
377   return true;
378 #elif !defined(NO_ASM) // GCC assumed
379    asm volatile (
380          "push %%ebx           \n"
381          "mov $1, %%eax        \n"  // CPUID level 1 
382          "cpuid                \n"      // EDX = feature flag 
383          "and $0x800000, %%edx \n"      // test bit 23 of feature flag 
384          "pop %%ebx            \n"
385          : "=d"(IsMMXSupported)
386          :
387          : "memory", "cc", "eax", "ecx"
388          );
389 #endif
390     if (IsMMXSupported != 0) 
391         return true; 
392     else 
393         return false; 
394
395
396 bool isSSESupported() 
397 {
398     int SSESupport = 0;
399
400 // And finally, check the CPUID for Streaming SIMD Extensions support.
401 #if !defined(__GNUC__) && !defined(NO_ASM)
402     _asm
403         {
404             mov      eax, 1          // Put a "1" in eax to tell CPUID to get the feature bits
405             cpuid                    // Perform CPUID (puts processor feature info into EDX)
406             and      edx, 02000000h  // Test bit 25, for Streaming SIMD Extensions existence.
407             mov      SSESupport, edx // SIMD Extensions).  Set return value to 1 to indicate,
408     }
409 #elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM)
410   return true;
411 #elif !defined(NO_ASM) // GCC assumed
412    asm volatile (
413          "push %%ebx                       \n"
414          "mov $1, %%eax                    \n"  // Put a "1" in eax to tell CPUID to get the feature bits
415          "cpuid                            \n"  // Perform CPUID (puts processor feature info into EDX)
416          "and       $0x02000000, %%edx     \n"  // Test bit 25, for Streaming SIMD Extensions existence.
417          "pop %%ebx                        \n"
418          : "=d"(SSESupport)
419          :
420          : "memory", "cc", "eax", "ecx"
421          );
422 # endif
423     
424     if (SSESupport != 0) 
425         return true; 
426     else 
427         return false; 
428
429
430 static void ReadConfiguration(void)
431 {
432     windowSetting.bDisplayFullscreen = ConfigGetParamBool(l_ConfigVideoGeneral, "Fullscreen");
433     windowSetting.uDisplayWidth = ConfigGetParamInt(l_ConfigVideoGeneral, "ScreenWidth");
434         windowSetting.bDisplayRatio = true;
435         windowSetting.uDisplayX = 0;
436         windowSetting.uDisplayY = 0;
437     windowSetting.bDisplayRatio = ConfigGetParamBool(l_ConfigVideoGeneral, "AspectRatio");
438         if (windowSetting.bDisplayRatio) {
439                 if (windowSetting.uDisplayWidth==800) {
440                         windowSetting.uDisplayWidth = 640;      // no strech
441                         windowSetting.uDisplayX = 80;
442                 }
443         }
444     windowSetting.uDisplayHeight = ConfigGetParamInt(l_ConfigVideoGeneral, "ScreenHeight");
445     windowSetting.bVerticalSync = ConfigGetParamBool(l_ConfigVideoGeneral, "VerticalSync");
446
447     defaultRomOptions.N64FrameBufferEmuType = ConfigGetParamInt(l_ConfigVideoRice, "FrameBufferSetting");
448     defaultRomOptions.N64FrameBufferWriteBackControl = ConfigGetParamInt(l_ConfigVideoRice, "FrameBufferWriteBackControl");
449     defaultRomOptions.N64RenderToTextureEmuType = ConfigGetParamInt(l_ConfigVideoRice, "RenderToTexture");
450     defaultRomOptions.screenUpdateSetting = ConfigGetParamInt(l_ConfigVideoRice, "screenUpdateSetting");
451
452     defaultRomOptions.bNormalBlender = ConfigGetParamBool(l_ConfigVideoRice, "NormalAlphaBlender");
453     defaultRomOptions.bFastTexCRC = ConfigGetParamBool(l_ConfigVideoRice, "FastTextureLoading");
454     defaultRomOptions.bAccurateTextureMapping = ConfigGetParamBool(l_ConfigVideoRice, "AccurateTextureMapping");
455     defaultRomOptions.bInN64Resolution = ConfigGetParamBool(l_ConfigVideoRice, "InN64Resolution");
456     defaultRomOptions.bSaveVRAM = ConfigGetParamBool(l_ConfigVideoRice, "SaveVRAM");
457     defaultRomOptions.bDoubleSizeForSmallTxtrBuf = ConfigGetParamBool(l_ConfigVideoRice, "DoubleSizeForSmallTxtrBuf");
458     defaultRomOptions.bNormalCombiner = ConfigGetParamBool(l_ConfigVideoRice, "DefaultCombinerDisable");
459
460     options.bEnableHacks = ConfigGetParamBool(l_ConfigVideoRice, "EnableHacks");
461     options.bWinFrameMode = ConfigGetParamBool(l_ConfigVideoRice, "WinFrameMode");
462     options.bFullTMEM = ConfigGetParamBool(l_ConfigVideoRice, "FullTMEMEmulation");
463     options.bOGLVertexClipper = ConfigGetParamBool(l_ConfigVideoRice, "OpenGLVertexClipper");
464     options.bEnableSSE = ConfigGetParamBool(l_ConfigVideoRice, "EnableSSE");
465     options.bEnableVertexShader = ConfigGetParamBool(l_ConfigVideoRice, "EnableVertexShader");
466     options.bSkipFrame = ConfigGetParamBool(l_ConfigVideoRice, "SkipFrame");
467     options.bTexRectOnly = ConfigGetParamBool(l_ConfigVideoRice, "TexRectOnly");
468     options.bSmallTextureOnly = ConfigGetParamBool(l_ConfigVideoRice, "SmallTextureOnly");
469     options.bLoadHiResTextures = ConfigGetParamBool(l_ConfigVideoRice, "LoadHiResTextures");
470     options.bLoadHiResCRCOnly = ConfigGetParamBool(l_ConfigVideoRice, "LoadHiResCRCOnly");
471     options.bDumpTexturesToFiles = ConfigGetParamBool(l_ConfigVideoRice, "DumpTexturesToFiles");
472     options.bShowFPS = ConfigGetParamBool(l_ConfigVideoRice, "ShowFPS");
473
474     options.mipmapping = ConfigGetParamInt(l_ConfigVideoRice, "Mipmapping");
475     options.fogMethod = ConfigGetParamInt(l_ConfigVideoRice, "FogMethod");
476     options.forceTextureFilter = ConfigGetParamInt(l_ConfigVideoRice, "ForceTextureFilter");
477     options.textureEnhancement = ConfigGetParamInt(l_ConfigVideoRice, "TextureEnhancement");
478     options.textureEnhancementControl = ConfigGetParamInt(l_ConfigVideoRice, "TextureEnhancementControl");
479     options.textureQuality = ConfigGetParamInt(l_ConfigVideoRice, "TextureQuality");
480     options.OpenglDepthBufferSetting = ConfigGetParamInt(l_ConfigVideoRice, "OpenGLDepthBufferSetting");
481     options.multiSampling = ConfigGetParamInt(l_ConfigVideoRice, "MultiSampling");
482     options.colorQuality = ConfigGetParamInt(l_ConfigVideoRice, "ColorQuality");
483     options.OpenglRenderSetting = ConfigGetParamInt(l_ConfigVideoRice, "OpenGLRenderSetting");
484     options.anisotropicFiltering = ConfigGetParamInt(l_ConfigVideoRice, "AnisotropicFiltering");
485
486     CDeviceBuilder::SelectDeviceType((SupportedDeviceType)options.OpenglRenderSetting);
487
488     status.isMMXSupported = isMMXSupported();
489     status.isSSESupported = isSSESupported();
490     status.isVertexShaderSupported = false;
491
492     status.isSSEEnabled = status.isSSESupported && options.bEnableSSE;
493 #if !defined(NO_ASM)
494     if( status.isSSEEnabled )
495     {
496         ProcessVertexData = ProcessVertexDataSSE;
497         DebugMessage(M64MSG_INFO, "SSE processing enabled.");
498     }
499     else
500 #endif
501     {
502         ProcessVertexData = ProcessVertexDataNoSSE;
503         DebugMessage(M64MSG_INFO, "Disabled SSE processing.");
504     }
505
506     status.isVertexShaderEnabled = status.isVertexShaderSupported && options.bEnableVertexShader;
507     status.bUseHW_T_L = false;
508 }
509     
510 BOOL LoadConfiguration(void)
511 {
512     IniSections.clear();
513     bIniIsChanged = false;
514     strcpy(szIniFileName, INI_FILE);
515
516     if (!ReadIniFile())
517     {
518         DebugMessage(M64MSG_ERROR, "Unable to read ini file from disk");
519         return FALSE;
520     }
521
522     if (l_ConfigVideoGeneral == NULL || l_ConfigVideoRice == NULL)
523     {
524         DebugMessage(M64MSG_ERROR, "Rice Video configuration sections are not open!");
525         return FALSE;
526     }
527     
528     // Read config parameters from core config API and set up internal variables
529     ReadConfiguration();
530
531     return TRUE;
532 }
533
534 void GenerateCurrentRomOptions()
535 {
536     currentRomOptions.N64FrameBufferEmuType     =g_curRomInfo.dwFrameBufferOption;  
537     currentRomOptions.N64FrameBufferWriteBackControl        =defaultRomOptions.N64FrameBufferWriteBackControl;  
538     currentRomOptions.N64RenderToTextureEmuType =g_curRomInfo.dwRenderToTextureOption;  
539     currentRomOptions.screenUpdateSetting       =g_curRomInfo.dwScreenUpdateSetting;
540     currentRomOptions.bNormalCombiner           =g_curRomInfo.dwNormalCombiner;
541     currentRomOptions.bNormalBlender            =g_curRomInfo.dwNormalBlender;
542     currentRomOptions.bFastTexCRC               =g_curRomInfo.dwFastTextureCRC;
543     currentRomOptions.bAccurateTextureMapping   =g_curRomInfo.dwAccurateTextureMapping;
544
545     options.enableHackForGames = NO_HACK_FOR_GAME;
546     if ((strncmp((char*)g_curRomInfo.szGameName, "BANJO TOOIE", 11) == 0))
547     {
548         options.enableHackForGames = HACK_FOR_BANJO_TOOIE;
549     }
550     else if ((strncmp((char*)g_curRomInfo.szGameName, "DR.MARIO", 8) == 0))
551     {
552         options.enableHackForGames = HACK_FOR_DR_MARIO;
553     }
554     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Pilot", 5) == 0))
555     {
556         options.enableHackForGames = HACK_FOR_PILOT_WINGS;
557     }
558     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "YOSHI", 5) == 0))
559     {
560         options.enableHackForGames = HACK_FOR_YOSHI;
561     }
562     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "NITRO", 5) == 0))
563     {
564         options.enableHackForGames = HACK_FOR_NITRO;
565     }
566     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "TONY HAWK", 9) == 0))
567     {
568         options.enableHackForGames = HACK_FOR_TONYHAWK;
569     }
570     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "THPS", 4) == 0))
571     {
572         options.enableHackForGames = HACK_FOR_TONYHAWK;
573     }
574     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "SPIDERMAN", 9) == 0))
575     {
576         options.enableHackForGames = HACK_FOR_TONYHAWK;
577     }
578     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "NASCAR", 6) == 0))
579     {
580         options.enableHackForGames = HACK_FOR_NASCAR;
581     }
582     else if ((strstr((char*)g_curRomInfo.szGameName, "ZELDA") != 0) && (strstr((char*)g_curRomInfo.szGameName, "MASK") != 0))
583     {
584         options.enableHackForGames = HACK_FOR_ZELDA_MM;
585     }
586     else if ((strstr((char*)g_curRomInfo.szGameName, "ZELDA") != 0))
587     {
588         options.enableHackForGames = HACK_FOR_ZELDA;
589     }
590     else if ((strstr((char*)g_curRomInfo.szGameName, "Ogre") != 0))
591     {
592         options.enableHackForGames = HACK_FOR_OGRE_BATTLE;
593     }
594     else if ((strstr((char*)g_curRomInfo.szGameName, "TWINE") != 0))
595     {
596         options.enableHackForGames = HACK_FOR_TWINE;
597     }
598     else if ((strstr((char*)g_curRomInfo.szGameName, "Squadron") != 0))
599     {
600         options.enableHackForGames = HACK_FOR_ROGUE_SQUADRON;
601     }
602     else if ((strstr((char*)g_curRomInfo.szGameName, "Baseball") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Star") != 0))
603     {
604         options.enableHackForGames = HACK_FOR_ALL_STAR_BASEBALL;
605     }
606     else if ((strstr((char*)g_curRomInfo.szGameName, "Tigger") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Honey") != 0))
607     {
608         options.enableHackForGames = HACK_FOR_TIGER_HONEY_HUNT;
609     }
610     else if ((strstr((char*)g_curRomInfo.szGameName, "Bust") != 0) && (strstr((char*)g_curRomInfo.szGameName, "Move") != 0))
611     {
612         options.enableHackForGames = HACK_FOR_BUST_A_MOVE;
613     }
614     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MarioTennis",11) == 0))
615     {
616         options.enableHackForGames = HACK_FOR_MARIO_TENNIS;
617     }
618     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "SUPER BOWLING",13) == 0))
619     {
620         options.enableHackForGames = HACK_FOR_SUPER_BOWLING;
621     }
622     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "CONKER",6) == 0))
623     {
624         options.enableHackForGames = HACK_FOR_CONKER;
625     }
626     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MK_MYTHOLOGIES",14) == 0))
627     {
628         options.enableHackForGames = HACK_REVERSE_Y_COOR;
629     }
630     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Fighting Force",14) == 0))
631     {
632         options.enableHackForGames = HACK_REVERSE_XY_COOR;
633     }
634     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "GOLDENEYE",9) == 0))
635     {
636         options.enableHackForGames = HACK_FOR_GOLDEN_EYE;
637     }
638     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "F-ZERO",6) == 0))
639     {
640         options.enableHackForGames = HACK_FOR_FZERO;
641     }
642     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Command&Conquer",15) == 0))
643     {
644         options.enableHackForGames = HACK_FOR_COMMANDCONQUER;
645     }
646     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "READY 2 RUMBLE",14) == 0))
647     {
648         options.enableHackForGames = HACK_FOR_RUMBLE;
649     }
650     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "READY to RUMBLE",15) == 0))
651     {
652         options.enableHackForGames = HACK_FOR_RUMBLE;
653     }
654     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "South Park Rally",16) == 0))
655     {
656         options.enableHackForGames = HACK_FOR_SOUTH_PARK_RALLY;
657     }
658     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "Extreme G 2",11) == 0))
659     {
660         options.enableHackForGames = HACK_FOR_EXTREME_G2;
661     }
662     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MarioGolf64",11) == 0))
663     {
664         options.enableHackForGames = HACK_FOR_MARIO_GOLF;
665     }
666     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MLB FEATURING",13) == 0))
667     {
668         options.enableHackForGames = HACK_FOR_MLB;
669     }
670     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "POLARISSNOCROSS",15) == 0))
671     {
672         options.enableHackForGames = HACK_FOR_POLARISSNOCROSS;
673     }
674     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "TOP GEAR RALLY",14) == 0))
675     {
676         options.enableHackForGames = HACK_FOR_TOPGEARRALLY;
677     }
678     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "DUKE NUKEM",10) == 0))
679     {
680         options.enableHackForGames = HACK_FOR_DUKE_NUKEM;
681     }
682     else if ((strncasecmp((char*)g_curRomInfo.szGameName, "MARIOKART64",11) == 0))
683     {
684         options.enableHackForGames = HACK_FOR_MARIO_KART;
685     }
686
687     if (options.enableHackForGames != NO_HACK_FOR_GAME)
688         DebugMessage(M64MSG_INFO, "Enabled hacks for game: '%s'", g_curRomInfo.szGameName);
689
690     if( currentRomOptions.N64FrameBufferEmuType == 0 )      currentRomOptions.N64FrameBufferEmuType = defaultRomOptions.N64FrameBufferEmuType;
691     else currentRomOptions.N64FrameBufferEmuType--;
692     if( currentRomOptions.N64RenderToTextureEmuType == 0 )  currentRomOptions.N64RenderToTextureEmuType = defaultRomOptions.N64RenderToTextureEmuType;
693     else currentRomOptions.N64RenderToTextureEmuType--;
694     if( currentRomOptions.screenUpdateSetting == 0 )        currentRomOptions.screenUpdateSetting = defaultRomOptions.screenUpdateSetting;
695     if( currentRomOptions.bNormalCombiner == 0 )            currentRomOptions.bNormalCombiner = defaultRomOptions.bNormalCombiner;
696     else currentRomOptions.bNormalCombiner--;
697     if( currentRomOptions.bNormalBlender == 0 )             currentRomOptions.bNormalBlender = defaultRomOptions.bNormalBlender;
698     else currentRomOptions.bNormalBlender--;
699     if( currentRomOptions.bFastTexCRC == 0 )                currentRomOptions.bFastTexCRC = defaultRomOptions.bFastTexCRC;
700     else currentRomOptions.bFastTexCRC--;
701     if( currentRomOptions.bAccurateTextureMapping == 0 )    currentRomOptions.bAccurateTextureMapping = defaultRomOptions.bAccurateTextureMapping;
702     else currentRomOptions.bAccurateTextureMapping--;
703
704     options.bUseFullTMEM = ((options.bFullTMEM && (g_curRomInfo.dwFullTMEM == 0)) || g_curRomInfo.dwFullTMEM == 2);
705
706     GenerateFrameBufferOptions();
707
708     if( options.enableHackForGames == HACK_FOR_MARIO_GOLF || options.enableHackForGames == HACK_FOR_MARIO_TENNIS )
709     {
710         frameBufferOptions.bIgnoreRenderTextureIfHeightUnknown = true;
711     }
712 }
713
714 void Ini_GetRomOptions(LPGAMESETTING pGameSetting)
715 {
716     int i;
717
718     i = FindIniEntry(pGameSetting->romheader.dwCRC1,
719                      pGameSetting->romheader.dwCRC2,
720                      pGameSetting->romheader.nCountryID,
721                      (char*)pGameSetting->szGameName, 1);
722
723     pGameSetting->bDisableTextureCRC    = IniSections[i].bDisableTextureCRC;
724     pGameSetting->bDisableCulling       = IniSections[i].bDisableCulling;
725     pGameSetting->bIncTexRectEdge       = IniSections[i].bIncTexRectEdge;
726     pGameSetting->bZHack                = IniSections[i].bZHack;
727     pGameSetting->bTextureScaleHack     = IniSections[i].bTextureScaleHack;
728     pGameSetting->bPrimaryDepthHack     = IniSections[i].bPrimaryDepthHack;
729     pGameSetting->bTexture1Hack         = IniSections[i].bTexture1Hack;
730     pGameSetting->bFastLoadTile         = IniSections[i].bFastLoadTile;
731     pGameSetting->bUseSmallerTexture    = IniSections[i].bUseSmallerTexture;
732
733     pGameSetting->VIWidth               = IniSections[i].VIWidth;
734     pGameSetting->VIHeight              = IniSections[i].VIHeight;
735     pGameSetting->UseCIWidthAndRatio    = IniSections[i].UseCIWidthAndRatio;
736     pGameSetting->dwFullTMEM            = IniSections[i].dwFullTMEM;
737     pGameSetting->bTxtSizeMethod2       = IniSections[i].bTxtSizeMethod2;
738     pGameSetting->bEnableTxtLOD         = IniSections[i].bEnableTxtLOD;
739
740     pGameSetting->dwFastTextureCRC      = IniSections[i].dwFastTextureCRC;
741     pGameSetting->bEmulateClear         = IniSections[i].bEmulateClear;
742     pGameSetting->bForceScreenClear     = IniSections[i].bForceScreenClear;
743     pGameSetting->dwAccurateTextureMapping  = IniSections[i].dwAccurateTextureMapping;
744     pGameSetting->dwNormalBlender       = IniSections[i].dwNormalBlender;
745     pGameSetting->bDisableBlender       = IniSections[i].bDisableBlender;
746     pGameSetting->dwNormalCombiner      = IniSections[i].dwNormalCombiner;
747     pGameSetting->bForceDepthBuffer     = IniSections[i].bForceDepthBuffer;
748     pGameSetting->bDisableObjBG         = IniSections[i].bDisableObjBG;
749     pGameSetting->dwFrameBufferOption   = IniSections[i].dwFrameBufferOption;
750     pGameSetting->dwRenderToTextureOption   = IniSections[i].dwRenderToTextureOption;
751     pGameSetting->dwScreenUpdateSetting = IniSections[i].dwScreenUpdateSetting;
752 }
753
754 void Ini_StoreRomOptions(LPGAMESETTING pGameSetting)
755 {
756     int i;
757
758     i = FindIniEntry(pGameSetting->romheader.dwCRC1,
759                      pGameSetting->romheader.dwCRC2,
760                      pGameSetting->romheader.nCountryID,
761                      (char*)pGameSetting->szGameName, 0);
762
763     if( IniSections[i].bDisableTextureCRC   !=pGameSetting->bDisableTextureCRC )
764     {
765         IniSections[i].bDisableTextureCRC   =pGameSetting->bDisableTextureCRC    ;
766         bIniIsChanged=true;
767     }
768
769     if( IniSections[i].bDisableCulling  !=pGameSetting->bDisableCulling )
770     {
771         IniSections[i].bDisableCulling  =pGameSetting->bDisableCulling   ;
772         bIniIsChanged=true;
773     }
774
775     if( IniSections[i].dwFastTextureCRC !=pGameSetting->dwFastTextureCRC )
776     {
777         IniSections[i].dwFastTextureCRC =pGameSetting->dwFastTextureCRC      ;
778         bIniIsChanged=true;
779     }
780
781     if( IniSections[i].bEmulateClear !=pGameSetting->bEmulateClear )
782     {
783         IniSections[i].bEmulateClear    =pGameSetting->bEmulateClear         ;
784         bIniIsChanged=true;
785     }
786
787     if( IniSections[i].dwNormalBlender      !=pGameSetting->dwNormalBlender )
788     {
789         IniSections[i].dwNormalBlender      =pGameSetting->dwNormalBlender       ;
790         bIniIsChanged=true;
791     }
792
793     if( IniSections[i].bDisableBlender  !=pGameSetting->bDisableBlender )
794     {
795         IniSections[i].bDisableBlender  =pGameSetting->bDisableBlender       ;
796         bIniIsChanged=true;
797     }
798
799     if( IniSections[i].bForceScreenClear    !=pGameSetting->bForceScreenClear )
800     {
801         IniSections[i].bForceScreenClear    =pGameSetting->bForceScreenClear         ;
802         bIniIsChanged=true;
803     }
804     if( IniSections[i].dwAccurateTextureMapping !=pGameSetting->dwAccurateTextureMapping )
805     {
806         IniSections[i].dwAccurateTextureMapping =pGameSetting->dwAccurateTextureMapping      ;
807         bIniIsChanged=true;
808     }
809     if( IniSections[i].dwNormalCombiner !=pGameSetting->dwNormalCombiner )
810     {
811         IniSections[i].dwNormalCombiner =pGameSetting->dwNormalCombiner      ;
812         bIniIsChanged=true;
813     }
814     if( IniSections[i].bForceDepthBuffer    !=pGameSetting->bForceDepthBuffer )
815     {
816         IniSections[i].bForceDepthBuffer    =pGameSetting->bForceDepthBuffer         ;
817         bIniIsChanged=true;
818     }
819     if( IniSections[i].bDisableObjBG    !=pGameSetting->bDisableObjBG )
820     {
821         IniSections[i].bDisableObjBG    =pGameSetting->bDisableObjBG         ;
822         bIniIsChanged=true;
823     }
824     if( IniSections[i].dwFrameBufferOption  !=pGameSetting->dwFrameBufferOption )
825     {
826         IniSections[i].dwFrameBufferOption  =pGameSetting->dwFrameBufferOption       ;
827         bIniIsChanged=true;
828     }
829     if( IniSections[i].dwRenderToTextureOption  !=pGameSetting->dwRenderToTextureOption )
830     {
831         IniSections[i].dwRenderToTextureOption  =pGameSetting->dwRenderToTextureOption       ;
832         bIniIsChanged=true;
833     }
834     if( IniSections[i].dwScreenUpdateSetting    !=pGameSetting->dwScreenUpdateSetting )
835     {
836         IniSections[i].dwScreenUpdateSetting    =pGameSetting->dwScreenUpdateSetting         ;
837         bIniIsChanged=true;
838     }
839     if( IniSections[i].bIncTexRectEdge  != pGameSetting->bIncTexRectEdge )
840     {
841         IniSections[i].bIncTexRectEdge      =pGameSetting->bIncTexRectEdge;
842         bIniIsChanged=true;
843     }
844     if( IniSections[i].bZHack   != pGameSetting->bZHack )
845     {
846         IniSections[i].bZHack       =pGameSetting->bZHack;
847         bIniIsChanged=true;
848     }
849     if( IniSections[i].bTextureScaleHack    != pGameSetting->bTextureScaleHack )
850     {
851         IniSections[i].bTextureScaleHack        =pGameSetting->bTextureScaleHack;
852         bIniIsChanged=true;
853     }
854     if( IniSections[i].bPrimaryDepthHack    != pGameSetting->bPrimaryDepthHack )
855     {
856         IniSections[i].bPrimaryDepthHack        =pGameSetting->bPrimaryDepthHack;
857         bIniIsChanged=true;
858     }
859     if( IniSections[i].bTexture1Hack    != pGameSetting->bTexture1Hack )
860     {
861         IniSections[i].bTexture1Hack        =pGameSetting->bTexture1Hack;
862         bIniIsChanged=true;
863     }
864     if( IniSections[i].bFastLoadTile    != pGameSetting->bFastLoadTile )
865     {
866         IniSections[i].bFastLoadTile    =pGameSetting->bFastLoadTile;
867         bIniIsChanged=true;
868     }
869     if( IniSections[i].bUseSmallerTexture   != pGameSetting->bUseSmallerTexture )
870     {
871         IniSections[i].bUseSmallerTexture   =pGameSetting->bUseSmallerTexture;
872         bIniIsChanged=true;
873     }
874     if( IniSections[i].VIWidth  != pGameSetting->VIWidth )
875     {
876         IniSections[i].VIWidth  =pGameSetting->VIWidth;
877         bIniIsChanged=true;
878     }
879     if( IniSections[i].VIHeight != pGameSetting->VIHeight )
880     {
881         IniSections[i].VIHeight =pGameSetting->VIHeight;
882         bIniIsChanged=true;
883     }
884     if( IniSections[i].UseCIWidthAndRatio   != pGameSetting->UseCIWidthAndRatio )
885     {
886         IniSections[i].UseCIWidthAndRatio   =pGameSetting->UseCIWidthAndRatio;
887         bIniIsChanged=true;
888     }
889     if( IniSections[i].dwFullTMEM   != pGameSetting->dwFullTMEM )
890     {
891         IniSections[i].dwFullTMEM   =pGameSetting->dwFullTMEM;
892         bIniIsChanged=true;
893     }
894     if( IniSections[i].bTxtSizeMethod2  != pGameSetting->bTxtSizeMethod2 )
895     {
896         IniSections[i].bTxtSizeMethod2  =pGameSetting->bTxtSizeMethod2;
897         bIniIsChanged=true;
898     }
899     if( IniSections[i].bEnableTxtLOD    != pGameSetting->bEnableTxtLOD )
900     {
901         IniSections[i].bEnableTxtLOD    =pGameSetting->bEnableTxtLOD;
902         bIniIsChanged=true;
903     }
904
905     if( bIniIsChanged )
906     {
907         WriteIniFile();
908         TRACE0("Rom option is changed and saved");
909     }
910 }
911
912 std::ifstream& getline( std::ifstream &is, char *str );
913
914 char * left(const char * src, int nchars)
915 {
916     static char dst[300];
917     strncpy(dst,src,nchars);
918     dst[nchars]=0;
919     return dst;
920 }
921
922 char * right(const char *src, int nchars)
923 {
924     static char dst[300];
925     int srclen = strlen(src);
926     if (nchars >= srclen)
927     {
928         strcpy(dst, src);
929     }
930     else
931     {
932         strncpy(dst, src + srclen - nchars, nchars);
933         dst[nchars]=0;
934     }
935     return dst;
936 }
937
938 char * tidy(char * s)
939 {
940     char * p = s + strlen(s);
941
942     p--;
943     while (p >= s && (*p == ' ' || *p == 0xa || *p == '\n') )
944     {
945         *p = 0;
946         p--;
947     }
948     return s;
949
950 }
951
952 BOOL ReadIniFile()
953 {
954     std::ifstream inifile;
955     char readinfo[100];
956     const char *ini_filepath = ConfigGetSharedDataFilepath(szIniFileName);
957
958     DebugMessage(M64MSG_VERBOSE, "Reading .ini file: %s", ini_filepath);
959     inifile.open(ini_filepath);
960
961     if (inifile.fail())
962     {
963         return FALSE;
964     }
965
966     while (getline(inifile,readinfo)/*&&sectionno<999*/)
967     {
968         tidy(readinfo);
969
970         if (readinfo[0] == '/')
971             continue;
972
973         if (!strcasecmp(readinfo,"")==0)
974         {
975             if (readinfo[0] == '{') //if a section heading
976             {
977                 section newsection;
978
979                 readinfo[strlen(readinfo)-1]='\0';
980                 strcpy(newsection.crccheck, readinfo+1);
981
982                 newsection.bDisableTextureCRC = FALSE;
983                 newsection.bDisableCulling = FALSE;
984                 newsection.bIncTexRectEdge = FALSE;
985                 newsection.bZHack = FALSE;
986                 newsection.bTextureScaleHack = FALSE;
987                 newsection.bFastLoadTile = FALSE;
988                 newsection.bUseSmallerTexture = FALSE;
989                 newsection.bPrimaryDepthHack = FALSE;
990                 newsection.bTexture1Hack = FALSE;
991                 newsection.bDisableObjBG = FALSE;
992                 newsection.VIWidth = -1;
993                 newsection.VIHeight = -1;
994                 newsection.UseCIWidthAndRatio = NOT_USE_CI_WIDTH_AND_RATIO;
995                 newsection.dwFullTMEM = 0;
996                 newsection.bTxtSizeMethod2 = FALSE;
997                 newsection.bEnableTxtLOD = FALSE;
998
999                 newsection.bEmulateClear = FALSE;
1000                 newsection.bForceScreenClear = FALSE;
1001                 newsection.bDisableBlender = FALSE;
1002                 newsection.bForceDepthBuffer = FALSE;
1003                 newsection.dwFastTextureCRC = 0;
1004                 newsection.dwAccurateTextureMapping = 0;
1005                 newsection.dwNormalBlender = 0;
1006                 newsection.dwNormalCombiner = 0;
1007                 newsection.dwFrameBufferOption = 0;
1008                 newsection.dwRenderToTextureOption = 0;
1009                 newsection.dwScreenUpdateSetting = 0;
1010
1011                 IniSections.push_back(newsection);
1012
1013             }
1014             else
1015             {       
1016                 int sectionno = IniSections.size() - 1;
1017
1018                 if (strcasecmp(left(readinfo,4), "Name")==0)
1019                     strcpy(IniSections[sectionno].name,right(readinfo,strlen(readinfo)-5));
1020
1021                 if (strcasecmp(left(readinfo,17), "DisableTextureCRC")==0)
1022                     IniSections[sectionno].bDisableTextureCRC=true;
1023
1024                 if (strcasecmp(left(readinfo,14), "DisableCulling")==0)
1025                     IniSections[sectionno].bDisableCulling=true;
1026
1027                 if (strcasecmp(left(readinfo,16), "PrimaryDepthHack")==0)
1028                     IniSections[sectionno].bPrimaryDepthHack=true;
1029
1030                 if (strcasecmp(left(readinfo,12), "Texture1Hack")==0)
1031                     IniSections[sectionno].bTexture1Hack=true;
1032
1033                 if (strcasecmp(left(readinfo,12), "FastLoadTile")==0)
1034                     IniSections[sectionno].bFastLoadTile=true;
1035
1036                 if (strcasecmp(left(readinfo,17), "UseSmallerTexture")==0)
1037                     IniSections[sectionno].bUseSmallerTexture=true;
1038
1039                 if (strcasecmp(left(readinfo,14), "IncTexRectEdge")==0)
1040                     IniSections[sectionno].bIncTexRectEdge=true;
1041
1042                 if (strcasecmp(left(readinfo,5), "ZHack")==0)
1043                     IniSections[sectionno].bZHack=true;
1044
1045                 if (strcasecmp(left(readinfo,16), "TexRectScaleHack")==0)
1046                     IniSections[sectionno].bTextureScaleHack=true;
1047
1048                 if (strcasecmp(left(readinfo,7), "VIWidth")==0)
1049                     IniSections[sectionno].VIWidth = strtol(right(readinfo,3),NULL,10);
1050
1051                 if (strcasecmp(left(readinfo,8), "VIHeight")==0)
1052                     IniSections[sectionno].VIHeight = strtol(right(readinfo,3),NULL,10);
1053
1054                 if (strcasecmp(left(readinfo,18), "UseCIWidthAndRatio")==0)
1055                     IniSections[sectionno].UseCIWidthAndRatio = strtol(right(readinfo,1),NULL,10);
1056
1057                 if (strcasecmp(left(readinfo,8), "FullTMEM")==0)
1058                     IniSections[sectionno].dwFullTMEM = strtol(right(readinfo,1),NULL,10);
1059
1060                 if (strcasecmp(left(readinfo,24), "AlternativeTxtSizeMethod")==0)
1061                     IniSections[sectionno].bTxtSizeMethod2 = strtol(right(readinfo,1),NULL,10);
1062
1063                 if (strcasecmp(left(readinfo,12), "EnableTxtLOD")==0)
1064                     IniSections[sectionno].bEnableTxtLOD = strtol(right(readinfo,1),NULL,10);
1065
1066                 if (strcasecmp(left(readinfo,12), "DisableObjBG")==0)
1067                     IniSections[sectionno].bDisableObjBG = strtol(right(readinfo,1),NULL,10);
1068
1069                 if (strcasecmp(left(readinfo,16), "ForceScreenClear")==0)
1070                     IniSections[sectionno].bForceScreenClear = strtol(right(readinfo,1),NULL,10);
1071
1072                 if (strcasecmp(left(readinfo,22), "AccurateTextureMapping")==0)
1073                     IniSections[sectionno].dwAccurateTextureMapping = strtol(right(readinfo,1),NULL,10);
1074
1075                 if (strcasecmp(left(readinfo,14), "FastTextureCRC")==0)
1076                     IniSections[sectionno].dwFastTextureCRC = strtol(right(readinfo,1),NULL,10);
1077
1078                 if (strcasecmp(left(readinfo,12), "EmulateClear")==0)
1079                     IniSections[sectionno].bEmulateClear = strtol(right(readinfo,1),NULL,10);
1080
1081                 if (strcasecmp(left(readinfo,18), "NormalAlphaBlender")==0)
1082                     IniSections[sectionno].dwNormalBlender = strtol(right(readinfo,1),NULL,10);
1083
1084                 if (strcasecmp(left(readinfo,19), "DisableAlphaBlender")==0)
1085                     IniSections[sectionno].bDisableBlender = strtol(right(readinfo,1),NULL,10);
1086
1087                 if (strcasecmp(left(readinfo,19), "NormalColorCombiner")==0)
1088                     IniSections[sectionno].dwNormalCombiner = strtol(right(readinfo,1),NULL,10);
1089
1090                 if (strcasecmp(left(readinfo,16), "ForceDepthBuffer")==0)
1091                     IniSections[sectionno].bForceDepthBuffer = strtol(right(readinfo,1),NULL,10);
1092
1093                 if (strcasecmp(left(readinfo,20), "FrameBufferEmulation")==0)
1094                     IniSections[sectionno].dwFrameBufferOption = strtol(readinfo+21,NULL,10);
1095
1096                 if (strcasecmp(left(readinfo,15), "RenderToTexture")==0)
1097                     IniSections[sectionno].dwRenderToTextureOption = strtol(right(readinfo,1),NULL,10);
1098
1099                 if (strcasecmp(left(readinfo,19), "ScreenUpdateSetting")==0)
1100                     IniSections[sectionno].dwScreenUpdateSetting = strtol(right(readinfo,1),NULL,10);
1101             }
1102         }
1103     }
1104     inifile.close();
1105
1106     return TRUE;
1107 }
1108
1109 //read a line from the ini file
1110 std::ifstream & getline(std::ifstream & is, char *str)
1111 {
1112     char buf[100];
1113
1114     is.getline(buf,100);
1115     strcpy( str,buf);
1116     return is;
1117 }
1118
1119 void WriteIniFile()
1120 {
1121     uint32 i;
1122     FILE * fhIn;
1123     FILE * fhOut;
1124
1125     /* get path to game-hack INI file and read it */
1126     const char *ini_filepath = ConfigGetSharedDataFilepath(szIniFileName);
1127     if (ini_filepath == NULL)
1128         return;
1129     fhIn = fopen(ini_filepath, "r");
1130     if (fhIn == NULL)
1131         return;
1132     fseek(fhIn, 0L, SEEK_END);
1133     long filelen = ftell(fhIn);
1134     fseek(fhIn, 0L, SEEK_SET);
1135     char *chIniData = (char *) malloc(filelen + 1);
1136     if (chIniData == NULL)
1137     {
1138         fclose(fhIn);
1139         return;
1140     }
1141     long bytesread = fread(chIniData, 1, filelen, fhIn);
1142     fclose(fhIn);
1143     if (bytesread != filelen)
1144     {
1145         free(chIniData);
1146         return;
1147     }
1148     chIniData[filelen] = 0;
1149
1150     /* now try to open the file for writing */
1151     fhOut = fopen(ini_filepath, "w");
1152     if (fhOut == NULL)
1153     {
1154         free(chIniData);
1155         return;
1156     }
1157
1158     // Mark all sections and needing to be written
1159     for (i = 0; i < IniSections.size(); i++)
1160     {
1161         IniSections[i].bOutput = false;
1162     }
1163
1164     char *thisline = chIniData;
1165     while ((thisline - chIniData) < filelen)
1166     {
1167         char *nextline = strchr(thisline, '\n');
1168         if (nextline == NULL)
1169             nextline = thisline + strlen(thisline) + 1;
1170         else
1171             nextline++;
1172         if (thisline[0] == '{')
1173         {
1174             BOOL bFound = FALSE;
1175             // Start of section
1176             tidy((char*) thisline);
1177             thisline[strlen(thisline) - 1] = '\0';
1178             for (i = 0; i < IniSections.size(); i++)
1179             {
1180                 if (IniSections[i].bOutput)
1181                     continue;
1182                 if (strcasecmp((char*) thisline + 1, IniSections[i].crccheck) == 0)
1183                 {
1184                     // Output this CRC
1185                     OutputSectionDetails(i, fhOut);
1186                     IniSections[i].bOutput = true;
1187                     bFound = TRUE;
1188                     break;
1189                 }
1190             }
1191             if (!bFound)
1192             {
1193                 // Do what? This should never happen, unless the user
1194                 // replaces the inifile while game is running!
1195             }
1196         }
1197         else if (thisline[0] == '/')
1198         {
1199             // Comment
1200             fputs((char*) thisline, fhOut);
1201         }
1202         thisline = nextline;
1203     }
1204
1205     // Input buffer done-  process any new entries!
1206     for (i = 0; i < IniSections.size(); i++)
1207     {
1208         // Skip any that have not been done.
1209         if (IniSections[i].bOutput)
1210             continue;
1211         // Output this CRC
1212         OutputSectionDetails(i, fhOut);
1213         IniSections[i].bOutput = true;
1214     }
1215
1216     fclose(fhOut);
1217     free(chIniData);
1218
1219     bIniIsChanged = false;
1220 }
1221
1222 void OutputSectionDetails(uint32 i, FILE * fh)
1223 {
1224     fprintf(fh, "{%s}\n", IniSections[i].crccheck);
1225
1226     fprintf(fh, "Name=%s\n", IniSections[i].name);
1227     //fprintf(fh, "UCode=%d\n", IniSections[i].ucode);
1228
1229     // Tri-state variables
1230     if (IniSections[i].dwAccurateTextureMapping != 0)
1231         fprintf(fh, "AccurateTextureMapping=%d\n", IniSections[i].dwAccurateTextureMapping);
1232
1233     if (IniSections[i].dwFastTextureCRC != 0)
1234         fprintf(fh, "FastTextureCRC=%d\n", IniSections[i].dwFastTextureCRC);
1235
1236     if (IniSections[i].dwNormalBlender != 0)
1237         fprintf(fh, "NormalAlphaBlender=%d\n", IniSections[i].dwNormalBlender);
1238
1239     if (IniSections[i].dwNormalCombiner != 0)
1240         fprintf(fh, "NormalColorCombiner=%d\n", IniSections[i].dwNormalCombiner);
1241
1242
1243     // Normal bi-state variables
1244     if (IniSections[i].bDisableTextureCRC)
1245         fprintf(fh, "DisableTextureCRC\n");
1246
1247     if (IniSections[i].bDisableCulling)
1248         fprintf(fh, "DisableCulling\n");
1249
1250     if (IniSections[i].bPrimaryDepthHack)
1251         fprintf(fh, "PrimaryDepthHack\n");
1252
1253     if (IniSections[i].bTexture1Hack)
1254         fprintf(fh, "Texture1Hack\n");
1255
1256     if (IniSections[i].bFastLoadTile)
1257         fprintf(fh, "FastLoadTile\n");
1258
1259     if (IniSections[i].bUseSmallerTexture)
1260         fprintf(fh, "UseSmallerTexture\n");
1261
1262     if (IniSections[i].bIncTexRectEdge)
1263         fprintf(fh, "IncTexRectEdge\n");
1264
1265     if (IniSections[i].bZHack)
1266         fprintf(fh, "ZHack\n");
1267
1268     if (IniSections[i].bTextureScaleHack)
1269         fprintf(fh, "TexRectScaleHack\n");
1270
1271     if (IniSections[i].VIWidth > 0)
1272         fprintf(fh, "VIWidth=%d\n", IniSections[i].VIWidth);
1273
1274     if (IniSections[i].VIHeight > 0)
1275         fprintf(fh, "VIHeight=%d\n", IniSections[i].VIHeight);
1276
1277     if (IniSections[i].UseCIWidthAndRatio > 0)
1278         fprintf(fh, "UseCIWidthAndRatio=%d\n", IniSections[i].UseCIWidthAndRatio);
1279
1280     if (IniSections[i].dwFullTMEM > 0)
1281         fprintf(fh, "FullTMEM=%d\n", IniSections[i].dwFullTMEM);
1282
1283     if (IniSections[i].bTxtSizeMethod2 != FALSE )
1284         fprintf(fh, "AlternativeTxtSizeMethod=%d\n", IniSections[i].bTxtSizeMethod2);
1285
1286     if (IniSections[i].bEnableTxtLOD != FALSE )
1287         fprintf(fh, "EnableTxtLOD=%d\n", IniSections[i].bEnableTxtLOD);
1288
1289     if (IniSections[i].bDisableObjBG != 0 )
1290         fprintf(fh, "DisableObjBG=%d\n", IniSections[i].bDisableObjBG);
1291
1292     if (IniSections[i].bForceScreenClear != 0)
1293         fprintf(fh, "ForceScreenClear=%d\n", IniSections[i].bForceScreenClear);
1294
1295     if (IniSections[i].bEmulateClear != 0)
1296         fprintf(fh, "EmulateClear=%d\n", IniSections[i].bEmulateClear);
1297
1298     if (IniSections[i].bDisableBlender != 0)
1299         fprintf(fh, "DisableAlphaBlender=%d\n", IniSections[i].bDisableBlender);
1300
1301     if (IniSections[i].bForceDepthBuffer != 0)
1302         fprintf(fh, "ForceDepthBuffer=%d\n", IniSections[i].bForceDepthBuffer);
1303
1304     if (IniSections[i].dwFrameBufferOption != 0)
1305         fprintf(fh, "FrameBufferEmulation=%d\n", IniSections[i].dwFrameBufferOption);
1306
1307     if (IniSections[i].dwRenderToTextureOption != 0)
1308         fprintf(fh, "RenderToTexture=%d\n", IniSections[i].dwRenderToTextureOption);
1309
1310     if (IniSections[i].dwScreenUpdateSetting != 0)
1311         fprintf(fh, "ScreenUpdateSetting=%d\n", IniSections[i].dwScreenUpdateSetting);
1312
1313     fprintf(fh, "\n");          // Spacer
1314 }
1315
1316 // Find the entry corresponding to the specified rom. 
1317 // If the rom is not found, a new entry is created
1318 // The resulting value is returned
1319 void __cdecl DebuggerAppendMsg (const char * Message, ...);
1320
1321 static int FindIniEntry(uint32 dwCRC1, uint32 dwCRC2, uint8 nCountryID, char* szName, int PrintInfo)
1322 {
1323     uint32 i;
1324     unsigned char szCRC[50+1];
1325
1326     // Generate the CRC-ID for this rom:
1327     sprintf((char*)szCRC, "%08x%08x-%02x", (unsigned int)dwCRC1, (unsigned int)dwCRC2, nCountryID);
1328
1329     for (i = 0; i < IniSections.size(); i++)
1330     {
1331         if (strcasecmp((char*)szCRC, IniSections[i].crccheck) == 0)
1332         {
1333             if (PrintInfo)
1334                 DebugMessage(M64MSG_INFO, "Found ROM '%s', CRC %s", IniSections[i].name, szCRC);
1335             return i;
1336         }
1337     }
1338
1339     // Add new entry!!!
1340     section newsection;
1341
1342     if (PrintInfo)
1343         DebugMessage(M64MSG_INFO, "ROM (CRC %s) not found in INI file", szCRC);
1344
1345     strcpy(newsection.crccheck, (char*)szCRC);
1346
1347     strncpy(newsection.name, szName, 50);
1348     newsection.bDisableTextureCRC = FALSE;
1349     newsection.bDisableCulling = FALSE;
1350     newsection.bIncTexRectEdge = FALSE;
1351     newsection.bZHack = FALSE;
1352     newsection.bTextureScaleHack = FALSE;
1353     newsection.bFastLoadTile = FALSE;
1354     newsection.bUseSmallerTexture = FALSE;
1355     newsection.bPrimaryDepthHack = FALSE;
1356     newsection.bTexture1Hack = FALSE;
1357     newsection.bDisableObjBG = FALSE;
1358     newsection.VIWidth = -1;
1359     newsection.VIHeight = -1;
1360     newsection.UseCIWidthAndRatio = NOT_USE_CI_WIDTH_AND_RATIO;
1361     newsection.dwFullTMEM = 0;
1362     newsection.bTxtSizeMethod2 = FALSE;
1363     newsection.bEnableTxtLOD = FALSE;
1364
1365     newsection.bEmulateClear = FALSE;
1366     newsection.bForceScreenClear = FALSE;
1367     newsection.bDisableBlender = FALSE;
1368     newsection.bForceDepthBuffer = FALSE;
1369     newsection.dwFastTextureCRC = 0;
1370     newsection.dwAccurateTextureMapping = 0;
1371     newsection.dwNormalBlender = 0;
1372     newsection.dwNormalCombiner = 0;
1373     newsection.dwFrameBufferOption = 0;
1374     newsection.dwRenderToTextureOption = 0;
1375     newsection.dwScreenUpdateSetting = 0;
1376
1377     IniSections.push_back(newsection);
1378
1379     bIniIsChanged = true;               // Flag to indicate we should be updated
1380     return IniSections.size()-1;            // -1 takes into account increment
1381 }
1382
1383 GameSetting g_curRomInfo;
1384
1385 void ROM_GetRomNameFromHeader(unsigned char * szName, ROMHeader * pHdr)
1386 {
1387     unsigned char * p;
1388
1389     memcpy(szName, pHdr->szName, 20);
1390     szName[20] = '\0';
1391
1392     p = szName + (strlen((char*)szName) -1);        // -1 to skip null
1393     while (p >= szName && *p == ' ')
1394     {
1395         *p = 0;
1396         p--;
1397     }
1398 }
1399
1400 uint32 CountryCodeToTVSystem(uint32 countryCode)
1401 {
1402     uint32 system;
1403     switch(countryCode)
1404     {
1405         /* Demo */
1406     case 0:
1407         system = TV_SYSTEM_NTSC;
1408         break;
1409
1410     case '7':
1411         system = TV_SYSTEM_NTSC;
1412         break;
1413
1414     case 0x41:
1415         system = TV_SYSTEM_NTSC;
1416         break;
1417
1418         /* Germany */
1419     case 0x44:
1420         system = TV_SYSTEM_PAL;
1421         break;
1422
1423         /* USA */
1424     case 0x45:
1425         system = TV_SYSTEM_NTSC;
1426         break;
1427
1428         /* France */
1429     case 0x46:
1430         system = TV_SYSTEM_PAL;
1431         break;
1432
1433         /* Italy */
1434     case 'I':
1435         system = TV_SYSTEM_PAL;
1436         break;
1437
1438         /* Japan */
1439     case 0x4A:
1440         system = TV_SYSTEM_NTSC;
1441         break;
1442
1443         /* Europe - PAL */
1444     case 0x50:
1445         system = TV_SYSTEM_PAL;
1446         break;
1447
1448     case 'S':   /* Spain */
1449         system = TV_SYSTEM_PAL;
1450         break;
1451
1452         /* Australia */
1453     case 0x55:
1454         system = TV_SYSTEM_PAL;
1455         break;
1456
1457     case 0x58:
1458         system = TV_SYSTEM_PAL;
1459         break;
1460
1461         /* Australia */
1462     case 0x59:
1463         system = TV_SYSTEM_PAL;
1464         break;
1465
1466     case 0x20:
1467     case 0x21:
1468     case 0x38:
1469     case 0x70:
1470         system = TV_SYSTEM_PAL;
1471         break;
1472
1473         /* ??? */
1474     default:
1475         system = TV_SYSTEM_PAL;
1476         break;
1477     }
1478
1479     return system;
1480 }
1481
1482