- added blend table translucency estimation instead of using a lame default.

- draw fullscreen blends below the console.
- moved all mouse event processing out of the SDL backend to D_PostEvent.
- removed all remaining code for dealing with mouse buttons directly.
This commit is contained in:
Christoph Oelckers 2019-11-10 15:15:14 +01:00
parent 87acd7fef6
commit 21ac5e87b5
22 changed files with 359 additions and 602 deletions

View file

@ -114,8 +114,8 @@ bool CGameMenuMgr::Push(CGameMenu *pMenu, int nItem)
m_mouselastactivity = -M_MOUSETIMEOUT;
m_mousewake_watchpoint = 0;
mouseLockToWindow(0);
mouseMoveToCenter();
mouseReadAbs(&m_prevmousepos, &g_mouseAbs);
//mouseMoveToCenter();
inputState.mouseReadAbs(&m_prevmousepos);
}
dassert(pMenu != NULL);
if (nMenuPointer == 8)
@ -187,7 +187,7 @@ void CGameMenuMgr::Draw(void)
m_postPop = false;
}
int32_t mousestatus = mouseReadAbs(&m_mousepos, &g_mouseAbs);
int32_t mousestatus = inputState.mouseReadAbs(&m_mousepos);
if (mousestatus && inputState.mouseClickState() == MOUSE_PRESSED)
m_mousedownpos = m_mousepos;

View file

@ -1891,7 +1891,6 @@ void UpdatePlayerName(CGameMenuItemZEdit *pItem, CGameMenuEvent *pEvent)
void SetMouseFilterInput(CGameMenuItemZBool *pItem)
{
CONTROL_SmoothMouse = pItem->at20;
in_mousesmoothing = pItem->at20;
}

View file

@ -131,6 +131,11 @@ glblend_t const bloodglblend =
void scrLoadPalette(void)
{
#ifdef USE_OPENGL
for (auto& x : glblend)
x = bloodglblend;
#endif
initfastcolorlookup_scale(30, 59, 11);
initfastcolorlookup_gridvectors();
paletteloaded = 0;
@ -155,11 +160,6 @@ void scrLoadPalette(void)
blendtable[0] = (char*)gSysRes.Lock(pTrans);
paletteloaded |= PALETTE_TRANSLUC;
#ifdef USE_OPENGL
for (auto & x : glblend)
x = bloodglblend;
#endif
initfastcolorlookup_palette(palette);
palettePostLoadTables();
}

View file

@ -143,7 +143,6 @@ void joyScanDevices(void);
void mouseInit(void);
void mouseUninit(void);
int32_t mouseReadAbs(vec2_t *pResult, vec2_t const *pInput);
void mouseGrabInput(bool grab);
void mouseLockToWindow(char a);
void mouseMoveToCenter(void);

View file

@ -49,8 +49,6 @@ typedef struct {
extern palette_t curpalette[256], curpalettefaded[256], palfadergb;
extern char palfadedelta;
extern void fullscreen_tint_gl(uint8_t r, uint8_t g, uint8_t b, uint8_t f);
extern void fullscreen_tint_gl_blood(void);
extern void videoFadeToBlack(int32_t moreopaquep);
void paletteMakeLookupTable(int32_t palnum, const char *remapbuf, uint8_t r, uint8_t g, uint8_t b, char noFloorPal);
void paletteSetColorTable(int32_t id, uint8_t const *table, bool transient = false);

View file

@ -33,21 +33,6 @@ bool g_mouseGrabbed;
bool g_mouseInsideWindow = 1;
bool g_mouseLockedToWindow = 1;
int32_t mouseReadAbs(vec2_t * const pResult, vec2_t const * const pInput)
{
if (!g_mouseEnabled || !appactive || !g_mouseInsideWindow || GUICapture)
return 0;
int32_t const xwidth = max(scale(240<<16, xdim, ydim), 320<<16);
pResult->x = scale(pInput->x, xwidth, xres) - ((xwidth>>1) - (320<<15));
pResult->y = scale(pInput->y, 200<<16, yres);
pResult->y = divscale16(pResult->y - (200<<15), rotatesprite_yxaspect) + (200<<15) - rotatesprite_y_offset;
return 1;
}
controllerinput_t joystick;
void joySetCallback(void (*callback)(int32_t, int32_t)) { joystick.pCallback = callback; }

View file

@ -10196,18 +10196,12 @@ int32_t videoSetGameMode(char davidoption, int32_t daupscaledxdim, int32_t daups
if (videoGetRenderMode() == REND_POLYMOST)
PolymostProcessVoxels();
}
# ifdef POLYMER
if (videoGetRenderMode() == REND_POLYMER)
{
if (!polymer_init())
rendmode = REND_POLYMOST;
}
#endif
#endif
qsetmode = 200;
return 0;
}
void DrawFullscreenBlends();
//
// nextpage
@ -10241,6 +10235,7 @@ void videoNextPage(void)
}
// Draw the console plus debug output on top of everything else.
DrawFullscreenBlends();
FStat::PrintStat();
C_DrawConsole();
GLInterface.Draw2D(&twod);

View file

