added graphics settings section with more control (shadowLOD and libSilicon can be turned off)

This commit is contained in:
aomizu
2025-07-10 13:36:21 +09:00
parent 2766aee96f
commit 9fd6ca731c
8 changed files with 726 additions and 34 deletions

View File

@@ -157,6 +157,33 @@ func PatchTurtleWoW(myWindow fyne.Window, updateAllStatuses func()) {
needsWinerosettaUpdate := true
needsLibSiliconPatchUpdate := true
// Check user's preference for libSiliconPatch and shadowLOD
prefs, _ := utils.LoadPrefs()
// Enable by default unless user has explicitly disabled them
shouldEnableLibSiliconPatch := true
shouldEnableShadowLOD := true
// If user has manually disabled these settings, respect their choice
if prefs.UserDisabledLibSiliconPatch {
shouldEnableLibSiliconPatch = false
debug.Printf("libSiliconPatch disabled by user choice")
} else {
// Enable by default and update preferences
prefs.EnableLibSiliconPatch = true
}
if prefs.UserDisabledShadowLOD {
shouldEnableShadowLOD = false
debug.Printf("shadowLOD disabled by user choice")
} else {
// Enable by default and update preferences
prefs.SetShadowLOD0 = true
}
// Save updated preferences
utils.SavePrefs(prefs)
if fileContentBytes, err := os.ReadFile(dllsTextFile); err == nil {
fileContent := string(fileContentBytes)
if strings.Contains(fileContent, winerosettaEntry) {
@@ -168,7 +195,13 @@ func PatchTurtleWoW(myWindow fyne.Window, updateAllStatuses func()) {
needsLibSiliconPatchUpdate = false
}
} else {
debug.Printf("dlls.txt not found, will create a new one with both entries")
debug.Printf("dlls.txt not found, will create a new one")
}
// Only add libSiliconPatch if user wants it enabled
if !shouldEnableLibSiliconPatch {
needsLibSiliconPatchUpdate = false
debug.Printf("libSiliconPatch disabled by user preference, will not add to dlls.txt")
}
if needsWinerosettaUpdate || needsLibSiliconPatchUpdate {
@@ -196,7 +229,7 @@ func PatchTurtleWoW(myWindow fyne.Window, updateAllStatuses func()) {
debug.Printf("Adding %s to dlls.txt", winerosettaEntry)
}
}
if needsLibSiliconPatchUpdate {
if needsLibSiliconPatchUpdate && shouldEnableLibSiliconPatch {
if !strings.Contains(updatedContent, libSiliconPatchEntry+"\n") {
updatedContent += libSiliconPatchEntry + "\n"
debug.Printf("Adding %s to dlls.txt", libSiliconPatchEntry)
@@ -212,12 +245,33 @@ func PatchTurtleWoW(myWindow fyne.Window, updateAllStatuses func()) {
}
}
// Apply shadowLOD setting to Config.wtf for FPS optimization
if err := applyShadowLODSetting(); err != nil {
debug.Printf("Warning: failed to apply shadowLOD setting to Config.wtf: %v", err)
// If user has disabled libSiliconPatch, make sure it's removed from dlls.txt
if !shouldEnableLibSiliconPatch {
if err := disableLibSiliconPatchInDlls(); err != nil {
debug.Printf("Warning: failed to remove libSiliconPatch from dlls.txt: %v", err)
}
}
// Always apply vertex animation shaders setting to Config.wtf
if err := applyVertexAnimShadersSetting(); err != nil {
debug.Printf("Warning: failed to apply vertex animation shaders setting to Config.wtf: %v", err)
// Continue with patching even if Config.wtf update fails
}
// Apply shadowLOD setting to Config.wtf for FPS optimization
// Use shouldEnableShadowLOD which accounts for first-time patching
if shouldEnableShadowLOD {
if err := applyShadowLODSetting(); err != nil {
debug.Printf("Warning: failed to apply shadowLOD setting to Config.wtf: %v", err)
// Continue with patching even if Config.wtf update fails
}
} else {
// If user has disabled shadowLOD, make sure it's removed from Config.wtf
if err := removeShadowLODSetting(); err != nil {
debug.Printf("Warning: failed to remove shadowLOD setting from Config.wtf: %v", err)
}
}
debug.Println("TurtleWoW patching with bundled resources completed successfully.")
dialog.ShowInformation("Success", "TurtleWoW patching process completed using bundled resources.", myWindow)
updateAllStatuses()
@@ -356,10 +410,13 @@ func UnpatchTurtleWoW(myWindow fyne.Window, updateAllStatuses func()) {
}
}
// Remove shadowLOD setting from Config.wtf
if err := removeShadowLODSetting(); err != nil {
debug.Printf("Warning: failed to remove shadowLOD setting from Config.wtf: %v", err)
// Continue with unpatching even if Config.wtf update fails
// Remove shadowLOD setting from Config.wtf - only if it was applied via graphics settings
prefs, _ := utils.LoadPrefs()
if prefs.SetShadowLOD0 {
if err := removeShadowLODSetting(); err != nil {
debug.Printf("Warning: failed to remove shadowLOD setting from Config.wtf: %v", err)
// Continue with unpatching even if Config.wtf update fails
}
}
debug.Println("TurtleWoW unpatching completed successfully.")
@@ -458,6 +515,20 @@ func updateOrAddConfigSetting(configText, setting, value string) string {
return configText
}
// removeConfigSetting removes a setting from the config text
func removeConfigSetting(configText, setting string) string {
// Create regex pattern to match the setting
pattern := fmt.Sprintf(`SET\s+%s\s+"[^"]*"[\r\n]*`, regexp.QuoteMeta(setting))
re := regexp.MustCompile(pattern)
if re.MatchString(configText) {
configText = re.ReplaceAllString(configText, "")
debug.Printf("Removed setting %s from config", setting)
}
return configText
}
// CheckShadowLODSetting checks if the shadowLOD setting is correctly applied in Config.wtf
func CheckShadowLODSetting() bool {
if paths.TurtlewowPath == "" {
@@ -533,3 +604,325 @@ func removeShadowLODSetting() error {
return nil
}
// applyVertexAnimShadersSetting applies the vertex animation shaders setting to Config.wtf
func applyVertexAnimShadersSetting() error {
if paths.TurtlewowPath == "" {
return fmt.Errorf("TurtleWoW path not set")
}
configPath := filepath.Join(paths.TurtlewowPath, "WTF", "Config.wtf")
// Create WTF directory if it doesn't exist
wtfDir := filepath.Dir(configPath)
if err := os.MkdirAll(wtfDir, 0755); err != nil {
return fmt.Errorf("failed to create WTF directory: %v", err)
}
var configText string
// Read existing config if it exists
if content, err := os.ReadFile(configPath); err == nil {
configText = string(content)
} else {
debug.Printf("Config.wtf not found, creating new file")
configText = ""
}
// Apply vertex animation shaders setting
configText = updateOrAddConfigSetting(configText, "M2UseShaders", "1")
// Write the updated config back to file
if err := os.WriteFile(configPath, []byte(configText), 0644); err != nil {
return fmt.Errorf("failed to write Config.wtf: %v", err)
}
debug.Printf("Successfully applied vertex animation shaders setting to Config.wtf")
return nil
}
// ApplyGraphicsSettings applies the selected graphics settings to Config.wtf
func ApplyGraphicsSettings(myWindow fyne.Window) error {
prefs, err := utils.LoadPrefs()
if err != nil {
return fmt.Errorf("failed to load preferences: %v", err)
}
if paths.TurtlewowPath == "" {
return fmt.Errorf("TurtleWoW path not set")
}
configPath := filepath.Join(paths.TurtlewowPath, "WTF", "Config.wtf")
// Create WTF directory if it doesn't exist
wtfDir := filepath.Dir(configPath)
if err := os.MkdirAll(wtfDir, 0755); err != nil {
return fmt.Errorf("failed to create WTF directory: %v", err)
}
var configText string
// Read existing config if it exists
if content, err := os.ReadFile(configPath); err == nil {
configText = string(content)
} else {
debug.Printf("Config.wtf not found, creating new file")
configText = ""
}
// Apply or remove graphics settings based on user preferences
if prefs.ReduceTerrainDistance {
configText = updateOrAddConfigSetting(configText, "farclip", "177")
} else {
configText = removeConfigSetting(configText, "farclip")
}
if prefs.SetMultisampleTo2x {
configText = updateOrAddConfigSetting(configText, "gxMultisample", "2")
} else {
configText = removeConfigSetting(configText, "gxMultisample")
}
if prefs.SetShadowLOD0 {
configText = updateOrAddConfigSetting(configText, "shadowLOD", "0")
} else {
configText = removeConfigSetting(configText, "shadowLOD")
}
// Handle libSiliconPatch.dll in dlls.txt (only if DLL exists)
libSiliconPatchPath := filepath.Join(paths.TurtlewowPath, "libSiliconPatch.dll")
if utils.PathExists(libSiliconPatchPath) {
if prefs.EnableLibSiliconPatch {
if err := enableLibSiliconPatchInDlls(); err != nil {
debug.Printf("Warning: failed to enable libSiliconPatch in dlls.txt: %v", err)
}
} else {
if err := disableLibSiliconPatchInDlls(); err != nil {
debug.Printf("Warning: failed to disable libSiliconPatch in dlls.txt: %v", err)
}
}
}
// Write the updated config back to file
if err := os.WriteFile(configPath, []byte(configText), 0644); err != nil {
return fmt.Errorf("failed to write Config.wtf: %v", err)
}
debug.Printf("Successfully applied graphics settings to Config.wtf")
return nil
}
// CheckGraphicsSettings checks if the graphics settings are correctly applied in Config.wtf
func CheckGraphicsSettings() (bool, bool, bool) {
prefs, _ := utils.LoadPrefs()
if paths.TurtlewowPath == "" {
return false, false, false
}
configPath := filepath.Join(paths.TurtlewowPath, "WTF", "Config.wtf")
if _, err := os.Stat(configPath); os.IsNotExist(err) {
return false, false, false
}
content, err := os.ReadFile(configPath)
if err != nil {
return false, false, false
}
configText := string(content)
terrainCorrect := !prefs.ReduceTerrainDistance || isConfigSettingCorrect(configText, "farclip", "177")
multisampleCorrect := !prefs.SetMultisampleTo2x || isConfigSettingCorrect(configText, "gxMultisample", "2")
shadowCorrect := !prefs.SetShadowLOD0 || isConfigSettingCorrect(configText, "shadowLOD", "0")
return terrainCorrect, multisampleCorrect, shadowCorrect
}
// LoadGraphicsSettingsFromConfig reads Config.wtf and updates preferences with current settings
func LoadGraphicsSettingsFromConfig() error {
if paths.TurtlewowPath == "" {
return fmt.Errorf("TurtleWoW path not set")
}
configPath := filepath.Join(paths.TurtlewowPath, "WTF", "Config.wtf")
// If Config.wtf doesn't exist, nothing to load
if _, err := os.Stat(configPath); os.IsNotExist(err) {
debug.Printf("Config.wtf not found, using default graphics settings")
return nil
}
content, err := os.ReadFile(configPath)
if err != nil {
return fmt.Errorf("failed to read Config.wtf: %v", err)
}
configText := string(content)
// Load current preferences
prefs, err := utils.LoadPrefs()
if err != nil {
return fmt.Errorf("failed to load preferences: %v", err)
}
// Check each graphics setting and update preferences
prefs.ReduceTerrainDistance = isConfigSettingCorrect(configText, "farclip", "177")
prefs.SetMultisampleTo2x = isConfigSettingCorrect(configText, "gxMultisample", "2")
prefs.SetShadowLOD0 = isConfigSettingCorrect(configText, "shadowLOD", "0")
// Check libSiliconPatch status (DLL exists and enabled in dlls.txt)
libSiliconPatchPath := filepath.Join(paths.TurtlewowPath, "libSiliconPatch.dll")
dllsTextFile := filepath.Join(paths.TurtlewowPath, "dlls.txt")
libSiliconPatchExists := utils.PathExists(libSiliconPatchPath)
libSiliconPatchEnabled := false
if libSiliconPatchExists && utils.PathExists(dllsTextFile) {
if dllsContent, err := os.ReadFile(dllsTextFile); err == nil {
libSiliconPatchEnabled = strings.Contains(string(dllsContent), "libSiliconPatch.dll")
}
}
prefs.EnableLibSiliconPatch = libSiliconPatchExists && libSiliconPatchEnabled
// Save updated preferences
if err := utils.SavePrefs(prefs); err != nil {
return fmt.Errorf("failed to save preferences: %v", err)
}
debug.Printf("Loaded graphics settings from Config.wtf: terrain=%v, multisample=%v, shadow=%v, libSiliconPatch=%v",
prefs.ReduceTerrainDistance, prefs.SetMultisampleTo2x, prefs.SetShadowLOD0, prefs.EnableLibSiliconPatch)
return nil
}
// CheckGraphicsSettingsPresence checks if libSiliconPatch.dll exists and shadowLOD is applied, updates preferences accordingly
func CheckGraphicsSettingsPresence() {
if paths.TurtlewowPath == "" {
return
}
libSiliconPatchPath := filepath.Join(paths.TurtlewowPath, "libSiliconPatch.dll")
dllsTextFile := filepath.Join(paths.TurtlewowPath, "dlls.txt")
// Check if libSiliconPatch.dll exists
libSiliconPatchExists := utils.PathExists(libSiliconPatchPath)
// Check if it's enabled in dlls.txt
libSiliconPatchEnabled := false
if utils.PathExists(dllsTextFile) {
if fileContentBytes, err := os.ReadFile(dllsTextFile); err == nil {
fileContent := string(fileContentBytes)
libSiliconPatchEnabled = strings.Contains(fileContent, "libSiliconPatch.dll")
}
}
// Check if shadowLOD is currently applied
shadowLODApplied := CheckShadowLODSetting()
// Load current preferences
prefs, _ := utils.LoadPrefs()
// Handle libSiliconPatch preference detection
if libSiliconPatchExists {
if libSiliconPatchEnabled && !prefs.EnableLibSiliconPatch {
// DLL is currently enabled but user preference says disabled - likely first run detection
prefs.EnableLibSiliconPatch = true
debug.Printf("libSiliconPatch detected as enabled, setting user preference to enabled")
} else if !libSiliconPatchEnabled && prefs.EnableLibSiliconPatch {
// DLL exists but not enabled, user preference says enabled - respect user choice
debug.Printf("libSiliconPatch disabled in dlls.txt but user preference is enabled - keeping user preference")
}
}
// Handle shadowLOD preference detection - enable by default if currently applied
if shadowLODApplied && !prefs.SetShadowLOD0 {
// shadowLOD is currently applied but user preference says disabled - likely first run detection
prefs.SetShadowLOD0 = true
debug.Printf("shadowLOD detected as applied, setting user preference to enabled")
} else if !shadowLODApplied && prefs.SetShadowLOD0 {
// shadowLOD not applied but user preference says enabled - respect user choice
debug.Printf("shadowLOD not applied but user preference is enabled - keeping user preference")
}
// Save any changes
utils.SavePrefs(prefs)
debug.Printf("Graphics settings detection: libSiliconPatch exists=%v, enabled_in_dlls=%v, user_setting=%v; shadowLOD applied=%v, user_setting=%v",
libSiliconPatchExists, libSiliconPatchEnabled, prefs.EnableLibSiliconPatch, shadowLODApplied, prefs.SetShadowLOD0)
}
// enableLibSiliconPatchInDlls adds libSiliconPatch.dll to dlls.txt if not present
func enableLibSiliconPatchInDlls() error {
if paths.TurtlewowPath == "" {
return fmt.Errorf("TurtleWoW path not set")
}
dllsTextFile := filepath.Join(paths.TurtlewowPath, "dlls.txt")
libSiliconPatchEntry := "libSiliconPatch.dll"
var fileContentBytes []byte
var err error
if utils.PathExists(dllsTextFile) {
fileContentBytes, err = os.ReadFile(dllsTextFile)
if err != nil {
return fmt.Errorf("failed to read dlls.txt: %v", err)
}
}
currentContent := string(fileContentBytes)
if strings.Contains(currentContent, libSiliconPatchEntry) {
debug.Printf("libSiliconPatch.dll already present in dlls.txt")
return nil
}
// Add libSiliconPatch.dll to dlls.txt
if len(currentContent) > 0 && !strings.HasSuffix(currentContent, "\n") {
currentContent += "\n"
}
currentContent += libSiliconPatchEntry + "\n"
if err := os.WriteFile(dllsTextFile, []byte(currentContent), 0644); err != nil {
return fmt.Errorf("failed to update dlls.txt: %v", err)
}
debug.Printf("Added libSiliconPatch.dll to dlls.txt")
return nil
}
// disableLibSiliconPatchInDlls removes libSiliconPatch.dll from dlls.txt
func disableLibSiliconPatchInDlls() error {
if paths.TurtlewowPath == "" {
return fmt.Errorf("TurtleWoW path not set")
}
dllsTextFile := filepath.Join(paths.TurtlewowPath, "dlls.txt")
if !utils.PathExists(dllsTextFile) {
debug.Printf("dlls.txt not found, nothing to remove")
return nil
}
content, err := os.ReadFile(dllsTextFile)
if err != nil {
return fmt.Errorf("failed to read dlls.txt: %v", err)
}
lines := strings.Split(string(content), "\n")
filteredLines := make([]string, 0, len(lines))
for _, line := range lines {
trimmedLine := strings.TrimSpace(line)
if trimmedLine != "libSiliconPatch.dll" {
filteredLines = append(filteredLines, line)
}
}
updatedContent := strings.Join(filteredLines, "\n")
if err := os.WriteFile(dllsTextFile, []byte(updatedContent), 0644); err != nil {
return fmt.Errorf("failed to update dlls.txt: %v", err)
}
debug.Printf("Removed libSiliconPatch.dll from dlls.txt")
return nil
}

View File

@@ -73,7 +73,7 @@ func createOptionsComponents() {
debug.Printf("Successfully applied recommended settings")
// Show success dialog if we have a window reference
if currentWindow != nil {
dialog.ShowInformation("Success", "Recommended graphics settings have been applied to Config.wtf", currentWindow)
dialog.ShowInformation("Success", "Recommended graphics settings have been applied", currentWindow)
}
// Update button state
updateRecommendedSettingsButton()
@@ -92,6 +92,9 @@ func createOptionsComponents() {
// Create Wine registry Option-as-Alt buttons and status
createWineRegistryComponents()
// Create graphics settings components
createGraphicsSettingsComponents()
// Load environment variables from preferences
if prefs.EnvironmentVariables != "" {
launcher.CustomEnvVars = prefs.EnvironmentVariables
@@ -476,3 +479,187 @@ func showRecommendedSettingsHelpPopup() {
helpPopup.Show()
}
// createGraphicsSettingsComponents creates all graphics settings checkboxes and buttons
func createGraphicsSettingsComponents() {
// Load preferences for initial values
prefs, _ := utils.LoadPrefs()
// Create Reduce Terrain Distance setting with help button
reduceTerrainDistanceCheckbox = widget.NewCheck("", func(checked bool) {
prefs, _ := utils.LoadPrefs()
prefs.ReduceTerrainDistance = checked
utils.SavePrefs(prefs)
debug.Printf("Reduce terrain distance: %v", checked)
updateApplyGraphicsSettingsButton()
})
reduceTerrainDistanceCheckbox.SetChecked(prefs.ReduceTerrainDistance)
reduceTerrainDistanceHelpButton = widget.NewButton("?", func() {
showGraphicsSettingHelpPopup("Reduce Terrain Distance", "Sets the draw distance to the lowest setting. This will drastically increase your FPS", "High Performance Impact")
})
reduceTerrainDistanceHelpButton.Importance = widget.MediumImportance
// Create Set Multisample to 2x setting with help button
setMultisampleTo2xCheckbox = widget.NewCheck("", func(checked bool) {
prefs, _ := utils.LoadPrefs()
prefs.SetMultisampleTo2x = checked
utils.SavePrefs(prefs)
debug.Printf("Set multisample to 2x: %v", checked)
updateApplyGraphicsSettingsButton()
})
setMultisampleTo2xCheckbox.SetChecked(prefs.SetMultisampleTo2x)
setMultisampleTo2xHelpButton = widget.NewButton("?", func() {
showGraphicsSettingHelpPopup("Set Multisample to 2x", "Might reduce your FPS slightly on lower end machines, but makes sure the portraits load properly.", "Medium Performance Impact")
})
setMultisampleTo2xHelpButton.Importance = widget.MediumImportance
// Create Set Shadow LOD to 0 setting with help button
setShadowLOD0Checkbox = widget.NewCheck("", func(checked bool) {
prefs, _ := utils.LoadPrefs()
prefs.SetShadowLOD0 = checked
// Track if user manually disabled this setting
if !checked {
prefs.UserDisabledShadowLOD = true
} else {
prefs.UserDisabledShadowLOD = false
}
utils.SavePrefs(prefs)
debug.Printf("Set shadow LOD to 0: %v (user manually changed)", checked)
updateApplyGraphicsSettingsButton()
})
setShadowLOD0Checkbox.SetChecked(prefs.SetShadowLOD0)
setShadowLOD0HelpButton = widget.NewButton("?", func() {
showGraphicsSettingHelpPopup("Set Shadow LOD to 0", "Turns off all shadows. This will give you ~10% more FPS.", "High Performance Impact")
})
setShadowLOD0HelpButton.Importance = widget.MediumImportance
// Create Enable libSiliconPatch setting with help button
libSiliconPatchCheckbox = widget.NewCheck("", func(checked bool) {
prefs, _ := utils.LoadPrefs()
prefs.EnableLibSiliconPatch = checked
// Track if user manually disabled this setting
if !checked {
prefs.UserDisabledLibSiliconPatch = true
} else {
prefs.UserDisabledLibSiliconPatch = false
}
utils.SavePrefs(prefs)
debug.Printf("Enable libSiliconPatch: %v (user manually changed)", checked)
updateApplyGraphicsSettingsButton()
})
libSiliconPatchCheckbox.SetChecked(prefs.EnableLibSiliconPatch)
libSiliconPatchHelpButton = widget.NewButton("?", func() {
showGraphicsSettingHelpPopup("Enable libSiliconPatch", "Hooks into the WoW process and replaces slow X87 instructions with SSE2 instructions that Rosetta can translate much quicker, resulting in an increase in FPS (2x or more). May potentially cause graphical bugs.", "Very High Performance Impact")
})
libSiliconPatchHelpButton.Importance = widget.MediumImportance
applyGraphicsSettingsButton = widget.NewButton("Apply Graphics Settings", func() {
err := patching.ApplyGraphicsSettings(currentWindow)
if err != nil {
debug.Printf("Failed to apply graphics settings: %v", err)
if currentWindow != nil {
dialog.ShowError(fmt.Errorf("failed to apply graphics settings: %v", err), currentWindow)
}
} else {
debug.Printf("Successfully applied graphics settings")
if currentWindow != nil {
dialog.ShowInformation("Success", "Graphics settings have been applied", currentWindow)
}
// Refresh checkboxes to reflect current state
refreshGraphicsSettingsCheckboxes()
}
})
applyGraphicsSettingsButton.Importance = widget.MediumImportance
// Initialize button state
updateApplyGraphicsSettingsButton()
}
// updateApplyGraphicsSettingsButton updates the state of the apply graphics settings button
func updateApplyGraphicsSettingsButton() {
if applyGraphicsSettingsButton == nil {
return
}
// Always enable the button since we need to handle both adding and removing settings
applyGraphicsSettingsButton.Enable()
applyGraphicsSettingsButton.SetText("Apply Changes")
}
// refreshGraphicsSettingsCheckboxes updates the checkbox states from current preferences
func refreshGraphicsSettingsCheckboxes() {
prefs, _ := utils.LoadPrefs()
if reduceTerrainDistanceCheckbox != nil {
reduceTerrainDistanceCheckbox.SetChecked(prefs.ReduceTerrainDistance)
}
if setMultisampleTo2xCheckbox != nil {
setMultisampleTo2xCheckbox.SetChecked(prefs.SetMultisampleTo2x)
}
if setShadowLOD0Checkbox != nil {
setShadowLOD0Checkbox.SetChecked(prefs.SetShadowLOD0)
}
if libSiliconPatchCheckbox != nil {
libSiliconPatchCheckbox.SetChecked(prefs.EnableLibSiliconPatch)
}
// Update the apply button state
updateApplyGraphicsSettingsButton()
}
// showGraphicsSettingHelpPopup shows a help popup for a specific graphics setting
func showGraphicsSettingHelpPopup(title, description, impact string) {
if currentWindow == nil {
return
}
// Create help content
helpTitle := widget.NewRichTextFromMarkdown("# " + title)
descriptionLabel := widget.NewLabel(description)
descriptionLabel.Wrapping = fyne.TextWrapWord
impactLabel := widget.NewLabel(impact)
impactLabel.TextStyle = fyne.TextStyle{Bold: true}
// Create OK button
okButton := widget.NewButton("OK", func() {
// This will be set when the popup is created
})
okButton.Importance = widget.MediumImportance
// Create help content container
helpContentContainer := container.NewVBox(
container.NewCenter(helpTitle),
widget.NewSeparator(),
descriptionLabel,
widget.NewSeparator(),
impactLabel,
widget.NewSeparator(),
container.NewCenter(okButton),
)
// Calculate popup size
windowSize := currentWindow.Content().Size()
popupWidth := windowSize.Width * 2 / 3
popupHeight := windowSize.Height / 2
// Create the help popup
helpPopup := widget.NewModalPopUp(container.NewPadded(helpContentContainer), currentWindow.Canvas())
helpPopup.Resize(fyne.NewSize(popupWidth, popupHeight))
// Set the OK button action to hide the help popup
okButton.OnTapped = func() {
helpPopup.Hide()
}
helpPopup.Show()
}

View File

@@ -13,6 +13,8 @@ import (
"howett.net/plist"
"turtlesilicon/pkg/debug"
"turtlesilicon/pkg/patching"
"turtlesilicon/pkg/paths"
"turtlesilicon/pkg/utils"
)
@@ -23,25 +25,84 @@ func showOptionsPopup() {
return
}
// Create options content with better organization and smaller titles
optionsTitle := widget.NewLabel("Options")
optionsTitle.TextStyle = fyne.TextStyle{Bold: true}
// Create label for recommended settings
recommendedSettingsLabel := widget.NewLabel("Graphics settings:")
// Check graphics settings presence and update preferences before showing UI
patching.CheckGraphicsSettingsPresence()
gameOptionsContainer := container.NewVBox(
optionsTitle,
// Load graphics settings from Config.wtf and update preferences
if err := patching.LoadGraphicsSettingsFromConfig(); err != nil {
debug.Printf("Warning: failed to load graphics settings from Config.wtf: %v", err)
}
// Refresh checkbox states to reflect current settings
refreshGraphicsSettingsCheckboxes()
// Create General tab content
generalTitle := widget.NewLabel("General Settings")
generalTitle.TextStyle = fyne.TextStyle{Bold: true}
generalContainer := container.NewVBox(
generalTitle,
widget.NewSeparator(),
metalHudCheckbox,
showTerminalCheckbox,
vanillaTweaksCheckbox,
autoDeleteWdbCheckbox,
widget.NewSeparator(),
container.NewBorder(nil, nil, recommendedSettingsLabel, container.NewHBox(applyRecommendedSettingsButton, recommendedSettingsHelpButton), nil),
widget.NewSeparator(),
container.NewBorder(nil, nil, nil, container.NewHBox(enableOptionAsAltButton, disableOptionAsAltButton), optionAsAltStatusLabel),
)
// Create Graphics tab content
graphicsTitle := widget.NewLabel("Graphics Settings")
graphicsTitle.TextStyle = fyne.TextStyle{Bold: true}
graphicsDescription := widget.NewLabel("Select graphics settings to apply to Config.wtf:")
graphicsDescription.TextStyle = fyne.TextStyle{Italic: true}
// Create bold text labels for each setting
terrainLabel := widget.NewLabel("Reduce Terrain Distance")
terrainLabel.TextStyle = fyne.TextStyle{Bold: true}
multisampleLabel := widget.NewLabel("Set Multisample to 2x")
multisampleLabel.TextStyle = fyne.TextStyle{Bold: true}
shadowLabel := widget.NewLabel("Set Shadow LOD to 0")
shadowLabel.TextStyle = fyne.TextStyle{Bold: true}
libSiliconPatchLabel := widget.NewLabel("Enable libSiliconPatch")
libSiliconPatchLabel.TextStyle = fyne.TextStyle{Bold: true}
// Create setting rows with help buttons between checkbox and label
terrainRow := container.NewHBox(
reduceTerrainDistanceCheckbox,
reduceTerrainDistanceHelpButton,
terrainLabel)
multisampleRow := container.NewHBox(
setMultisampleTo2xCheckbox,
setMultisampleTo2xHelpButton,
multisampleLabel)
shadowRow := container.NewHBox(
setShadowLOD0Checkbox,
setShadowLOD0HelpButton,
shadowLabel)
libSiliconPatchRow := container.NewHBox(
libSiliconPatchCheckbox,
libSiliconPatchHelpButton,
libSiliconPatchLabel)
graphicsContainer := container.NewVBox(
graphicsTitle,
widget.NewSeparator(),
graphicsDescription,
widget.NewSeparator(),
terrainRow,
multisampleRow,
shadowRow,
libSiliconPatchRow,
widget.NewSeparator(),
container.NewCenter(applyGraphicsSettingsButton),
)
// Create Environment Variables tab content
envVarsTitle := widget.NewLabel("Environment Variables")
envVarsTitle.TextStyle = fyne.TextStyle{Bold: true}
envVarsContainer := container.NewVBox(
@@ -50,13 +111,15 @@ func showOptionsPopup() {
envVarsEntry,
)
// Create a scrollable container for all options
optionsContent := container.NewVBox(
gameOptionsContainer,
envVarsContainer,
// Create tabs
tabs := container.NewAppTabs(
container.NewTabItem("General", container.NewScroll(generalContainer)),
container.NewTabItem("Graphics", container.NewScroll(graphicsContainer)),
container.NewTabItem("Environment", container.NewScroll(envVarsContainer)),
)
scrollContainer := container.NewScroll(optionsContent)
// Set tab location to top
tabs.SetTabLocation(container.TabLocationTop)
// Create close button
closeButton := widget.NewButton("Close", func() {
@@ -65,11 +128,11 @@ func showOptionsPopup() {
// Create the popup content with close button
popupContent := container.NewBorder(
nil, // top
container.NewCenter(closeButton), // bottom
nil, // left
nil, // right
container.NewPadded(scrollContainer), // center
nil, // top
container.NewCenter(closeButton), // bottom
nil, // left
nil, // right
container.NewPadded(tabs), // center
)
// Get the window size and calculate 2/3 size

View File

@@ -97,7 +97,15 @@ func updateTurtleWoWStatus() {
if utils.PathExists(dllsTextFile) {
if fileContent, err := os.ReadFile(dllsTextFile); err == nil {
contentStr := string(fileContent)
if strings.Contains(contentStr, "winerosetta.dll") && strings.Contains(contentStr, "libSiliconPatch.dll") {
winerosettaPresent := strings.Contains(contentStr, "winerosetta.dll")
// Check if libSiliconPatch should be present based on user preference
prefs, _ := utils.LoadPrefs()
libSiliconPatchRequired := prefs.EnableLibSiliconPatch
libSiliconPatchPresent := strings.Contains(contentStr, "libSiliconPatch.dll")
// Validate dlls.txt: winerosetta must be present, libSiliconPatch based on setting
if winerosettaPresent && (!libSiliconPatchRequired || libSiliconPatchPresent) {
dllsFileValid = true
}
}
@@ -110,14 +118,18 @@ func updateTurtleWoWStatus() {
rosettaX87CorrectSize := utils.CompareFileWithBundledResource(rosettaX87ExePath, "rosettax87/rosettax87")
libRuntimeRosettaX87CorrectSize := utils.CompareFileWithBundledResource(libRuntimeRosettaX87Path, "rosettax87/libRuntimeRosettax87")
// Check if shadowLOD setting is applied
shadowLODApplied := patching.CheckShadowLODSetting()
// Check if shadowLOD setting is applied (only if user has enabled it in graphics settings)
prefs, _ := utils.LoadPrefs()
shadowLODRequiredAndApplied := true // Default to true if not required
if prefs.SetShadowLOD0 {
shadowLODRequiredAndApplied = patching.CheckShadowLODSetting()
}
if utils.PathExists(winerosettaDllPath) && utils.PathExists(d3d9DllPath) && utils.PathExists(libSiliconPatchDllPath) &&
utils.DirExists(rosettaX87DirPath) && utils.PathExists(rosettaX87ExePath) &&
utils.PathExists(libRuntimeRosettaX87Path) && dllsFileValid &&
winerosettaDllCorrectSize && d3d9DllCorrectSize && libSiliconPatchCorrectSize &&
rosettaX87CorrectSize && libRuntimeRosettaX87CorrectSize && shadowLODApplied {
rosettaX87CorrectSize && libRuntimeRosettaX87CorrectSize && shadowLODRequiredAndApplied {
paths.PatchesAppliedTurtleWoW = true
}
}

View File

@@ -1,7 +1,9 @@
package ui
import (
"turtlesilicon/pkg/debug"
"turtlesilicon/pkg/paths"
"turtlesilicon/pkg/patching"
"turtlesilicon/pkg/utils"
"fyne.io/fyne/v2"
@@ -35,6 +37,18 @@ func CreateUI(myWindow fyne.Window) fyne.CanvasObject {
// Check default CrossOver path
paths.CheckDefaultCrossOverPath()
// Check graphics settings presence and set default state
patching.CheckGraphicsSettingsPresence()
// Load graphics settings from Config.wtf and update UI
if err := patching.LoadGraphicsSettingsFromConfig(); err != nil {
// Log error but continue - this is not critical for app startup
debug.Printf("Warning: failed to load graphics settings from Config.wtf: %v", err)
} else {
// Refresh checkbox states to reflect loaded settings
refreshGraphicsSettingsCheckboxes()
}
// Create header, main content and bottom bar
headerContent := createHeaderContainer()
mainContent := createMainContent(myWindow)

View File

@@ -45,6 +45,19 @@ var (
// Environment variables entry
envVarsEntry *widget.Entry
// Graphics settings checkboxes
reduceTerrainDistanceCheckbox *widget.Check
setMultisampleTo2xCheckbox *widget.Check
setShadowLOD0Checkbox *widget.Check
libSiliconPatchCheckbox *widget.Check
applyGraphicsSettingsButton *widget.Button
// Graphics settings help buttons
reduceTerrainDistanceHelpButton *widget.Button
setMultisampleTo2xHelpButton *widget.Button
setShadowLOD0HelpButton *widget.Button
libSiliconPatchHelpButton *widget.Button
// Window reference for popup functionality
currentWindow fyne.Window

View File

@@ -16,6 +16,16 @@ type UserPrefs struct {
EnableVanillaTweaks bool `json:"enable_vanilla_tweaks"`
RemapOptionAsAlt bool `json:"remap_option_as_alt"`
AutoDeleteWdb bool `json:"auto_delete_wdb"`
// Graphics settings
ReduceTerrainDistance bool `json:"reduce_terrain_distance"`
SetMultisampleTo2x bool `json:"set_multisample_to_2x"`
SetShadowLOD0 bool `json:"set_shadow_lod_0"`
EnableLibSiliconPatch bool `json:"enable_lib_silicon_patch"`
// Tracking whether user has manually disabled these settings
UserDisabledShadowLOD bool `json:"user_disabled_shadow_lod"`
UserDisabledLibSiliconPatch bool `json:"user_disabled_lib_silicon_patch"`
}
func getPrefsPath() (string, error) {