Merge branch 'reverbedit'

This commit is contained in:
Christoph Oelckers 2018-01-20 13:06:26 +01:00
commit 16461e0d59
10 changed files with 870 additions and 1442 deletions

View file

@ -474,7 +474,6 @@ endif()
# Start defining source files for ZDoom # Start defining source files for ZDoom
set( PLAT_WIN32_SOURCES set( PLAT_WIN32_SOURCES
sound/mididevices/music_win_mididevice.cpp sound/mididevices/music_win_mididevice.cpp
win32/eaxedit.cpp
win32/critsec.cpp win32/critsec.cpp
win32/fb_d3d9.cpp win32/fb_d3d9.cpp
win32/fb_d3d9_wipe.cpp win32/fb_d3d9_wipe.cpp

View file

@ -3,7 +3,7 @@
** **
**--------------------------------------------------------------------------- **---------------------------------------------------------------------------
** Copyright 2005-2016 Randy Heit ** Copyright 2005-2016 Randy Heit
** Copyright 2005-2016 Christoph Oelckers ** Copyright 2005-2017 Christoph Oelckers
** All rights reserved. ** All rights reserved.
** **
** Redistribution and use in source and binary forms, with or without ** Redistribution and use in source and binary forms, with or without
@ -40,6 +40,27 @@
#include "templates.h" #include "templates.h"
#include "w_wad.h" #include "w_wad.h"
#include "i_system.h" #include "i_system.h"
#include "m_misc.h"
#include "c_cvars.h"
#include "c_dispatch.h"
#include "files.h"
#include "vm.h"
#include "dobject.h"
#include "menu/menu.h"
void InitReverbMenu();
REVERB_PROPERTIES SavedProperties;
ReverbContainer *CurrentEnv;
extern ReverbContainer *ForcedEnvironment;
// These are for internal use only and not supposed to be user-settable
CVAR(String, reverbedit_name, "", CVAR_NOSET);
CVAR(Int, reverbedit_id1, 0, CVAR_NOSET);
CVAR(Int, reverbedit_id2, 0, CVAR_NOSET);
CVAR(String, reverbsavename, "", 0);
struct FReverbField struct FReverbField
{ {
@ -49,6 +70,7 @@ struct FReverbField
unsigned int Flag; unsigned int Flag;
}; };
static const FReverbField ReverbFields[] = static const FReverbField ReverbFields[] =
{ {
{ 0, 25, 0, &REVERB_PROPERTIES::Environment, 0 }, { 0, 25, 0, &REVERB_PROPERTIES::Environment, 0 },
@ -629,6 +651,7 @@ void S_ParseReverbDef ()
{ {
ReadReverbDef (lump); ReadReverbDef (lump);
} }
InitReverbMenu();
} }
void S_UnloadReverbDef () void S_UnloadReverbDef ()
@ -653,3 +676,477 @@ void S_UnloadReverbDef ()
} }
Environments = &Off; Environments = &Off;
} }
CUSTOM_CVAR(Bool, eaxedit_test, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (self)
{
ForcedEnvironment = CurrentEnv;
}
else
{
ForcedEnvironment = nullptr;
}
}
struct EnvFlag
{
const char *Name;
int CheckboxControl;
unsigned int Flag;
};
inline int HIBYTE(int i)
{
return (i >> 8) & 255;
}
inline int LOBYTE(int i)
{
return i & 255;
}
uint16_t FirstFreeID(uint16_t base, bool builtin)
{
int tryCount = 0;
int priID = HIBYTE(base);
// If the original sound is built-in, start searching for a new
// primary ID at 30.
if (builtin)
{
for (priID = 30; priID < 256; ++priID)
{
if (S_FindEnvironment(priID << 8) == nullptr)
{
break;
}
}
if (priID == 256)
{ // Oh well.
priID = 30;
}
}
for (;;)
{
uint16_t lastID = Environments->ID;
const ReverbContainer *env = Environments->Next;
// Find the lowest-numbered free ID with the same primary ID as base
// If none are available, add 100 to base's primary ID and try again.
// If that fails, then the primary ID gets incremented
// by 1 until a match is found. If all the IDs searchable by this
// algorithm are in use, then you're in trouble.
while (env != nullptr)
{
if (HIBYTE(env->ID) > priID)
{
break;
}
if (HIBYTE(env->ID) == priID)
{
if (HIBYTE(lastID) == priID)
{
if (LOBYTE(env->ID) - LOBYTE(lastID) > 1)
{
return lastID + 1;
}
}
lastID = env->ID;
}
env = env->Next;
}
if (LOBYTE(lastID) == 255)
{
if (tryCount == 0)
{
base += 100 * 256;
tryCount = 1;
}
else
{
base += 256;
}
}
else if (builtin && lastID == 0)
{
return priID << 8;
}
else
{
return lastID + 1;
}
}
}
FString SuggestNewName(const ReverbContainer *env)
{
const ReverbContainer *probe = nullptr;
char text[32];
size_t len;
int number, numdigits;
strncpy(text, env->Name, 31);
text[31] = 0;
len = strlen(text);
while (text[len - 1] >= '0' && text[len - 1] <= '9')
{
len--;
}
number = atoi(text + len);
if (number < 1)
{
number = 1;
}
if (text[len - 1] != ' ' && len < 31)
{
text[len++] = ' ';
}
for (; number < 100000; ++number)
{
if (number < 10) numdigits = 1;
else if (number < 100) numdigits = 2;
else if (number < 1000) numdigits = 3;
else if (number < 10000)numdigits = 4;
else numdigits = 5;
if (len + numdigits > 31)
{
len = 31 - numdigits;
}
mysnprintf(text + len, countof(text) - len, "%d", number);
probe = Environments;
while (probe != nullptr)
{
if (stricmp(probe->Name, text) == 0)
break;
probe = probe->Next;
}
if (probe == nullptr)
{
break;
}
}
return text;
}
void ExportEnvironments(const char *filename, uint32_t count, const ReverbContainer **envs)
{
FString dest = M_GetDocumentsPath() + filename;
FileWriter *f = FileWriter::Open(dest);
if (f != nullptr)
{
for (uint32_t i = 0; i < count; ++i)
{
const ReverbContainer *env = envs[i];
const ReverbContainer *base;
size_t j;
if ((unsigned int)env->Properties.Environment < 26)
{
base = DefaultEnvironments[env->Properties.Environment];
}
else
{
base = nullptr;
}
f->Printf("\"%s\" %u %u\n{\n", env->Name, HIBYTE(env->ID), LOBYTE(env->ID));
for (j = 0; j < countof(ReverbFields); ++j)
{
const FReverbField *ctl = &ReverbFields[j];
const char *ctlName = ReverbFieldNames[j];
if (ctlName)
{
if (j == 0 ||
(ctl->Float && base->Properties.*ctl->Float != env->Properties.*ctl->Float) ||
(ctl->Int && base->Properties.*ctl->Int != env->Properties.*ctl->Int))
{
f->Printf("\t%s ", ctlName);
if (ctl->Float)
{
float v = env->Properties.*ctl->Float * 1000;
int vi = int(v >= 0.0 ? v + 0.5 : v - 0.5);
f->Printf("%d.%03d\n", vi / 1000, abs(vi % 1000));
}
else
{
f->Printf("%d\n", env->Properties.*ctl->Int);
}
}
else
{
if ((1 << ctl->Flag) & (env->Properties.Flags ^ base->Properties.Flags))
{
f->Printf("\t%s %s\n", ctlName, ctl->Flag & env->Properties.Flags ? "true" : "false");
}
}
}
}
f->Printf("}\n\n");
}
delete f;
}
else
{
M_StartMessage("Save failed", 1);
}
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetValue)
{
PARAM_PROLOGUE;
PARAM_INT(index);
float v;
if (index >= 0 && index < countof(ReverbFields))
{
auto rev = &ReverbFields[index];
if (rev->Int != nullptr)
{
v = float(CurrentEnv->Properties.*(rev->Int));
}
else if (rev->Float != nullptr)
{
v = CurrentEnv->Properties.*(rev->Float);
}
else
{
v = !!(CurrentEnv->Properties.Flags & (1 << int(rev->Flag)));
}
}
ACTION_RETURN_FLOAT(v);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, SetValue)
{
PARAM_PROLOGUE;
PARAM_INT(index);
PARAM_FLOAT(v);
if (index >= 0 && index < countof(ReverbFields))
{
auto rev = &ReverbFields[index];
if (rev->Int != nullptr)
{
v = CurrentEnv->Properties.*(rev->Int) = clamp<int>(int(v), rev->Min, rev->Max);
}
else if (rev->Float != nullptr)
{
v = CurrentEnv->Properties.*(rev->Float) = clamp<float>(float(v), rev->Min / 1000.f, rev->Max / 1000.f);
}
else
{
if (v == 0) CurrentEnv->Properties.Flags &= ~(1 << int(rev->Flag));
else CurrentEnv->Properties.Flags |= (1 << int(rev->Flag));
}
}
ACTION_RETURN_FLOAT(v);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GrayCheck)
{
PARAM_PROLOGUE;
ACTION_RETURN_BOOL(CurrentEnv->Builtin);
return 1;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetSelectedEnvironment)
{
PARAM_PROLOGUE;
if (numret > 1)
{
numret = 2;
ret[1].SetInt(CurrentEnv ? CurrentEnv->ID : -1);
}
if (numret > 0)
{
ret[0].SetString(CurrentEnv ? CurrentEnv->Name : "");
}
return numret;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, FillSelectMenu)
{
PARAM_PROLOGUE;
PARAM_STRING(ccmd);
PARAM_OBJECT(desc, DOptionMenuDescriptor);
desc->mItems.Clear();
for (auto env = Environments; env != nullptr; env = env->Next)
{
FStringf text("(%d, %d) %s", HIBYTE(env->ID), LOBYTE(env->ID), env->Name);
FStringf cmd("%s \"%s\"", ccmd.GetChars(), env->Name);
PClass *cls = PClass::FindClass("OptionMenuItemCommand");
if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->FindSymbol("Init", true));
if (func != nullptr)
{
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
VMValue params[] = { item, &text, FName(cmd).GetIndex(), false, true };
VMCall(func->Variants[0].Implementation, params, 5, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
}
}
}
return 0;
}
static TArray<std::pair<ReverbContainer*, bool>> SaveState;
DEFINE_ACTION_FUNCTION(DReverbEdit, FillSaveMenu)
{
PARAM_PROLOGUE;
PARAM_OBJECT(desc, DOptionMenuDescriptor);
desc->mItems.Resize(4);
SaveState.Clear();
for (auto env = Environments; env != nullptr; env = env->Next)
{
if (!env->Builtin)
{
int index = (int)SaveState.Push(std::make_pair(env, false));
FStringf text("(%d, %d) %s", HIBYTE(env->ID), LOBYTE(env->ID), env->Name);
PClass *cls = PClass::FindClass("OptionMenuItemReverbSaveSelect");
if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->FindSymbol("Init", true));
if (func != nullptr)
{
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
VMValue params[] = { item, &text, index, FName("OnOff").GetIndex() };
VMCall(func->Variants[0].Implementation, params, 4, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
}
}
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(DReverbEdit, GetSaveSelection)
{
PARAM_PROLOGUE;
PARAM_INT(index);
bool res = false;
if ((unsigned)index <= SaveState.Size())
{
res = SaveState[index].second;
}
ACTION_RETURN_BOOL(res);
}
DEFINE_ACTION_FUNCTION(DReverbEdit, ToggleSaveSelection)
{
PARAM_PROLOGUE;
PARAM_INT(index);
if ((unsigned)index <= SaveState.Size())
{
SaveState[index].second = !SaveState[index].second;
}
return 0;
}
CCMD(savereverbs)
{
if (SaveState.Size() == 0) return;
TArray<const ReverbContainer*> toSave;
for (auto &p : SaveState)
{
if (p.second) toSave.Push(p.first);
}
ExportEnvironments(reverbsavename, toSave.Size(), &toSave[0]);
SaveState.Clear();
}
static void SelectEnvironment(const char *envname)
{
for (auto env = Environments; env != nullptr; env = env->Next)
{
if (!strcmp(env->Name, envname))
{
CurrentEnv = env;
SavedProperties = env->Properties;
if (eaxedit_test) ForcedEnvironment = env;
// Set up defaults for a new environment based on this one.
int newid = FirstFreeID(env->ID, env->Builtin);
UCVarValue cv;
cv.Int = HIBYTE(newid);
reverbedit_id1.ForceSet(cv, CVAR_Int);
cv.Int = LOBYTE(newid);
reverbedit_id2.ForceSet(cv, CVAR_Int);
FString selectname = SuggestNewName(env);
cv.String = selectname.GetChars();
reverbedit_name.ForceSet(cv, CVAR_String);
return;
}
}
}
void InitReverbMenu()
{
// Make sure that the editor's variables are properly initialized.
SelectEnvironment("Off");
}
CCMD(selectenvironment)
{
if (argv.argc() > 1)
{
auto str = argv[1];
SelectEnvironment(str);
}
else
InitReverbMenu();
}
CCMD(revertenvironment)
{
if (CurrentEnv != nullptr)
{
CurrentEnv->Properties = SavedProperties;
}
}
CCMD(createenvironment)
{
if (S_FindEnvironment(reverbedit_name))
{
M_StartMessage(FStringf("An environment with the name '%s' already exists", *reverbedit_name), 1);
return;
}
int id = (reverbedit_id1 << 8) + reverbedit_id2;
if (S_FindEnvironment(id))
{
M_StartMessage(FStringf("An environment with the ID (%d, %d) already exists", *reverbedit_id1, *reverbedit_id2), 1);
return;
}
auto newenv = new ReverbContainer;
newenv->Builtin = false;
newenv->ID = id;
newenv->Name = copystring(reverbedit_name);
newenv->Next = nullptr;
newenv->Properties = CurrentEnv->Properties;
S_AddEnvironment(newenv);
SelectEnvironment(newenv->Name);
}
CCMD(reverbedit)
{
C_DoCommand("openmenu reverbedit");
}

File diff suppressed because it is too large Load diff

View file

@ -130,9 +130,6 @@ FJoystickCollection *JoyDevices[NUM_JOYDEVICES];
extern HINSTANCE g_hInst; extern HINSTANCE g_hInst;
extern DWORD SessionID; extern DWORD SessionID;
extern void ShowEAXEditor ();
extern bool SpawnEAXWindow;
static HMODULE DInputDLL; static HMODULE DInputDLL;
bool GUICapture; bool GUICapture;
@ -141,10 +138,8 @@ extern FKeyboard *Keyboard;
bool VidResizing; bool VidResizing;
extern bool SpawnEAXWindow;
extern BOOL vidactive; extern BOOL vidactive;
extern HWND Window, ConWindow; extern HWND Window, ConWindow;
extern HWND EAXEditWindow;
EXTERN_CVAR (String, language) EXTERN_CVAR (String, language)
EXTERN_CVAR (Bool, lookstrafe) EXTERN_CVAR (Bool, lookstrafe)
@ -500,12 +495,6 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break; break;
case WM_KEYDOWN: case WM_KEYDOWN:
// When the EAX editor is open, pressing Ctrl+Tab will switch to it
if (EAXEditWindow != 0 && wParam == VK_TAB && !(lParam & 0x40000000) &&
(GetKeyState (VK_CONTROL) & 0x8000))
{
SetForegroundWindow (EAXEditWindow);
}
break; break;
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
@ -531,11 +520,6 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_DISPLAYCHANGE: case WM_DISPLAYCHANGE:
case WM_STYLECHANGED: case WM_STYLECHANGED:
if (SpawnEAXWindow)
{
SpawnEAXWindow = false;
ShowEAXEditor ();
}
return DefWindowProc(hWnd, message, wParam, lParam); return DefWindowProc(hWnd, message, wParam, lParam);
case WM_GETMINMAXINFO: case WM_GETMINMAXINFO:
@ -798,14 +782,12 @@ void I_GetEvent ()
{ {
if (mess.message == WM_QUIT) if (mess.message == WM_QUIT)
exit (mess.wParam); exit (mess.wParam);
if (EAXEditWindow == 0 || !IsDialogMessage (EAXEditWindow, &mess))
if (GUICapture)
{ {
if (GUICapture) TranslateMessage (&mess);
{
TranslateMessage (&mess);
}
DispatchMessage (&mess);
} }
DispatchMessage (&mess);
} }
if (Keyboard != NULL) if (Keyboard != NULL)

View file

@ -165,7 +165,7 @@ public:
bool GetDevice(); bool GetDevice();
void ProcessInput(); void ProcessInput();
bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); bool WndProcHook(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam, LRESULT *result);
void AddAxes(float axes[NUM_JOYAXIS]); void AddAxes(float axes[NUM_JOYAXIS]);
void GetDevices(TArray<IJoystickConfig *> &sticks); void GetDevices(TArray<IJoystickConfig *> &sticks);
IJoystickConfig *Rescan(); IJoystickConfig *Rescan();
@ -781,7 +781,7 @@ void FXInputManager::GetDevices(TArray<IJoystickConfig *> &sticks)
// //
//=========================================================================== //===========================================================================
bool FXInputManager::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) bool FXInputManager::WndProcHook(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam, LRESULT *result)
{ {
if (nullptr != InputEnable && message == WM_ACTIVATE) if (nullptr != InputEnable && message == WM_ACTIVATE)
{ {

View file

@ -1682,6 +1682,7 @@ OPTMNU_CHANGERENDER = "Change Rendering Output";
OPTMNU_DEFAULTS = "Reset to defaults"; OPTMNU_DEFAULTS = "Reset to defaults";
OPTMNU_RESETTOSAVED = "Reset to last saved"; OPTMNU_RESETTOSAVED = "Reset to last saved";
OPTMNU_CONSOLE = "Go to console"; OPTMNU_CONSOLE = "Go to console";
OPTMNU_REVERB = "Reverb environment editor";
// Controls Menu // Controls Menu

View file

@ -1630,6 +1630,8 @@ OptionMenu SoundOptions protected
StaticText " " StaticText " "
Submenu "$SNDMNU_ADVANCED", "AdvSoundOptions" Submenu "$SNDMNU_ADVANCED", "AdvSoundOptions"
Submenu "$SNDMNU_MODREPLAYER", "ModReplayerOptions" Submenu "$SNDMNU_MODREPLAYER", "ModReplayerOptions"
StaticText " "
Submenu "$OPTMNU_REVERB", "ReverbEdit"
} }
/*======================================= /*=======================================
@ -2214,3 +2216,90 @@ OptionMenu "OpenGLOptions" protected
Slider "$GLPREFMNU_PALTONEMAPPOWER", gl_paltonemap_powtable, 0.2, 3.0, 0.1, 1 Slider "$GLPREFMNU_PALTONEMAPPOWER", gl_paltonemap_powtable, 0.2, 3.0, 0.1, 1
Option "$GLPREFMNU_PALTONEMAPORDER", gl_paltonemap_reverselookup, "LookupOrder" Option "$GLPREFMNU_PALTONEMAPORDER", gl_paltonemap_reverselookup, "LookupOrder"
} }
OptionMenu "ReverbEdit" protected
{
Class "ReverbEdit"
Title "$OPTMNU_REVERB"
StaticTextSwitchable "", "", "EvironmentName", 1
StaticTextSwitchable "", "", "EvironmentID"
StaticText " "
Submenu "Select Environment", "ReverbSelect"
Option "Test Environment", "eaxedit_test", OnOff
StaticText " "
Submenu "New Environment", "ReverbNew"
Submenu "Save Environments", "ReverbSave"
Submenu "Edit Environment", "ReverbSettings"
}
OptionMenu "ReverbSelect" protected
{
Class "ReverbSelect"
Title "Select Environment"
// filled in by code
}
OptionMenu "ReverbSettings" protected
{
Title "Edit Reverb Environment"
SafeCommand "Revert settings", "revertenvironment"
StaticText " "
SliderReverbEditOption "Environment Size", 1, 100, 0.01, 3, 1
SliderReverbEditOption "Environment Diffusion", 0, 1, 0.01, 3, 2
SliderReverbEditOption "Room", -10000, 0, 1, 0, 3
SliderReverbEditOption "Room HF", -10000, 0, 1, 0, 4
SliderReverbEditOption "Room LF", -10000, 0, 1, 0, 5
SliderReverbEditOption "Decay Time", 1, 200, 0.01, 3, 6
SliderReverbEditOption "Decay HF Ratio", 1, 20, 0.01, 3, 7
SliderReverbEditOption "Decay LF Ratio", 1, 20, 0.01, 3, 8
SliderReverbEditOption "Reflections", -10000, 1000, 1, 0, 9
SliderReverbEditOption "Reflections Delay", 0, 0.3, 1, 3, 10
SliderReverbEditOption "Reflections Pan X", -2000, 2000, 1, 3, 11
SliderReverbEditOption "Reflections Pan Y", -2000, 2000, 1, 3, 12
SliderReverbEditOption "Reflections Pan Z", -2000, 2000, 1, 3, 13
SliderReverbEditOption "Reverb", -10000, 2000, 1, 0, 14
SliderReverbEditOption "Reverb Delay", 0, 0.1, 0.01, 3, 15
SliderReverbEditOption "Reverb Pan X", -2000, 2000, 1, 3, 16
SliderReverbEditOption "Reverb Pan Y", -2000, 2000, 1, 3, 17
SliderReverbEditOption "Reverb Pan Z", -2000, 2000, 1, 3, 18
SliderReverbEditOption "Echo Time", 0.075, 0.25, 0.005, 3, 19
SliderReverbEditOption "Echo Depth", 0, 1, 0.01, 3, 20
SliderReverbEditOption "Modulation Time", 0.04, 4, 0.01, 3, 21
SliderReverbEditOption "Modulation Depth",0, 1, 0.01, 3, 22
SliderReverbEditOption "Air Absorption HF", -100, 0, 0.01, 3, 23
SliderReverbEditOption "HF Reference", 10000, 200000, 1, 3, 24
SliderReverbEditOption "LF Reference",20, 10000, 0.1, 3, 25
SliderReverbEditOption "Room Rolloff Factor",0, 10, 0.01, 3, 26
SliderReverbEditOption "Diffusion",0, 100, 0.01, 3, 27
SliderReverbEditOption "Density",0, 100, 0.01, 3, 28
StaticText " "
ReverbOption "Reflections Scale", 29, OnOff
ReverbOption "Reflections Delay Scale", 30, OnOff
ReverbOption "Decay Time Scale", 31, OnOff
ReverbOption "Decay HF Limit", 32, OnOff
ReverbOption "Reverb Scale", 33, OnOff
ReverbOption "Reverb Delay Scale", 34, OnOff
ReverbOption "Echo Time Scale", 35, OnOff
ReverbOption "Modulation Time Scale", 36, OnOff
}
OptionMenu "ReverbNew" protected
{
Title "New Reverb Environment"
ReverbSelect "Based on", "ReverbSelect"
TextField "Name", "reverbedit_name"
NumberField "ID #1", "reverbedit_id1", 0, 255
NumberField "ID #2", "reverbedit_id2", 0, 255
Command "Create", "createenvironment", 0, 1
}
OptionMenu "ReverbSave" protected
{
Class "ReverbSave"
Title "Save Reverb Environments"
Command "Save...", "savereverbs"
TextField "File name", "reverbsavename"
StaticText ""
StaticText "Environments to save"
// Rest is filled in by code.
}

View file

@ -25,6 +25,7 @@ version "3.3"
#include "zscript/menu/videomenu.txt" #include "zscript/menu/videomenu.txt"
#include "zscript/menu/readthis.txt" #include "zscript/menu/readthis.txt"
#include "zscript/menu/conversationmenu.txt" #include "zscript/menu/conversationmenu.txt"
#include "zscript/menu/reverbedit.txt"
#include "zscript/statscreen/types.txt" #include "zscript/statscreen/types.txt"
#include "zscript/statscreen/statscreen.txt" #include "zscript/statscreen/statscreen.txt"

View file

@ -127,11 +127,13 @@ class OptionMenuItemSubmenu : OptionMenuItem
class OptionMenuItemCommand : OptionMenuItemSubmenu class OptionMenuItemCommand : OptionMenuItemSubmenu
{ {
private String ccmd; // do not allow access to this from the outside. private String ccmd; // do not allow access to this from the outside.
bool mCloseOnSelect;
OptionMenuItemCommand Init(String label, Name command, bool centered = false) OptionMenuItemCommand Init(String label, Name command, bool centered = false, bool closeonselect = false)
{ {
Super.Init(label, command, 0, centered); Super.Init(label, command, 0, centered);
ccmd = command; ccmd = command;
mCloseOnSelect = closeonselect;
return self; return self;
} }
@ -150,6 +152,11 @@ class OptionMenuItemCommand : OptionMenuItemSubmenu
} }
Menu.MenuSound("menu/choose"); Menu.MenuSound("menu/choose");
DoCommand(ccmd); DoCommand(ccmd);
if (mCloseOnSelect)
{
let curmenu = Menu.GetCurrentMenu();
if (curmenu != null) curmenu.Close();
}
return true; return true;
} }
@ -245,11 +252,11 @@ class OptionMenuItemOptionBase : OptionMenuItem
virtual void SetSelection(int Selection) virtual void SetSelection(int Selection)
{ {
} }
//============================================================================= //=============================================================================
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{ {
bool grayed = mGrayCheck != null && !(mGrayCheck.GetInt()); bool grayed = isGrayed();
if (mCenter) if (mCenter)
{ {
@ -294,10 +301,15 @@ class OptionMenuItemOptionBase : OptionMenuItem
} }
return true; return true;
} }
virtual bool isGrayed()
{
return mGrayCheck != null && !mGrayCheck.GetInt();
}
override bool Selectable() override bool Selectable()
{ {
return mGrayCheck == null || mGrayCheck.GetInt(); return !isGrayed();
} }
} }

View file

@ -0,0 +1,259 @@
class ReverbEdit : OptionMenu
{
static native double GetValue(int index);
static native double SetValue(int index, double value);
static native bool GrayCheck();
static native string, int GetSelectedEnvironment();
static native void FillSelectMenu(String ccmd, OptionMenuDescriptor desc);
static native void FillSaveMenu(OptionMenuDescriptor desc);
static native int GetSaveSelection(int num);
static native void ToggleSaveSelection(int num);
override void Init(Menu parent, OptionMenuDescriptor desc)
{
super.Init(parent, desc);
OnReturn();
}
override void OnReturn()
{
string env;
int id;
[env, id] = GetSelectedEnvironment();
let li = GetItem('EvironmentName');
if (li != NULL)
{
if (id != -1)
{
li.SetValue(0, 1);
li.SetString(0, env);
}
else
{
li.SetValue(0, 0);
}
}
li = GetItem('EvironmentID');
if (li != NULL)
{
if (id != -1)
{
li.SetValue(0, 1);
li.SetString(0, String.Format("%d, %d", (id >> 8) & 255, id & 255));
}
else
{
li.SetValue(0, 0);
}
}
}
}
class ReverbSelect : OptionMenu
{
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, OptionMenuDescriptor desc)
{
ReverbEdit.FillSelectMenu("selectenvironment", desc);
super.Init(parent, desc);
}
}
class ReverbSave : OptionMenu
{
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, OptionMenuDescriptor desc)
{
ReverbEdit.FillSaveMenu(desc);
super.Init(parent, desc);
}
}
//=============================================================================
//
// Change a CVAR, command is the CVAR name
//
//=============================================================================
class OptionMenuItemReverbSaveSelect : OptionMenuItemOptionBase
{
int mValIndex;
OptionMenuItemReverbSaveSelect Init(String label, int index, Name values)
{
Super.Init(label, 'None', values, null, 0);
mValIndex = index;
return self;
}
//=============================================================================
override int GetSelection()
{
return ReverbEdit.GetSaveSelection(mValIndex);
}
override void SetSelection(int Selection)
{
ReverbEdit.ToggleSaveSelection(mValIndex);
}
}
//=============================================================================
//
// opens a submenu, command is a submenu name
//
//=============================================================================
class OptionMenuItemReverbSelect : OptionMenuItemSubMenu
{
OptionMenuItemReverbSelect Init(String label, Name command)
{
Super.init(label, command, 0, false);
return self;
}
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
int x = drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor);
String text = ReverbEdit.GetSelectedEnvironment();
screen.DrawText (SmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true);
return indent;
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemReverbOption : OptionMenuItemOptionBase
{
int mValIndex;
OptionMenuItemReverbOption Init(String label, int valindex, Name values)
{
Super.Init(label, "", values, null, false);
mValIndex = valindex;
return self;
}
override bool isGrayed()
{
return ReverbEdit.GrayCheck();
}
override int GetSelection()
{
return int(ReverbEdit.GetValue(mValIndex));
}
override void SetSelection(int Selection)
{
ReverbEdit.SetValue(mValIndex, Selection);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase
{
int mValIndex;
String mEditValue;
TextEnterMenu mEnter;
OptionMenuItemSliderReverbEditOption Init(String label, double min, double max, double step, int showval, int valindex)
{
Super.Init(label, min, max, step, showval);
mValIndex = valindex;
mEnter = null;
return self;
}
override double GetSliderValue()
{
return ReverbEdit.GetValue(mValIndex);
}
override void SetSliderValue(double val)
{
ReverbEdit.SetValue(mValIndex, val);
}
override bool Selectable()
{
return !ReverbEdit.GrayCheck();
}
virtual String Represent()
{
return mEnter.GetText() .. SmallFont.GetCursor();
}
//=============================================================================
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
drawLabel(indent, y, selected ? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, ReverbEdit.GrayCheck());
mDrawX = indent + CursorSpace();
if (mEnter)
{
screen.DrawText(SmallFont, OptionMenuSettings.mFontColorValue, mDrawX, y, Represent(), DTA_CleanNoMove_1, true);
}
else
{
DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent);
}
return indent;
}
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (mkey == Menu.MKEY_Enter)
{
Menu.MenuSound("menu/choose");
mEnter = TextEnterMenu.Open(Menu.GetCurrentMenu(), String.Format("%.3f", GetSliderValue()), -1, 2, fromcontroller);
mEnter.ActivateMenu();
return true;
}
else if (mkey == Menu.MKEY_Input)
{
String val = mEnter.GetText();
SetSliderValue(val.toDouble());
mEnter = null;
return true;
}
else if (mkey == Menu.MKEY_Abort)
{
mEnter = null;
return true;
}
return Super.MenuEvent(mkey, fromcontroller);
}
}