@ -45,88 +45,58 @@ int8_t g_noFloorPal[MAXPALOOKUPS];
int32_t curbrightness = 0;
static void paletteSetFade(uint8_t offset);
void setBlendFactor(int index, int alpha);
#ifdef USE_OPENGL
void fullscreen_tint_gl(uint8_t r, uint8_t g, uint8_t b, uint8_t f)
int DetermineTranslucency(const uint8_t *table)
{
auto oldproj = GLInterface.GetMatrix(Matrix_Projection);
auto oldmv = GLInterface.GetMatrix(Matrix_ModelView);
VSMatrix identity(0);
GLInterface.SetMatrix(Matrix_Projection, &identity);
GLInterface.SetMatrix(Matrix_ModelView, &identity);
uint8_t index;
PalEntry newcolor;
PalEntry newcolor2;
GLInterface.EnableDepthTest(false);
GLInterface.EnableAlphaTest(false);
index = table[blackcol * 256 + whitecol];
auto pp = &basepaltable[0][index];
newcolor = PalEntry(pp[0], pp[1], pp[2]);
GLInterface.SetBlendFunc(STYLEALPHA_Src, STYLEALPHA_InvSrc);
GLInterface.EnableBlend(true);
GLInterface.SetColorub(r, g, b, f);
index = table[whitecol * 256 + blackcol];
pp = &basepaltable[0][index];
newcolor2 = PalEntry(pp[0], pp[1], pp[2]);
if (newcolor2.r == 255) // if black on white results in white it's either
// fully transparent or additive
{
/*
if (developer >= DMSG_NOTIFY)
{
char lumpname[9];
lumpname[8] = 0;
Wads.GetLumpName(lumpname, lumpnum);
Printf("%s appears to be additive translucency %d (%d%%)\n", lumpname, newcolor.r,
newcolor.r * 100 / 255);
}
*/
return -newcolor.r;
}
GLInterface.UseColorOnly(true);
auto data = GLInterface.AllocVertices(3);
auto vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.UseColorOnly(false);
GLInterface.SetMatrix(Matrix_Projection, &oldproj);
GLInterface.SetMatrix(Matrix_ModelView, &oldmv);
/*
if (developer >= DMSG_NOTIFY)
{
char lumpname[9];
lumpname[8] = 0;
Wads.GetLumpName(lumpname, lumpnum);
Printf("%s appears to be translucency %d (%d%%)\n", lumpname, newcolor.r,
newcolor.r * 100 / 255);
}
*/
return newcolor.r;
}
int32_t tint_blood_r = 0, tint_blood_g = 0, tint_blood_b = 0;
void fullscreen_tint_gl_blood(void)
{
if (!(tint_blood_r|tint_blood_g|tint_blood_b))
return;
auto oldproj = GLInterface.GetMatrix(Matrix_Projection);
auto oldmv = GLInterface.GetMatrix(Matrix_ModelView);
VSMatrix identity(0);
GLInterface.SetMatrix(Matrix_Projection, &identity);
GLInterface.SetMatrix(Matrix_ModelView, &identity);
GLInterface.EnableDepthTest(false);
GLInterface.EnableAlphaTest(false);
GLInterface.SetBlendFunc(STYLEALPHA_One, STYLEALPHA_One);
GLInterface.EnableBlend(true);
GLInterface.UseColorOnly(true);
GLInterface.SetColorub(max(tint_blood_r, 0), max(tint_blood_g, 0), max(tint_blood_b, 0), 255);
auto data = GLInterface.AllocVertices(3);
auto vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.SetBlendOp(STYLEOP_RevSub);
GLInterface.SetColorub(max(-tint_blood_r, 0), max(-tint_blood_g, 0), max(-tint_blood_b, 0), 255);
data = GLInterface.AllocVertices(3);
vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.SetBlendOp(STYLEOP_Add);
GLInterface.SetColorub(0,0,0,0);
GLInterface.SetBlendFunc(STYLEALPHA_Src, STYLEALPHA_InvSrc);
GLInterface.UseColorOnly(false);
GLInterface.SetMatrix(Matrix_Projection, &oldproj);
GLInterface.SetMatrix(Matrix_ModelView, &oldmv);
}
#endif
void fullscreen_tint_gl(PalEntry pe);
void videoFadeToBlack(int32_t moreopaquep)
{
#ifdef USE_OPENGL
if (videoGetRenderMode() >= REND_POLYMOST)
fullscreen_tint_gl(0, 0, 0, moreopaquep ? 168 : 84);
fullscreen_tint_gl(moreopaquep? PalEntry(168, 0, 0, 0) : PalEntry(84, 0, 0, 0));
else
#endif
{
@ -347,6 +317,8 @@ void paletteLoadFromDisk(void)
}
paletteSetBlendTable(blendnum, tab);
setBlendFactor(blendnum, DetermineTranslucency((const uint8_t*)tab));
}
Xfree(tab);
@ -545,8 +517,8 @@ void paletteSetBlendTable(int32_t blend, const char *tab)
blendtable[blend] = (char *) Xmalloc(256*256);
Bmemcpy(blendtable[blend], tab, 256*256);
// Todo: Calculate an alpha factor from the loaded data so that the hardware renderer uses the proper amount of tranlucency.
}
void paletteFreeBlendTable(int32_t const blend)
{
DO_FREE_AND_NULL(blendtable[blend]);
@ -577,6 +549,28 @@ glblend_t const defaultglblend =
glblend_t glblend[MAXBLENDTABS];
void setBlendFactor(int index, int alpha)
{
if (index >= 0 && index < MAXBLENDTABS)
{
auto& myblend = glblend[index];
if (index >= 0)
{
myblend.def[0].alpha = index / 255.f;
myblend.def[1].alpha = 1.f - (index / 255.f);
myblend.def[0].src = myblend.def[1].src = BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
myblend.def[0].dst = myblend.def[1].dst = BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
}
else
{
myblend.def[0].alpha = 1;
myblend.def[1].alpha = 1;
myblend.def[0].src = myblend.def[1].src = BLENDFACTOR_ONE;
myblend.def[0].dst = myblend.def[1].dst = BLENDFACTOR_ONE;
}
}
}
void handle_blend(uint8_t enable, uint8_t blend, uint8_t def)
{
static GLenum const blendFuncTokens[NUMBLENDFACTORS] =
@ -839,6 +833,7 @@ static void paletteSetFade(uint8_t offset)
//#define DEBUG_PALETTEFADE
//
// setpalettefade
//
@ -869,12 +864,3 @@ void videoFadePalette(uint8_t r, uint8_t g, uint8_t b, uint8_t offset)
g_lastpalettesum = lastpalettesum = newpalettesum;
}
}
#ifdef USE_OPENGL
void videoTintBlood(int32_t r, int32_t g, int32_t b)
{
tint_blood_r = r;
tint_blood_g = g;
tint_blood_b = b;
}
#endif

