2019-09-18 16:11:37 +00:00
|
|
|
/*****************************************************************************\
|
|
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
This file is licensed under the Snes9x License.
|
|
|
|
For further information, consult the LICENSE file in the root directory.
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
2018-05-24 16:12:35 +00:00
|
|
|
#include "CShaderParamDlg.h"
|
|
|
|
#include "wsnes9x.h"
|
|
|
|
#include "display.h"
|
|
|
|
#include "win32_display.h"
|
2018-05-25 20:24:32 +00:00
|
|
|
#include <CommCtrl.h>
|
2018-05-24 16:12:35 +00:00
|
|
|
|
2018-05-25 20:24:32 +00:00
|
|
|
#define IDC_PARAMS_START_STATIC 5000
|
|
|
|
#define IDC_PARAMS_START_EDIT 5500
|
|
|
|
#define IDC_PARAMS_START_UPDOWN 6000
|
2018-05-24 16:12:35 +00:00
|
|
|
|
|
|
|
INT_PTR CALLBACK CShaderParamDlg::DlgShaderParams(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
CShaderParamDlg* dlg = (CShaderParamDlg*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
|
|
switch(msg)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
|
|
|
|
dlg = (CShaderParamDlg*)lParam;
|
|
|
|
dlg->createContent(hDlg);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch(LOWORD(wParam))
|
|
|
|
{
|
|
|
|
case IDCANCEL:
|
|
|
|
if(HIWORD(wParam) == BN_CLICKED) {
|
|
|
|
EndDialog(hDlg, IDCANCEL);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IDOK:
|
|
|
|
if(HIWORD(wParam) == BN_CLICKED) {
|
|
|
|
dlg->get_changed_parameters(hDlg);
|
|
|
|
EndDialog(hDlg, IDOK);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
case IDAPPLY:
|
|
|
|
if(HIWORD(wParam) == BN_CLICKED) {
|
2018-05-25 20:24:32 +00:00
|
|
|
dlg->apply_changes(hDlg);
|
2018-05-24 16:12:35 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case WM_VSCROLL:
|
|
|
|
{
|
|
|
|
short sbCode = LOWORD(wParam);
|
|
|
|
SCROLLINFO si = { 0 };
|
|
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
|
|
si.fMask = SIF_ALL;
|
|
|
|
GetScrollInfo((HWND)lParam, SB_CTL, &si);
|
|
|
|
int delta = 0;
|
|
|
|
int maxPos = si.nMax - si.nPage;
|
|
|
|
switch(sbCode) {
|
|
|
|
case SB_LINEDOWN:
|
|
|
|
if(dlg->scrollpos >= maxPos)
|
|
|
|
break;
|
|
|
|
|
|
|
|
delta = min(max(maxPos / 20, 5), maxPos - dlg->scrollpos);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SB_LINEUP:
|
|
|
|
if(dlg->scrollpos <= 0)
|
|
|
|
break;
|
|
|
|
delta = -min(max(maxPos / 20, 5), dlg->scrollpos);
|
|
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
|
|
if(dlg->scrollpos >= maxPos)
|
|
|
|
break;
|
|
|
|
delta = min(si.nPage, maxPos - dlg->scrollpos);
|
|
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
|
|
delta = (int)si.nTrackPos - dlg->scrollpos;
|
|
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
|
|
delta = (int)si.nPos - dlg->scrollpos;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SB_PAGEUP:
|
|
|
|
if(dlg->scrollpos <= 0)
|
|
|
|
break;
|
|
|
|
delta = -min((INT)si.nPage, dlg->scrollpos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dlg->scrollpos += delta;
|
|
|
|
HWND hContainer = GetDlgItem(hDlg, IDC_STATIC_CONTAINER);
|
|
|
|
RECT clientRect;
|
|
|
|
GetClientRect(hContainer, &clientRect);
|
|
|
|
ScrollWindow(hContainer, 0, -delta, NULL, &clientRect);
|
|
|
|
SetScrollPos((HWND)lParam, SB_CTL, dlg->scrollpos, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-05-25 20:24:32 +00:00
|
|
|
INT_PTR CALLBACK CShaderParamDlg::WndProcContainerStatic(HWND hStatic, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
CShaderParamDlg* dlg = (CShaderParamDlg*)GetWindowLongPtr(hStatic, GWLP_USERDATA);
|
|
|
|
switch (msg)
|
|
|
|
{
|
|
|
|
case WM_NOTIFY:
|
|
|
|
UINT nCode = ((LPNMHDR)lParam)->code;
|
|
|
|
switch (nCode)
|
|
|
|
{
|
|
|
|
case UDN_DELTAPOS:
|
|
|
|
LPNMUPDOWN lpnmud = (LPNMUPDOWN)lParam;
|
|
|
|
dlg->handle_up_down(hStatic, lpnmud->hdr.idFrom, lpnmud->iDelta);
|
|
|
|
dlg->apply_changes(GetParent(hStatic));
|
|
|
|
return TRUE; // return true so the up/down pos does not change
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dlg->oldStaticProc(hStatic, msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
2023-02-01 20:47:42 +00:00
|
|
|
CShaderParamDlg::CShaderParamDlg(std::vector<GLSLParam>& parameters_, std::function<void (const char *)> save_function_)
|
|
|
|
: parameters(parameters_),
|
|
|
|
save_function(save_function_)
|
2018-05-24 16:12:35 +00:00
|
|
|
{
|
|
|
|
HDC hIC;
|
|
|
|
TEXTMETRIC tm;
|
|
|
|
LOGFONT lf;
|
|
|
|
|
|
|
|
OSVERSIONINFO ovi;
|
|
|
|
|
|
|
|
ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
GetVersionEx(&ovi);
|
|
|
|
|
|
|
|
hIC = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL); // information context
|
|
|
|
|
|
|
|
lf.lfHeight = (LONG)ceil(((-8.0f) * (FLOAT)GetDeviceCaps(hIC, LOGPIXELSY) / 72.0f) - 0.5f);
|
|
|
|
lf.lfWidth = 0;
|
|
|
|
lf.lfEscapement = 0;
|
|
|
|
lf.lfOrientation = 0;
|
|
|
|
lf.lfWeight = FW_DONTCARE; //default weight
|
|
|
|
lf.lfItalic = FALSE;
|
|
|
|
lf.lfUnderline = FALSE;
|
|
|
|
lf.lfStrikeOut = FALSE;
|
|
|
|
lf.lfCharSet = DEFAULT_CHARSET;
|
|
|
|
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
|
|
lf.lfQuality = DEFAULT_QUALITY;
|
|
|
|
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
|
|
|
if(ovi.dwMajorVersion >= 6) //Vista
|
|
|
|
lstrcpy(lf.lfFaceName, TEXT("Segoe UI"));
|
|
|
|
else if(ovi.dwMajorVersion >= 5) //2000 - Vista
|
|
|
|
lstrcpy(lf.lfFaceName, TEXT("MS Shell Dlg 2"));
|
|
|
|
else
|
|
|
|
lstrcpy(lf.lfFaceName, TEXT("MS Shell Dlg"));
|
|
|
|
|
|
|
|
hFont = CreateFontIndirect(&lf);
|
|
|
|
|
|
|
|
SelectObject(hIC, hFont);
|
|
|
|
GetTextMetrics(hIC, &tm);
|
|
|
|
|
|
|
|
avgCharWidth = tm.tmAveCharWidth;
|
|
|
|
avgCharHeight = tm.tmHeight;
|
|
|
|
|
|
|
|
DeleteDC(hIC);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CShaderParamDlg::~CShaderParamDlg()
|
|
|
|
{
|
|
|
|
if(hFont)
|
|
|
|
DeleteFont(hFont);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CShaderParamDlg::show()
|
|
|
|
{
|
2023-02-01 20:47:42 +00:00
|
|
|
saved_parameters = parameters;
|
2019-02-03 01:08:19 +00:00
|
|
|
|
2018-05-24 16:12:35 +00:00
|
|
|
if(DialogBoxParam(GUI.hInstance, MAKEINTRESOURCE(IDD_DIALOG_SHADER_PARAMS), GUI.hWnd, DlgShaderParams, (LPARAM)this) == IDOK)
|
|
|
|
{
|
|
|
|
save_custom_shader();
|
|
|
|
return true;
|
|
|
|
}
|
2019-02-03 01:08:19 +00:00
|
|
|
|
2023-02-01 20:47:42 +00:00
|
|
|
parameters = saved_parameters;
|
2019-02-03 01:08:19 +00:00
|
|
|
WinRefreshDisplay();
|
2018-05-24 16:12:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CShaderParamDlg::createContent(HWND hDlg)
|
|
|
|
{
|
|
|
|
HWND parent = GetDlgItem(hDlg, IDC_STATIC_CONTAINER);
|
2018-05-25 20:24:32 +00:00
|
|
|
// override static wndproc so we can handle the up/down messages, save original proc so we can forward everything else
|
|
|
|
oldStaticProc = (WNDPROC)GetWindowLongPtr(parent, GWLP_WNDPROC);
|
|
|
|
SetWindowLongPtr(parent, GWLP_WNDPROC, (LONG_PTR)WndProcContainerStatic);
|
|
|
|
SetWindowLongPtr(parent, GWLP_USERDATA, (LONG_PTR)this);
|
2018-05-24 16:12:35 +00:00
|
|
|
|
2019-02-03 01:08:19 +00:00
|
|
|
RECT clientRect;
|
|
|
|
GetClientRect(parent, &clientRect);
|
|
|
|
|
|
|
|
const int HORIZONTAL_MARGIN = 10;
|
|
|
|
const int VERTICAL_MARGIN = 10;
|
|
|
|
const int HORIZONTAL_SPACE = 20;
|
|
|
|
const int VERTICAL_SPACE = 5;
|
|
|
|
|
|
|
|
unsigned int desc_left = HORIZONTAL_MARGIN;
|
|
|
|
unsigned int desc_width = (clientRect.right - clientRect.left) * 3 / 4 - desc_left - HORIZONTAL_SPACE / 2;
|
|
|
|
unsigned int edit_left = desc_left + desc_width + HORIZONTAL_SPACE;
|
|
|
|
unsigned int edit_width = clientRect.right - clientRect.left - edit_left - HORIZONTAL_MARGIN;
|
|
|
|
unsigned int top = VERTICAL_MARGIN;
|
|
|
|
|
2023-02-01 20:47:42 +00:00
|
|
|
for(int i = 0; i < parameters.size(); i++) {
|
|
|
|
GLSLParam &p = parameters[i];
|
2018-05-24 16:12:35 +00:00
|
|
|
TCHAR desc[270];
|
2023-01-26 23:06:45 +00:00
|
|
|
_stprintf(desc, TEXT("%s [%g-%g]"), (TCHAR*)_tFromChar(p.name.c_str()), p.min, p.max);
|
2019-02-03 01:08:19 +00:00
|
|
|
HWND item = CreateWindow(TEXT("STATIC"), desc, SS_LEFTNOWORDWRAP | WS_VISIBLE | WS_CHILD, desc_left, (INT)(top + avgCharHeight * 0.3), desc_width, avgCharHeight, parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_STATIC + i), GUI.hInstance, NULL);
|
2018-05-24 16:12:35 +00:00
|
|
|
SendMessage(item, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(FALSE, 0));
|
|
|
|
TCHAR val[100];
|
|
|
|
_stprintf(val, TEXT("%g"), p.val);
|
2019-02-03 01:08:19 +00:00
|
|
|
item = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), val, ES_AUTOHSCROLL | WS_VISIBLE | WS_CHILD | WS_TABSTOP, edit_left , top, edit_width, (INT)(avgCharHeight * 1.7), parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_EDIT + i), GUI.hInstance, NULL);
|
2018-05-24 16:12:35 +00:00
|
|
|
SendMessage(item, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(FALSE, 0));
|
2018-05-25 20:24:32 +00:00
|
|
|
|
|
|
|
item = CreateWindow(UPDOWN_CLASS, NULL, WS_CHILDWINDOW | WS_VISIBLE | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_HOTTRACK, 0, 0, 0, 0, parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_UPDOWN + i), GUI.hInstance, NULL);
|
|
|
|
SendMessage(item, UDM_SETRANGE, 0, MAKELONG(10, -10)); // we don't use this range, simply set it so the up arrow is positive and down arrow negative
|
|
|
|
|
2019-02-03 01:08:19 +00:00
|
|
|
top += (INT)(avgCharHeight * 1.7 + VERTICAL_SPACE);
|
2018-05-24 16:12:35 +00:00
|
|
|
}
|
|
|
|
|
2019-02-03 01:08:19 +00:00
|
|
|
RECT windowRect;
|
2018-05-24 16:12:35 +00:00
|
|
|
GetClientRect(parent, &clientRect);
|
|
|
|
HWND scrollbar = GetDlgItem(hDlg,IDC_SCROLLBAR_PARAMS);
|
|
|
|
SCROLLINFO si = { 0 };
|
|
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
|
|
si.fMask = SIF_RANGE | SIF_PAGE;
|
|
|
|
si.nMin = 0;
|
|
|
|
si.nMax = top;
|
|
|
|
si.nPage = clientRect.bottom;
|
|
|
|
si.nPos = 0;
|
|
|
|
scrollpos = 0;
|
|
|
|
SetScrollInfo(scrollbar, SB_CTL, &si, TRUE);
|
|
|
|
}
|
|
|
|
|
2018-05-25 20:24:32 +00:00
|
|
|
void CShaderParamDlg::handle_up_down(HWND hStatic, int id, int change)
|
|
|
|
{
|
|
|
|
int param_id = id - IDC_PARAMS_START_UPDOWN;
|
|
|
|
HWND hEdit = GetDlgItem(hStatic, IDC_PARAMS_START_EDIT + param_id);
|
2023-02-01 20:47:42 +00:00
|
|
|
GLSLParam &p = parameters[param_id];
|
2018-05-25 20:24:32 +00:00
|
|
|
TCHAR val[100];
|
|
|
|
GetWindowText(hEdit, val, 100);
|
|
|
|
p.val = _ttof(val);
|
|
|
|
p.val += change > 0 ? p.step : -p.step;
|
|
|
|
if (p.val < p.min)
|
|
|
|
p.val = p.min;
|
|
|
|
if (p.val > p.max)
|
|
|
|
p.val = p.max;
|
|
|
|
_stprintf(val, TEXT("%g"), p.val);
|
|
|
|
SetWindowText(hEdit, val);
|
|
|
|
}
|
|
|
|
|
2018-05-24 16:12:35 +00:00
|
|
|
void CShaderParamDlg::get_changed_parameters(HWND hDlg)
|
|
|
|
{
|
|
|
|
HWND parent = GetDlgItem(hDlg, IDC_STATIC_CONTAINER);
|
2023-02-01 20:47:42 +00:00
|
|
|
for(int i = 0; i < parameters.size(); i++) {
|
|
|
|
GLSLParam &p = parameters[i];
|
2018-05-24 16:12:35 +00:00
|
|
|
TCHAR val[100];
|
|
|
|
HWND hEdit = GetDlgItem(parent, IDC_PARAMS_START_EDIT + i);
|
|
|
|
GetWindowText(hEdit, val, 100);
|
|
|
|
p.val = _ttof(val);
|
|
|
|
if(p.val < p.min)
|
|
|
|
p.val = p.min;
|
|
|
|
if(p.val > p.max)
|
|
|
|
p.val = p.max;
|
|
|
|
_stprintf(val, TEXT("%g"), p.val);
|
|
|
|
SetWindowText(hEdit, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CShaderParamDlg::save_custom_shader()
|
|
|
|
{
|
|
|
|
TCHAR save_path[MAX_PATH];
|
2019-02-01 21:33:24 +00:00
|
|
|
int len = lstrlen(GUI.OGLshaderFileName);
|
|
|
|
if (len > 5 && !_tcsncicmp(&GUI.OGLshaderFileName[len - 6], TEXT(".glslp"), 6)) {
|
|
|
|
_stprintf(save_path, TEXT("%s\\custom_shader_params.glslp"), S9xGetDirectoryT(DEFAULT_DIR));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_stprintf(save_path, TEXT("%s\\custom_shader_params.slangp"), S9xGetDirectoryT(DEFAULT_DIR));
|
|
|
|
}
|
2023-02-01 20:47:42 +00:00
|
|
|
save_function(_tToChar(save_path));
|
2018-05-24 16:12:35 +00:00
|
|
|
lstrcpy(GUI.OGLshaderFileName, save_path);
|
|
|
|
}
|
2018-05-25 20:24:32 +00:00
|
|
|
|
|
|
|
void CShaderParamDlg::apply_changes(HWND hDlg)
|
|
|
|
{
|
|
|
|
get_changed_parameters(hDlg);
|
|
|
|
save_custom_shader();
|
|
|
|
WinRefreshDisplay();
|
|
|
|
}
|