diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Visualization/vis_avs/util.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Visualization/vis_avs/util.cpp')
-rw-r--r-- | Src/Plugins/Visualization/vis_avs/util.cpp | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/Src/Plugins/Visualization/vis_avs/util.cpp b/Src/Plugins/Visualization/vis_avs/util.cpp new file mode 100644 index 00000000..03ffc769 --- /dev/null +++ b/Src/Plugins/Visualization/vis_avs/util.cpp @@ -0,0 +1,536 @@ +/* + LICENSE + ------- +Copyright 2005 Nullsoft, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Nullsoft nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ +#include <windows.h> +#include <commctrl.h> +#include "r_defs.h" +#include "resource.h" +#include "../Agave/Language/api_language.h" +#if 0//syntax highlighting +#include "compiler.h" +#include "richedit.h" +#endif + +char* GetTextResource(UINT id){ + void* data = 0; + HRSRC rsrc = FindResource(WASABI_API_LNG_HINST,MAKEINTRESOURCE(id),"TEXT"); + if(rsrc){ + HGLOBAL resourceHandle = LoadResource(WASABI_API_LNG_HINST,rsrc); + data = LockResource(resourceHandle); + } + return (char*)data; +} + +void loadComboBox(HWND dlg, char *ext, char *selectedName) +{ + char path[MAX_PATH]; + int a; + HANDLE ff; + WIN32_FIND_DATA fd; + + wsprintf(path,"%s\\%s",g_path,ext); + + ff=FindFirstFile(path, &fd); + if (ff == INVALID_HANDLE_VALUE) return; + + do + { + SendMessage(dlg, CB_ADDSTRING, 0, (LPARAM)(fd.cFileName)); + } while (FindNextFile(ff, &fd)); + FindClose(ff); + + a = SendMessage(dlg, CB_FINDSTRINGEXACT, 0, (LPARAM)(selectedName)); + if (a != CB_ERR) SendMessage(dlg, CB_SETCURSEL, (WPARAM) a, 0); +} + +void GR_SelectColor(HWND hwnd, int *a) +{ + static COLORREF custcolors[16]; + CHOOSECOLOR cs; + cs.lStructSize = sizeof(cs); + cs.hwndOwner = hwnd; + cs.hInstance = 0; + cs.rgbResult=((*a>>16)&0xff)|(*a&0xff00)|((*a<<16)&0xff0000); + cs.lpCustColors = custcolors; + cs.Flags = CC_RGBINIT|CC_FULLOPEN; + if (ChooseColor(&cs)) + { + *a = ((cs.rgbResult>>16)&0xff)|(cs.rgbResult&0xff00)|((cs.rgbResult<<16)&0xff0000); + } +} + +void GR_DrawColoredButton(DRAWITEMSTRUCT *di, COLORREF color) +{ + color = ((color>>16)&0xff)|(color&0xff00)|((color<<16)&0xff0000); + + char wt[123]; + HPEN hPen,hOldPen; + HBRUSH hBrush,hOldBrush; + hPen = (HPEN)GetStockObject(BLACK_PEN); + LOGBRUSH lb={BS_SOLID,color,0}; + hBrush = CreateBrushIndirect(&lb); + hOldPen=(HPEN)SelectObject(di->hDC,hPen); + hOldBrush=(HBRUSH)SelectObject(di->hDC,hBrush); + + Rectangle(di->hDC,di->rcItem.left,di->rcItem.top,di->rcItem.right,di->rcItem.bottom); + + GetWindowText(di->hwndItem,wt,sizeof(wt)); + SetBkColor(di->hDC,color); + SetTextColor(di->hDC,~color & 0xffffff); + DrawText(di->hDC,wt,-1,&di->rcItem,DT_CENTER|DT_VCENTER|DT_SINGLELINE); + + DeleteObject(hBrush); + SelectObject(di->hDC,hOldPen); + SelectObject(di->hDC,hOldBrush); +} + +static int m_help_lastpage=4; +static char *m_localtext; +static void _dosetsel(HWND hwndDlg) +{ + HWND tabwnd=GetDlgItem(hwndDlg,IDC_TAB1); + int sel=TabCtrl_GetCurSel(tabwnd); + char *text=""; + + m_help_lastpage=sel; + + if (sel == 0) + +/* + text="Many AVS effects allow you to write simple expressions to control\r\n" + "visualization. Here is a brief summary of how to write AVS code.\r\n" + "\r\n" + "Many aspects of AVS code are similar to C (including comments). " + "\r\n" + "You can create new variables just by using them, and you can read\r\n" + "and write predefined variables (of which each effect has its own)\r\n" + "to interact with the effect. Note that variables are all floating\r\n" + "point numbers (no strings), and the maximum length of a variable's\r\n" + "name is 8 characters (anything longer will be ignored.\r\n" + "\r\n" + "So, to create a variable, you can simply use it, for example:\r\n" + " x = 5;\r\n" + "\r\n" + "You can also use a variety of operators and math functions to\r\n" + "modify variables, see the Operators and Functions tabs above.\r\n" + "\r\n" + "Code can include C and C++ style comments:\r\n" + "\r\n" + "You can combine operators and functions into expressions, such\r\n" + "as:\r\n" + " x = 5 * cos(y) / 32.0; // this does some leetness right here\r\n" + "\r\n" + "You can use multiple expressions by seperating them with one or\r\n" + "more semicolons, for example:\r\n" + " x = x * 17.0; x = x / 5; y = pow(x,3.0);\r\n" + "\r\n" + "It is worth noting that extra whitespace (spaces, newlines) is\r\n" + "ignored, so if you need to space things out for clarity, you can.\r\n" + ; + else if (sel == 1) + text="The following operators are available:\r\n" + "=\r\n" + " assigns a value to a variable. \r\n" + " example: var=5;\r\n" + "\r\n" + "+\r\n" + " adds two values, returns the sum. \r\n" + " example: var=5+var2;\r\n" + "\r\n" + "-\r\n" + " subtracts two values, returns the difference. \r\n" + " example: var=5-var2;\r\n" + "\r\n" + "*\r\n" + " multiplies two values, returns the product. \r\n" + " example: var=5*var2;\r\n" + "\r\n" + "/\r\n" + " divides two values, returns the quotient. \r\n" + " example: var=5/var2;\r\n" + "\r\n" + "%\r\n" + " converts two values to integer, performs division, returns remainder\r\n" + " example: var=var2%5;\r\n" + "\r\n" + "|\r\n" + " converts two values to integer, returns bitwise OR of both values\r\n" + " example: var=var2|31;\r\n" + "\r\n" + "&\r\n" + " converts two values to integer, returns bitwise AND of both values\r\n" + " example: var=var2&31;\r\n" + "\r\n" + ; + else if (sel == 2) + text="Functions available from code:\r\n" + "abs(value)\r\n" + " = returns the absolute value of 'value'\r\n" + "\r\n" + "sin(value)\r\n" + " = returns the sine of the radian angle 'value'\r\n" + "\r\n" + "cos(value)\r\n" + " = returns the cosine of the radian angle 'value'\r\n" + "\r\n" + "tan(value)\r\n" + " = returns the tangent of the radian angle 'value'\r\n" + "\r\n" + "asin(value)\r\n" + " = returns the arcsine (in radians) of 'value'\r\n" + "\r\n" + "acos(value)\r\n" + " = returns the arccosine (in radians) of 'value'\r\n" + "\r\n" + "atan(value)\r\n" + " = returns the arctangent (in radians) of 'value'\r\n" + "\r\n" + "atan2(value,value2)\r\n" + " = returns the arctangent (in radians) of 'value'/'value2'\r\n" + "\r\n" + "sqr(value)\r\n" + " = returns the square of 'value'\r\n" + "\r\n" + "sqrt(value)\r\n" + " = returns the square root of 'value'\r\n" + "\r\n" + "invsqrt(value)\r\n" + " = returns the reciprocal of the square root of 'value' (1/sqrt(value))\r\n" + " (uses a fast approximation, may not always = 1/sqrt(value) :)\r\n" + "\r\n" + "pow(value,value2)\r\n" + " = returns 'value' to the power of 'value2'\r\n" + "\r\n" + "exp(value)\r\n" + " = returns e to the power of 'value'\r\n" + "\r\n" + "log(value)\r\n" + " = returns the log in base e of 'value'\r\n" + "\r\n" + "log10(value)\r\n" + " = returns the log in base 10 of 'value'\r\n" + "\r\n" + "floor(value)\r\n" + " = returns the largest integer less than or equal to 'value'\r\n" + "\r\n" + "ceil(value)\r\n" + " = returns the smallest integer greater than or equal to 'value'\r\n" + "\r\n" + "sign(value)\r\n" + " = returns the sign of 'value' (-1.0 or 1.0, or 0.0 or -0.0 for 0.0 or -0.0)\r\n" + "\r\n" + "min(value,value2)\r\n" + " = returns the smallest of 'value' and 'value2'\r\n" + "\r\n" + "max(var,var2)\r\n" + " = returns the greatest of 'value' and 'value2'\r\n" + "\r\n" + "sigmoid(value,value2)\r\n" + " = returns sigmoid function value of x='value' ('value2'=constraint)\r\n" + "\r\n" + "rand(value)\r\n" + " = returns a random integer between 0 and 'value'\r\n" + "\r\n" + "band(value,value2)\r\n" + " = returns a boolean AND of 'value' and 'value2'\r\n" + "\r\n" + "bor(value,value2)\r\n" + " = returns a boolean OR of 'value' and 'value2'\r\n" + "\r\n" + "bnot(value)\r\n" + " = returns a boolean NOT of 'value'\r\n" + "\r\n" + "if(condition,valtrue,valfalse)\r\n" + " = returns 'valtrue' if 'condition' is nonzero, returns 'valfalse' otherwise.\r\n" + " new in AVS 2.8+: only one of valtrue/valfalse is evaluated, depending on condition\r\n" + "\r\n" + "assign(dest, source)\r\n" + " = if 'dest' is a variable, assigns the value of 'source' to it. returns the value of 'source'.\r\n" + " a little trick: assign(if(v,a,b),1.0); is like if V is true, a=1.0, otherwise b=1.0. :)\r\n" + "\r\n" + "exec2(parm1, parm2)\r\n" + " = evaluates parm1, then parm2, and returns the value of parm2.\r\n" + "\r\n" + "equal(value,value2)\r\n" + " = returns 1.0 if 'value' is equal to 'value2', otherwise returns 0.0\r\n" + "\r\n" + "above(value,value2)\r\n" + " = returns 1.0 if 'value' is greater than 'value2', otherwise returns 0.0\r\n" + "\r\n" + "below(value,value2)\r\n" + " = returns 1.0 if 'value' is less than 'value2', otherwise returns 0.0\r\n" + "\r\n" + "getosc(band,width,channel)\r\n" + " = returns waveform data centered at 'band', (0..1), sampled 'width' (0..1) wide.\r\n" + " 'channel' can be: 0=center, 1=left, 2=right. return value is (-1..1)\r\n" + "\r\n" + "getspec(band,width,channel)\r\n" + " = returns spectrum data centered at 'band', (0..1), sampled 'width' (0..1) wide.\r\n" + " 'channel' can be: 0=center, 1=left, 2=right. return value is (0..1)\r\n" + "\r\n" + "gettime(start_time)\r\n" + " = returns time in seconds since start_time (start_time can be 0 for time since boot)\r\n" + " (start_time can be -1.0 for current play time in seconds\r\n" + " (start_time can be -2.0 for current play length in seconds\r\n" + "\r\n" + "getkbmouse(which_parm)\r\n" + " = returns information about the location and state of the keyboard or mouse\r\n" + " which_parm = 1: mouse X position (-1..1 is onscreen)\r\n" + " which_parm = 2: mouse Y position (-1..1 is onscreen)\r\n" + " which_parm = 3: mouse left button state (0 up, 1 down)\r\n" + " which_parm = 4: mouse right button state (0 up, 1 down)\r\n" + " which_parm = 5: mouse middle button state (0 up, 1 down)\r\n" + " which_parm > 5: (GetAsyncKeyState(which_parm)&0x8000)?1:0\r\n" + "\r\n" + "megabuf(index)\r\n" + " = can be used to get or set an item from the 1 million item temp buffer\r\n" + " to get, use: val=megabuf(index);\r\n" + " to set, use: assign(megabuf(index),val);\r\n" + "gmegabuf(index)\r\n" + " = can be used to get or set an item from the global 1 million item buffer\r\n" + " to get, use: val=gmegabuf(index);\r\n" + " to set, use: assign(gmegabuf(index),val);\r\n" + "\r\n" + "loop(count, statement)\r\n" + " = executes <statement> <count> times. count is evaluated once and clamped\r\n" + " to 0..4096. best used with exec2() and exec3() and assign(). Note that\r\n" + " the return value of loop() is undefined and should not be used.\r\n" + "\r\n" + ; + else if (sel == 3) + text="Constants\r\n" + " '$PI' can be used in place of '3.14159'\r\n" + " '$E' can be used in place of '2.71828'\r\n" + " '$PHI' can be used in place of '1.618033'\r\n" + " Numbers can be specified as integers or as floating point\r\n" + " (i.e. '5' or '5.0' or '5.00001')\r\n" + + ; +*/ + + text=GetTextResource(IDR_HELP_1); + else if (sel == 1) + text=GetTextResource(IDR_HELP_2); + else if (sel == 2) + text=GetTextResource(IDR_HELP_3); + else if (sel == 3) + text=GetTextResource(IDR_HELP_4); + else if (sel == 4 && m_localtext) + text=m_localtext; + + SetDlgItemText(hwndDlg,IDC_EDIT1,text); +} + +static BOOL CALLBACK evalHelpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + TCITEM item; + HWND tabwnd=GetDlgItem(hwndDlg,IDC_TAB1); + item.mask=TCIF_TEXT; + item.pszText=WASABI_API_LNGSTRING(IDS_GENERAL); + TabCtrl_InsertItem(tabwnd,0,&item); + item.pszText=WASABI_API_LNGSTRING(IDS_OPERATORS); + TabCtrl_InsertItem(tabwnd,1,&item); + item.pszText=WASABI_API_LNGSTRING(IDS_FUNCTIONS); + TabCtrl_InsertItem(tabwnd,2,&item); + item.pszText=WASABI_API_LNGSTRING(IDS_CONSTANTS); + TabCtrl_InsertItem(tabwnd,3,&item); + // fucko: context specific stuff + m_localtext=0; + if (lParam) + { + item.pszText=(char *)lParam; + m_localtext=item.pszText + strlen(item.pszText)+1; + TabCtrl_InsertItem(tabwnd,4,&item); + } + else if (m_help_lastpage > 3) m_help_lastpage=0; + + TabCtrl_SetCurSel(tabwnd,m_help_lastpage); + _dosetsel(hwndDlg); + } + return 0; + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + EndDialog(hwndDlg,1); + return 0; + case WM_NOTIFY: + { + LPNMHDR p=(LPNMHDR) lParam; + if (p->idFrom == IDC_TAB1 && p->code == TCN_SELCHANGE) _dosetsel(hwndDlg); + } + return 0; + } + return 0; +} + +void compilerfunctionlist(HWND hwndDlg, char *localinfo) +{ + WASABI_API_DIALOGBOXPARAM(IDD_EVAL_HELP,hwndDlg,evalHelpDlgProc, (LONG)localinfo); +} + + + +#if 0//syntax highlighting +// If you include richedit boxes, you need to load the richlib at the beginning: +// HANDLE hRichLib = LoadLibrary("RICHED32.DLL"); +// When quitting: +// FreeLibrary(hRichLib); + + +#define M_WORD 1 +#define M_NUM 2 +#define M_COMM 3 + +#define is_alpha(a) ((((a) >= 'A') && ((a) <= 'Z')) || (((a) >= 'a') && ((a) <= 'z'))) +#define is_num(a) (((a) >= '0') && ((a) <= '9')) + +#define is_op(a) (((a) == '=') || ((a) == '+') || ((a) == '-') || ((a) == '*') || ((a) == '/') || ((a) == '%')) + + +// Colors for bracket pairs (loops around, ugly colors for now), can be any number of colors +static int bcol[] = { RGB(192, 0, 0), RGB(64, 128, 128), RGB(128, 0, 255), RGB(128, 128, 255) }; + +#define COLOR_COMMENT RGB(0, 128, 0) +#define COLOR_FUNC RGB(0, 0, 192) +#define COLOR_VAR RGB(96, 96, 96) +#define COLOR_OP RGB(0, 0, 0) +#define COLOR_NUMBER RGB(0, 0, 128) + +// Actual syntax highlighting +// 'hwnd' is a richedit box, 'data' is the code of 'size' characters +void doAVSEvalHighLight(HWND hwndDlg, UINT sub, char *data) { + int size=strlen(data); + HWND hwnd=GetDlgItem(hwndDlg,sub); + CHARRANGE cr, cro; + + CHARFORMAT cf; + cf.cbSize = sizeof(CHARFORMAT); + cf.dwMask = CFM_COLOR; + cf.dwEffects = 0; + + SendMessage(hwnd, WM_SETREDRAW, false, 0); + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&cro); + int mode = 0; + int pos = 0; + int brackets = 0; + for (int i = 0; i < size; ++i) { + if (mode == M_COMM) { + // We're inside a comment, check for its end + if ((data[i] == ';') || ((data[i] == '*') && ((i+1) < size) && (data[++i] == '/'))) { + mode = 0; + cf.crTextColor = COLOR_COMMENT; + cr.cpMin = pos; + cr.cpMax = i+1; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); + SendMessage(hwnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } else if (is_alpha(data[i]) || ((mode == M_WORD) && is_num(data[i]))) { + // Letter tokens (func calls, vars) + if (mode != M_WORD) { + // Enter word-mode if we haven't yet + mode = M_WORD; + pos = i; + } + // Stop condition + bool valid = (i != (size-1)); // Check if this isn't the last character + if (valid) { + valid = is_num(data[i+1]) || is_alpha(data[i+1]); + } + if (!valid) { + // We have reached the end of this word + cr.cpMin = pos; + cr.cpMax = i+1; + // Check if its a function + bool func = false; + for (int j = 0; j < (sizeof(fnTable) / sizeof(fnTable[0])); ++j) { + if ((i - pos + 1) == (signed)strlen(fnTable[j].name)) { + if (strnicmp(fnTable[j].name, &data[pos], strlen(fnTable[j].name)) == 0) { + func = true; + break; + } + } + } + cf.crTextColor = func ? COLOR_FUNC : COLOR_VAR; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); + SendMessage(hwnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } else if (is_op(data[i])) { + // This is an operator + mode = 0; + cf.crTextColor = COLOR_OP; + cr.cpMin = i; + cr.cpMax = i+1; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); + SendMessage(hwnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } else if ((data[i] & 0x80) || ((data[i] == '/') && ((i+1) < size) && (data[++i] == '*'))) { + // This is a comment marker, enter comment mode + mode = M_COMM; + pos = i; + } else if ((data[i] == '(') || (data[i] == ')') || (data[i] == ',')) { + // Reached brackets: we count them and color them in pairs + mode = 0; + if (data[i] == '(') ++brackets; + cf.crTextColor = bcol[brackets % (sizeof(bcol) / sizeof(bcol[0]))]; + if (data[i] == ')') --brackets; + cr.cpMin = i; + cr.cpMax = i+1; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); + SendMessage(hwnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } else if (is_num(data[i]) || (data[i] == '.')) { + // constants + if (mode != M_NUM) { + pos = i; + mode = M_NUM; + } + // Stop condition + bool valid = (i != (size-1)); + if (valid) { + valid = is_num(data[i+1]) || (data[i+1] == '.'); + } + if (!valid) { + cf.crTextColor = COLOR_NUMBER; + cr.cpMin = pos; + cr.cpMax = i+1; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); + SendMessage(hwnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } else if (data[i] == ';') { + // Reset bracket count and mode for every statement. + mode = 0; + brackets = 0; + } + } + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cro); + SendMessage(hwnd, WM_SETREDRAW, true, 0); + InvalidateRect(hwnd, 0, true); +} +#endif
\ No newline at end of file |