View file

@ -958,7 +958,7 @@ void mouseGrabInput(bool grab)
else
g_mouseGrabbed = grab;
g_mousePos.x = g_mousePos.y = 0;
inputState.MouseSetPos(0, 0);
}
void mouseLockToWindow(char a)
@ -973,15 +973,6 @@ void mouseLockToWindow(char a)
SDL_ShowCursor(GUICapture ? SDL_ENABLE : SDL_DISABLE);
}
void mouseMoveToCenter(void)
{
if (sdl_window)
{
g_mouseAbs = { xdim >> 1, ydim >> 1 };
SDL_WarpMouseInWindow(sdl_window, g_mouseAbs.x, g_mouseAbs.y);
}
}
//
// setjoydeadzone() -- sets the dead and saturation zones for the joystick
//
@ -1523,15 +1514,7 @@ void videoShowFrame(int32_t w)
#ifdef USE_OPENGL
if (!nogl)
{
if (bpp > 8)
{
if (palfadedelta)
fullscreen_tint_gl(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta);
if (playing_blood)
fullscreen_tint_gl_blood();
}
else
if (bpp == 8)
{
glsurface_blitBuffer();
}
@ -1631,6 +1614,46 @@ int32_t handleevents_peekkeys(void)
return SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN);
}
static void PostMouseMove(int x, int y)
{
static int lastx = 0, lasty = 0;
event_t ev = { 0,0,0,0,0,0,0 };
ev.x = x;
ev.y = y;
lastx = x;
lasty = y;
if (ev.x | ev.y)
{
ev.type = EV_Mouse;
D_PostEvent(&ev);
}
}
CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
static void MouseRead()
{
int x, y;
#if 0
if (NativeMouse)
{
return;
}
#endif
SDL_GetRelativeMouseState(&x, &y);
if (!m_noprescale)
{
x *= 3;
y *= 2;
}
if (x | y)
{
PostMouseMove(x, -y);
}
}
//
@ -1643,20 +1666,25 @@ int32_t handleevents_sdlcommon(SDL_Event *ev)
switch (ev->type)
{
case SDL_MOUSEMOTION:
g_mouseAbs.x = ev->motion.x;
g_mouseAbs.y = ev->motion.y;
// SDL <VER> doesn't handle relative mouse movement correctly yet as the cursor still clips to the
// screen edges
// so, we call SDL_WarpMouse() to center the cursor and ignore the resulting motion event that occurs
// <VER> is 1.3 for PK, 1.2 for tueidj
if (appactive && g_mouseGrabbed)
{
{
g_mousePos.x += ev->motion.xrel;
g_mousePos.y += ev->motion.yrel;
}
}
// The menus need this, even in non GUI-capture mode
event_t event;
event.data1 = ev->motion.x;
event.data2 = ev->motion.y;
//screen->ScaleCoordsFromWindow(event.data1, event.data2);
event.type = EV_GUI_Event;
event.subtype = EV_GUI_MouseMove;
SDL_Keymod kmod = SDL_GetModState();
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
((kmod & KMOD_ALT) ? GKM_ALT : 0);
D_PostEvent(&event);
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
@ -2003,6 +2031,7 @@ int32_t handleevents_pollsdl(void)
break;
}
}
MouseRead();
return rv;
}

View file

@ -134,13 +134,15 @@ FBaseCVar::~FBaseCVar ()
else
CVars = m_Next;
}
if (var->Flags & CVAR_AUTO)
C_RemoveTabCommand(VarName);
}
}
const char *FBaseCVar::GetHumanString(int precision) const
{
return GetGenericRep(CVAR_String).String;
assert(true);
return "";// GetGenericRep(CVAR_String).String;
}
void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend)

View file

@ -173,29 +173,17 @@ void D_PostEvent (const event_t *ev)
{
return;
}
events[eventhead] = *ev;
#if 0 // No idea if this can be made to work ever... For now, pass on the mouse movement event so that the input code can deal with them itself.
if (ev->type == EV_Mouse && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !primaryLevel->localEventManager->Responder(ev) && !paused)
{
if (Button_Mlook.bDown || freelook)
{
int look = int(ev->y * m_pitch * mouse_sensitivity * 16.0);
if (invertmouse)
look = -look;
G_AddViewPitch (look, true);
events[eventhead].y = 0;
}
if (!Button_Strafe.bDown && !lookstrafe)
{
G_AddViewAngle (int(ev->x * m_yaw * mouse_sensitivity * 8.0), true);
events[eventhead].x = 0;
}
if ((events[eventhead].x | events[eventhead].y) == 0)
if (ev->type == EV_Mouse && GUICapture == 0 && appactive && g_mouseGrabbed)
{
inputState.MouseAddToPos(ev->x / 3, -ev->y / 2);
return;
}
else if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_MouseMove && appactive && GUICapture == 0 && !g_mouseGrabbed)
{
inputState.MouseSetAbs(ev->data1, ev->data2);
return;
}
#endif
if ((GUICapture & 8) && ev->type == EV_KeyDown)
{
@ -208,10 +196,10 @@ void D_PostEvent (const event_t *ev)
// This is probably the biggest roadblock with the input system as it undermines a proper event driven approach.
// Too much code depends on just checking this instead of waiting for events to happen.
// Here's also definitely not the best place to maintain the keyboard state but right now it's unavoidable to do this outside the event processing because so much code depends on it.
// Once all those busy waiting loops can poll the event queue for a proper skip event, this will mostly go away.
inputState.AddEvent(ev);
// Also add it to the event queue - this is where everything should transition to eventually.
// Also add it to the event queue.
events[eventhead] = *ev;
eventhead = (eventhead+1)&(NUM_EVENTS-1);
}

View file

@ -674,11 +674,6 @@ void CONFIG_SetupJoystick(void)
JoystickAnalogueSaturate[i] = (int32_t)strtoull(val, nullptr, 0);
}
for (int i = 0; i < MAXJOYBUTTONSANDHATS; i++)
{
CONTROL_MapButton(JoystickFunctions[i][0], i, 0, controldevice_joystick);
CONTROL_MapButton(JoystickFunctions[i][1], i, 1, controldevice_joystick);
}
for (int i = 0; i < MAXJOYAXES; i++)
{
CONTROL_MapAnalogAxis(i, JoystickAnalogueAxes[i], controldevice_joystick);
@ -699,7 +694,7 @@ void CONFIG_SetupJoystick(void)
static void CONFIG_SetJoystickButtonFunction(int i, int j, int function)
{
JoystickFunctions[i][j] = function;
CONTROL_MapButton(function, i, j, controldevice_joystick);
//CONTROL_MapButton(function, i, j, controldevice_joystick);
}
static void CONFIG_SetJoystickAnalogAxisScale(int i, int scale)
{

View file

@ -309,10 +309,7 @@ CUSTOM_CVARD(Int, in_mousedeadzone, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE, "amount o
else if (self > 512) self = 512;
}
CUSTOM_CVARD(Bool, in_mousesmoothing, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE, "enable/disable mouse input smoothing")
{
CONTROL_SmoothMouse = self;
}
CVARD(Bool, in_mousesmoothing, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE, "enable/disable mouse input smoothing")
CUSTOM_CVARD(Float, in_mousesensitivity, DEFAULTMOUSESENSITIVITY, CVAR_ARCHIVE|CVAR_GLOBALCONFIG, "changes the mouse sensitivity")
{

View file

@ -0,0 +1,66 @@
#include "inputstate.h"
#include "v_draw.h"
#include "build.h"
#include "gamecvars.h"
int32_t InputState::mouseReadAbs(vec2_t * const pResult)
{
auto pInput = &g_mouseAbs;
if (!g_mouseEnabled || !appactive || !g_mouseInsideWindow || GUICapture)
return 0;
int32_t const xwidth = max(scale(240<<16, screen->GetWidth(), screen->GetHeight()), 320<<16);
pResult->x = scale(pInput->x, xwidth, xres) - ((xwidth>>1) - (320<<15));
pResult->y = scale(pInput->y, 200<<16, yres);
pResult->y = divscale16(pResult->y - (200<<15), rotatesprite_yxaspect) + (200<<15) - rotatesprite_y_offset;
return 1;
}
void InputState::GetMouseDelta(ControlInfo * info)
{
vec2_t input;
if (!g_mouseEnabled || !g_mouseGrabbed || !appactive)
{
input = {0,0};
return;
}
input = g_mousePos;
g_mousePos = {};
vec2f_t finput = { float(input.x), float(input.y) };
if (in_mousesmoothing)
{
static vec2_t last;
finput = { float(input.x + last.x) * 0.5f, float(input.y + last.y) * 0.5f };
last = input;
}
info->mousex = int(finput.x * (4.f / 65536.f) * in_mousesensitivity * in_mousescalex);
info->mousey = int(finput.y * (4.f / 65536.f) * in_mousesensitivity * in_mousescaley);
}
void InputState::AddEvent(const event_t *ev)
{
// Set the old mouseBits. Yet another piece of cruft that needs to go away.
if (ev->type == EV_KeyDown || ev->type == EV_KeyUp)
{
switch (ev->data1)
{
case KEY_MOUSE1 : mouseSetBit(LEFT_MOUSE, ev->type == EV_KeyDown); handleevents_updatemousestate(ev->type); break;
case KEY_MOUSE2 : mouseSetBit(RIGHT_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MOUSE3 : mouseSetBit(MIDDLE_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MOUSE4 : mouseSetBit(THUMB_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MWHEELUP: mouseSetBit(WHEELUP_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MWHEELDOWN: mouseSetBit(WHEELDOWN_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MOUSE5: mouseSetBit(THUMB2_MOUSE, ev->type == EV_KeyDown); break;
default: break;
}
}
keySetState(ev->data1, ev->type == EV_KeyDown);
if (ev->data2) keySetChar(ev->data2);
}

View file

@ -23,8 +23,6 @@ enum
extern bool CONTROL_BindsEnabled;
extern vec2_t g_mousePos;
extern vec2_t g_mouseAbs;
extern bool g_mouseGrabbed;
extern bool g_mouseEnabled;
extern bool g_mouseInsideWindow;
@ -51,6 +49,18 @@ enum
MOUSE_RELEASED,
};
struct ControlInfo
{
int32_t dx;
int32_t dy;
int32_t dz;
int32_t dyaw;
int32_t dpitch;
int32_t droll;
int32_t mousex;
int32_t mousey;
};
class InputState
{
@ -72,6 +82,10 @@ class InputState
int g_mouseBits;
uint8_t g_mouseClickState;
vec2_t g_mousePos;
vec2_t g_mouseAbs;
public:
uint8_t GetKeyStatus(int key)
@ -240,26 +254,7 @@ public:
g_mouseClickState = state == EV_KeyUp ? MOUSE_RELEASED : MOUSE_PRESSED;
}
void AddEvent(const event_t *ev)
{
// Set the old mouseBits. Yet another piece of cruft that needs to go away.
if (ev->type == EV_KeyDown || ev->type == EV_KeyUp)
{
switch (ev->data1)
{
case KEY_MOUSE1 : mouseSetBit(LEFT_MOUSE, ev->type == EV_KeyDown); handleevents_updatemousestate(ev->type); break;
case KEY_MOUSE2 : mouseSetBit(RIGHT_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MOUSE3 : mouseSetBit(MIDDLE_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MOUSE4 : mouseSetBit(THUMB_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MWHEELUP: mouseSetBit(WHEELUP_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MWHEELDOWN: mouseSetBit(WHEELDOWN_MOUSE, ev->type == EV_KeyDown); break;
case KEY_MOUSE5: mouseSetBit(THUMB2_MOUSE, ev->type == EV_KeyDown); break;
default: break;
}
}
keySetState(ev->data1, ev->type == EV_KeyDown);
if (ev->data2) keySetChar(ev->data2);
}
void AddEvent(const event_t* ev);
int32_t mouseReadButtons(void)
{
@ -288,9 +283,25 @@ public:
return 0;
}
void MouseSetPos(int x, int y)
{
g_mousePos = { x, y };
}
void MouseAddToPos(int x, int y)
{
g_mousePos.x += x;
g_mousePos.y += y;
}
void MouseSetAbs(int x, int y)
{
g_mouseAbs = { x, y };
}
int32_t MouseGetButtons(void) { return mouseReadButtons(); }
inline void MouseClearButton(int32_t b) { g_mouseBits &= ~b; }
inline void MouseClearAllButtonss(void) { g_mouseBits = 0; }
int32_t mouseReadAbs(vec2_t* const pResult);
void GetMouseDelta(ControlInfo* info);
};
typedef enum

View file

@ -3138,8 +3138,6 @@ static int32_t Menu_EntryOptionModify(MenuEntry_t *entry, int32_t newOption)
}
else if (entry == &ME_SOUND_DUKETALK)
snd_speech = (snd_speech&~1) | newOption;
else if (entry == &ME_MOUSESETUP_SMOOTH)
CONTROL_SmoothMouse = in_mousesmoothing;
else if (entry == &ME_JOYSTICK_ENABLE)
{
if (newOption)
@ -4243,7 +4241,7 @@ void Menu_Open(uint8_t playerID)
{
g_player[playerID].ps->gm |= MODE_MENU;
mouseReadAbs(&m_prevmousepos, &g_mouseAbs);
inputState.mouseReadAbs(&m_prevmousepos);
m_mouselastactivity = -M_MOUSETIMEOUT;
#if !defined EDUKE32_TOUCH_DEVICES
@ -6768,7 +6766,7 @@ void M_DisplayMenus(void)
if (!Menu_IsTextInput(m_currentMenu) && inputState.GetKeyStatus(sc_Q))
Menu_AnimateChange(MENU_QUIT, MA_Advance);
int32_t mousestatus = mouseReadAbs(&m_mousepos, &g_mouseAbs);
int32_t mousestatus = inputState.mouseReadAbs(&m_mousepos);
if (mousestatus && inputState.mouseClickState() == MOUSE_PRESSED)
m_mousedownpos = m_mousepos;

View file

@ -31,6 +31,7 @@
#include "c_cvars.h"
#include "glbackend.h"
#include "v_draw.h"
#include "palette.h"
//===========================================================================
//
@ -197,3 +198,95 @@ void GLInstance::Draw2D(F2DDrawer *drawer)
twod.Clear();
EnableMultisampling(true);
}
void fullscreen_tint_gl(PalEntry pe)
{
// Todo: reroute to the 2D drawer
auto oldproj = GLInterface.GetMatrix(Matrix_Projection);
auto oldmv = GLInterface.GetMatrix(Matrix_ModelView);
VSMatrix identity(0);
GLInterface.SetMatrix(Matrix_Projection, &identity);
GLInterface.SetMatrix(Matrix_ModelView, &identity);
GLInterface.EnableDepthTest(false);
GLInterface.EnableAlphaTest(false);
GLInterface.SetBlendFunc(STYLEALPHA_Src, STYLEALPHA_InvSrc);
GLInterface.EnableBlend(true);
GLInterface.SetColorub (pe.r, pe.g, pe.b, pe.a);
GLInterface.UseColorOnly(true);
auto data = GLInterface.AllocVertices(3);
auto vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.UseColorOnly(false);
GLInterface.SetMatrix(Matrix_Projection, &oldproj);
GLInterface.SetMatrix(Matrix_ModelView, &oldmv);
}
void fullscreen_tint_gl_blood(int tint_blood_r, int tint_blood_g, int tint_blood_b)
{
if (!(tint_blood_r | tint_blood_g | tint_blood_b))
return;
auto oldproj = GLInterface.GetMatrix(Matrix_Projection);
auto oldmv = GLInterface.GetMatrix(Matrix_ModelView);
VSMatrix identity(0);
GLInterface.SetMatrix(Matrix_Projection, &identity);
GLInterface.SetMatrix(Matrix_ModelView, &identity);
GLInterface.EnableDepthTest(false);
GLInterface.EnableAlphaTest(false);
GLInterface.SetBlendFunc(STYLEALPHA_One, STYLEALPHA_One);
GLInterface.EnableBlend(true);
GLInterface.UseColorOnly(true);
GLInterface.SetColorub(max(tint_blood_r, 0), max(tint_blood_g, 0), max(tint_blood_b, 0), 255);
auto data = GLInterface.AllocVertices(3);
auto vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.SetBlendOp(STYLEOP_RevSub);
GLInterface.SetColorub(max(-tint_blood_r, 0), max(-tint_blood_g, 0), max(-tint_blood_b, 0), 255);
data = GLInterface.AllocVertices(3);
vt = data.second;
vt[0].Set(-2.5f, 1.f);
vt[1].Set(2.5f, 1.f);
vt[2].Set(.0f, -2.5f);
GLInterface.Draw(DT_TRIANGLES, data.first, 3);
GLInterface.SetBlendOp(STYLEOP_Add);
GLInterface.SetColorub(0, 0, 0, 0);
GLInterface.SetBlendFunc(STYLEALPHA_Src, STYLEALPHA_InvSrc);
GLInterface.UseColorOnly(false);
GLInterface.SetMatrix(Matrix_Projection, &oldproj);
GLInterface.SetMatrix(Matrix_ModelView, &oldmv);
}
static int32_t tint_blood_r = 0, tint_blood_g = 0, tint_blood_b = 0;
extern palette_t palfadergb;
extern char palfadedelta ;
void DrawFullscreenBlends()
{
if (palfadedelta) fullscreen_tint_gl(PalEntry(palfadedelta, palfadergb.r, palfadergb.g, palfadergb.b));
fullscreen_tint_gl_blood(tint_blood_r, tint_blood_g, tint_blood_b);
}
void videoTintBlood(int32_t r, int32_t g, int32_t b)
{
tint_blood_r = r;
tint_blood_g = g;
tint_blood_b = b;
}

View file

@ -69,19 +69,6 @@ typedef enum
analog_maxtype
} analogcontrol;
typedef struct
{
int32_t dx;
int32_t dy;
int32_t dz;
int32_t dyaw;
int32_t dpitch;
int32_t droll;
int32_t mousex;
int32_t mousey;
} ControlInfo;
typedef enum
{
controltype_keyboard,
@ -155,12 +142,7 @@ extern LastSeenInput CONTROL_LastSeenInput;
// PROTOTYPES
//
//***************************************************************************
//void CONTROL_MapKey( int32_t which, kb_scancode key1, kb_scancode key2 );
void CONTROL_MapButton(int whichfunction, int whichbutton, int doubleclicked, controldevice device);
int CONTROL_FlagActive( int which );
void CONTROL_ClearAssignments( void );
// void CONTROL_GetFunctionInput( void );
void CONTROL_GetInput( ControlInfo *info );
bool CONTROL_Startup(controltype which, int32_t ( *TimeFunction )( void ), int32_t ticspersecond);
@ -178,16 +160,10 @@ int32_t CONTROL_GetGameControllerDigitalAxisNeg(int32_t axis);
void CONTROL_ClearGameControllerDigitalAxisPos(int32_t axis);
void CONTROL_ClearGameControllerDigitalAxisNeg(int32_t axis);
//void CONTROL_PrintKeyMap(void);
//void CONTROL_PrintControlFlag(int32_t which);
//void CONTROL_PrintAxes( void );
////////// KEY/MOUSE BIND STUFF //////////
////////////////////
extern bool CONTROL_SmoothMouse;
#endif

View file

@ -1,38 +0,0 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 1996, 2003 - 3D Realms Entertainment
This file is part of Duke Nukem 3D version 1.5 - Atomic Edition
Duke Nukem 3D is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Original Source: 1996 - Todd Replogle
Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
*/
//-------------------------------------------------------------------------
#pragma once
#ifndef mouse_h_
#define mouse_h_
#include "baselayer.h"
#include "inputstate.h"
#endif /* __mouse_h */

View file

@ -37,14 +37,6 @@ static controlaxistype CONTROL_LastJoyAxes[MAXJOYAXES];
static int32_t CONTROL_JoyAxesScale[MAXJOYAXES];
static int8_t CONTROL_JoyAxesInvert[MAXJOYAXES];
static controlbuttontype CONTROL_MouseButtonMapping[MAXMOUSEBUTTONS];
static int32_t CONTROL_MouseButtonClicked[MAXMOUSEBUTTONS];
static int32_t CONTROL_MouseButtonClickedState[MAXMOUSEBUTTONS];
static int32_t CONTROL_MouseButtonClickedTime[MAXMOUSEBUTTONS];
static int32_t CONTROL_MouseButtonState[MAXMOUSEBUTTONS];
static uint8_t CONTROL_MouseButtonClickedCount[MAXMOUSEBUTTONS];
static controlbuttontype CONTROL_JoyButtonMapping[MAXJOYBUTTONS];
static int32_t CONTROL_JoyButtonClicked[MAXJOYBUTTONS];
@ -59,38 +51,9 @@ static uint8_t CONTROL_DoubleClickSpeed;
int32_t CONTROL_ButtonFlags[NUMKEYS];
bool CONTROL_BindsEnabled = 0;
bool CONTROL_SmoothMouse = 0;
#define CONTROL_CheckRange(which) ((unsigned)which >= (unsigned)NUMKEYS)
vec2_t g_mousePos; // Written to directly by the message pump.
vec2_t g_mouseAbs; // Used by the menus for some coodinate voodoo. Will be removed anyway so no need to refactor.
static void CONTROL_GetMouseDelta(ControlInfo * info)
{
vec2_t input;
if (!g_mouseEnabled || !g_mouseGrabbed || !appactive)
{
input = {0,0};
return;
}
input = g_mousePos;
g_mousePos = {};
vec2f_t finput = { float(input.x), float(input.y) };
if (CONTROL_SmoothMouse)
{
static vec2_t last;
finput = { float(input.x + last.x) * 0.5f, float(input.y + last.y) * 0.5f };
last = input;
}
info->mousex = mulscale16(Blrintf(finput.x * 4.f * in_mousesensitivity), in_mousescalex);
info->mousey = mulscale16(Blrintf(finput.y * 4.f * in_mousesensitivity), in_mousescaley);
}
static int32_t CONTROL_GetTime(void)
{
static int32_t t = 0;
@ -98,35 +61,6 @@ static int32_t CONTROL_GetTime(void)
return t;
}
void CONTROL_MapButton(int whichfunction, int whichbutton, int doubleclicked, controldevice device)
{
controlbuttontype *set;
if (CONTROL_CheckRange(whichfunction)) whichfunction = BUTTONUNDEFINED;
switch (device)
{
case controldevice_joystick:
if ((unsigned)whichbutton >= (unsigned)MAXJOYBUTTONS)
{
//Error("CONTROL_MapButton: button %d out of valid range for %d joystick buttons.",
// whichbutton, CONTROL_NumJoyButtons);
return;
}
set = CONTROL_JoyButtonMapping;
break;
default:
//Error("CONTROL_MapButton: invalid controller device type");
return;
}
if (doubleclicked)
set[whichbutton].doubleclicked = whichfunction;
else
set[whichbutton].singleclicked = whichfunction;
}
void CONTROL_MapAnalogAxis(int whichaxis, int whichanalog, controldevice device)
{
controlaxismaptype *set;
@ -254,9 +188,7 @@ void CONTROL_ClearAssignments(void)
memset(CONTROL_JoyAxesInvert, 0, sizeof(CONTROL_JoyAxesInvert));
memset(CONTROL_JoyAxesMap, AXISUNDEFINED, sizeof(CONTROL_JoyAxesMap));
memset(CONTROL_JoyButtonMapping, BUTTONUNDEFINED, sizeof(CONTROL_JoyButtonMapping));
// memset(CONTROL_KeyMapping, KEYUNDEFINED, sizeof(CONTROL_KeyMapping));
memset(CONTROL_LastJoyAxes, 0, sizeof(CONTROL_LastJoyAxes));
memset(CONTROL_MouseButtonMapping, BUTTONUNDEFINED, sizeof(CONTROL_MouseButtonMapping));
}
static int DoGetDeviceButtons(
@ -320,19 +252,6 @@ static void CONTROL_GetDeviceButtons(void)
{
int32_t const t = ExtGetTime();
if (CONTROL_MouseEnabled)
{
DoGetDeviceButtons(
inputState.MouseGetButtons(), t,
CONTROL_NumMouseButtons,
CONTROL_MouseButtonState,
CONTROL_MouseButtonClickedTime,
CONTROL_MouseButtonClickedState,
CONTROL_MouseButtonClicked,
CONTROL_MouseButtonClickedCount
);
}
if (CONTROL_JoystickEnabled)
{
int retval = DoGetDeviceButtons(
@ -450,7 +369,7 @@ static void CONTROL_PollDevices(ControlInfo *info)
memset(info, 0, sizeof(ControlInfo));
if (CONTROL_MouseEnabled)
CONTROL_GetMouseDelta(info);
inputState.GetMouseDelta(info);
if (CONTROL_JoystickEnabled)
{

View file

@ -3554,8 +3554,6 @@ static int32_t Menu_EntryOptionModify(MenuEntry_t *entry, int32_t newOption)
}
else if (entry == &ME_SOUND_DUKETALK)
snd_speech = (snd_speech&~1) | newOption;
else if (entry == &ME_MOUSESETUP_SMOOTH)
CONTROL_SmoothMouse = in_mousesmoothing;
else if (entry == &ME_JOYSTICKAXIS_ANALOG)
CONTROL_MapAnalogAxis(M_JOYSTICKAXES.currentEntry, newOption, controldevice_joystick);
else if (entry == &ME_NETOPTIONS_EPISODE)
@ -4586,7 +4584,7 @@ void Menu_Open(uint8_t playerID)
{
g_player[playerID].ps->gm |= MODE_MENU;
mouseReadAbs(&m_prevmousepos, &g_mouseAbs);
inputState.mouseReadAbs(&m_prevmousepos);
m_mouselastactivity = -M_MOUSETIMEOUT;
#if !defined EDUKE32_TOUCH_DEVICES
@ -7367,7 +7365,7 @@ void M_DisplayMenus(void)
if (!Menu_IsTextInput(m_currentMenu) && inputState.GetKeyStatus(sc_Q))
Menu_AnimateChange(MENU_QUIT, MA_Advance);
int32_t mousestatus = mouseReadAbs(&m_mousepos, &g_mouseAbs);
int32_t mousestatus = inputState.mouseReadAbs(&m_mousepos);
if (mousestatus && inputState.mouseClickState() == MOUSE_PRESSED)
m_mousedownpos = m_mousepos;

View file

@ -972,101 +972,13 @@ static SWBOOL MNU_MouseButtonPostProcess(MenuItem_p item)
SWBOOL MNU_MouseButtonSetupCustom(UserCall call, MenuItem_p item)
{
#if 0
static int currentfunc = 0;
if (call == uc_touchup)
return TRUE;
if (cust_callback == NULL)
{
if (call != uc_setup)
return FALSE;
if (mouse_button_item->tics >= 6)
{
currentfunc = MouseButtonsClicked[mouse_button_item->tics % 6];
}
else
{
currentfunc = MouseButtons[mouse_button_item->tics % 6];
}
currentfunc++;
cust_callback = MNU_MouseButtonSetupCustom;
cust_callback_call = call;
cust_callback_item = item;
}
{
short w, h = 0;
const char *s = "Mouse Setup";
rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
MNU_MeasureStringLarge(s, &w, &h);
MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
}
int selection = MNU_SelectButtonFunction(mouse_button_item->text, &currentfunc);
switch (selection)
{
case -1: //cancel
cust_callback = NULL;
break;
case 1: //acknowledge
currentfunc--;
if (mouse_button_item->tics >= 6)
{
MouseButtonsClicked[mouse_button_item->tics % 6] = currentfunc;
CONTROL_MapButton(currentfunc, mouse_button_item->tics % 6, 1, controldevice_mouse);
}
else
{
MouseButtons[mouse_button_item->tics % 6] = currentfunc;
CONTROL_MapButton(currentfunc, mouse_button_item->tics % 6, 0, controldevice_mouse);
}
MNU_SetMouseButtonFunctions(mouse_button_item);
cust_callback = NULL;
break;
default: break;
}
#endif
// Mouse buttons are now handled as normal keybinds
return TRUE;
}
static SWBOOL MNU_SetMouseButtonFunctions(MenuItem_p item)
{
#if 0
int button, clicked, function;
char *p;
clicked = item->tics >= 6;
button = item->tics % 6;
ASSERT(button >= 0 && button <= 5);
if (clicked)
{
function = MouseButtonsClicked[button];
}
else
{
function = MouseButtons[button];
}
if (function < 0)
{
strcpy(MouseButtonFunctions[item->tics], " -");
}
else
{
strcpy(MouseButtonFunctions[item->tics], buttonMap.GetButtonName(function));
for (p = MouseButtonFunctions[item->tics]; *p; p++)
{
if (*p == '_')
*p = ' ';
}
}
#endif
// Mouse buttons are now handled as normal keybinds
return TRUE;
}
@ -1081,76 +993,13 @@ static SWBOOL MNU_MouseDigitalPostProcess(MenuItem_p item)
static SWBOOL MNU_MouseDigitalSetupCustom(UserCall call, MenuItem_p item)
{
#if 0
static int currentfunc = 0;
if (call == uc_touchup)
return TRUE;
if (cust_callback == NULL)
{
if (call != uc_setup)
return FALSE;
currentfunc = MouseDigitalAxes[mouse_digital_item->tics/2][mouse_digital_item->tics%2];
currentfunc++;
cust_callback = MNU_MouseDigitalSetupCustom;
cust_callback_call = call;
cust_callback_item = item;
}
{
short w, h = 0;
const char *s = "Adv'd Mouse";
rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
MNU_MeasureStringLarge(s, &w, &h);
MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
}
int selection = MNU_SelectButtonFunction(mouse_digital_item->text, &currentfunc);
switch (selection)
{
case -1: //cancel
cust_callback = NULL;
break;
case 1: //acknowledge
currentfunc--;
MouseDigitalAxes[mouse_digital_item->tics/2][mouse_digital_item->tics%2] = currentfunc;
CONTROL_MapDigitalAxis(mouse_digital_item->tics/2, currentfunc, mouse_digital_item->tics%2, controldevice_mouse);
MNU_SetAdvancedMouseFunctions(mouse_digital_item);
cust_callback = NULL;
break;
default: break;
}
#endif
// obsolete
return TRUE;
}
static SWBOOL MNU_SetAdvancedMouseFunctions(MenuItem_p item)
{
#if 0
int axis;
char *p;
axis = item->tics;
ASSERT(axis >= 0 && axis < 4);
if (MouseDigitalAxes[axis/2][axis%2] < 0)
{
strcpy(AdvancedMouseAxisFunctions[axis], " -");
}
else
{
strcpy(AdvancedMouseAxisFunctions[axis], buttonMap.GetButtonName(MouseDigitalAxes[axis/2][axis%2]));
for (p = AdvancedMouseAxisFunctions[axis]; *p; p++)
{
if (*p == '_')
*p = ' ';
}
}
#endif
// obsolete
return TRUE;
}
@ -1275,66 +1124,7 @@ static SWBOOL MNU_JoystickButtonPostProcess(MenuItem_p item)
static SWBOOL MNU_JoystickButtonSetupCustom(UserCall call, MenuItem *item)
{
#if 0
static int currentfunc = 0;
if (call == uc_touchup)
return TRUE;
if (cust_callback == NULL)
{
if (call != uc_setup)
return FALSE;
if (joystick_button_item->tics & 128)
{
currentfunc = JoystickButtonsClicked[joystick_button_item->tics & 127];
}
else
{
currentfunc = JoystickButtons[joystick_button_item->tics & 127];
}
currentfunc++;
cust_callback = MNU_JoystickButtonSetupCustom;
cust_callback_call = call;
cust_callback_item = item;
}
{
short w, h = 0;
const char *s = "Joystick Setup";
rotatesprite(10 << 16, (5-3) << 16, MZ, 0, 2427,
m_defshade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
MNU_MeasureStringLarge(s, &w, &h);
MNU_DrawStringLarge(TEXT_XCENTER(w), 5, s);
}
int selection = MNU_SelectButtonFunction(joystick_button_item->text, &currentfunc);
switch (selection)
{
case -1: //cancel
cust_callback = NULL;
break;
case 1: //acknowledge
currentfunc--;
if (joystick_button_item->tics & 128)
{
JoystickButtonsClicked[joystick_button_item->tics & 127] = currentfunc;
CONTROL_MapButton(currentfunc, joystick_button_item->tics & 127, 1, controldevice_joystick);
}
else
{
JoystickButtons[joystick_button_item->tics & 127] = currentfunc;
CONTROL_MapButton(currentfunc, joystick_button_item->tics & 127, 0, controldevice_joystick);
}
MNU_SetJoystickButtonFunctions(joystick_button_item);
cust_callback = NULL;
break;
default: break;
}
#endif
// controller buttons are being handled as keybinds now
return TRUE;
}
@ -1349,36 +1139,7 @@ static SWBOOL MNU_JoystickButtonNextPage(void)
static SWBOOL MNU_SetJoystickButtonFunctions(MenuItem_p item)
{
#if 0
int button, clicked, function;
char *p;
clicked = (item->tics & 128) > 0;
button = item->tics & 127;
ASSERT(button >= 0 && button < MAXJOYBUTTONS);
if (clicked)
{
function = JoystickButtonsClicked[button];
}
else
{
function = JoystickButtons[button];
}
if (function < 0)
{
strcpy(JoystickButtonFunctions[button + clicked*MAXJOYBUTTONS], " -");
}
else
{
strcpy(JoystickButtonFunctions[button + clicked*MAXJOYBUTTONS], buttonMap.GetButtonName(function));
for (p = JoystickButtonFunctions[button + clicked*MAXJOYBUTTONS]; *p; p++)
{
if (*p == '_')
*p = ' ';
}
}
#endif
// controller buttons are being handled as keybinds now
return TRUE;
}