attempt to implement 'simple csqc' api. handle qw+nq gunshot+blood+lightning differently - they do actually have different particle spawn patterns (qw is a single point, so spreads wider). fix q3ui logo mesh thing. work around q3ui player meshes on d3d. split video and renderer latching, so vid_reload delatches more stuff. fix autosprite+autosprite2 in 6 different renderers... added fog volumes to d3d9 renderer. using matrix hacks instead of glDepthRange, this should give more consistent behaviour, especially now that we have r_viewmodel_fov. small cleanup for gl shadowmaps to make the interface more consistent with other renderers. added patchDef2 parsing to fte's .map loader, doesn't actually use it though. some fixes for q3's shaders, including to try to get overbright working better. updated customskin api to give more control. first attempt at a packager system for fteqccgui. probably useless, but whatever. menusys changes to try to support QSS's csqc. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5200 fc73d0e0-1445-4013-8a0c-d673dee63da5
465 lines
12 KiB
C++
465 lines
12 KiB
C++
/***************************************************************************
|
|
desktop and top-level functions.
|
|
*/
|
|
|
|
#ifdef USEPOINTERS
|
|
typedef mitem mitem_desktop;
|
|
#else
|
|
class mitem_desktop : mitem_frame
|
|
{
|
|
virtual float(vector pos, float scan, float char, float down) item_keypress;
|
|
virtual void(mitem newfocus, float flag) item_focuschange;
|
|
virtual void(vector pos) item_draw; //draws the game, then calls mitem_frame::item_draw for children.
|
|
#ifndef MENU
|
|
virtual void(float seat, vector minpos, vector size) drawgame = __NULL__; //if overridden, should call renderscene and then draw whatever hud it needs to. this will do splitscreen efficiently and automatically.
|
|
#endif
|
|
void() mitem_desktop; //the constructor. uninteresting. just ensures the size defaults to fullscreen.
|
|
};
|
|
#endif
|
|
|
|
#if !defined(MENU) && !defined(CSQC_SIMPLE)
|
|
float sb_showscores;
|
|
#endif
|
|
|
|
float drawfont;
|
|
float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357;
|
|
|
|
void() mitem_desktop::mitem_desktop =
|
|
{
|
|
#define menu_font_win autocvar(menu_font_win, "cour")
|
|
#define menu_font autocvar(menu_font, "")
|
|
#define menu_font_fallback autocvar(gl_font, "")
|
|
queryscreensize();
|
|
|
|
if (checkextension("DP_GFX_FONTS"))
|
|
{
|
|
//make sure we have a font that can cope with slightly up-scaled stuff.
|
|
//windows is special because we can load from the system fonts
|
|
string fontname = menu_font_fallback;
|
|
if (menu_font_win != "" && !strncasecmp(cvar_string("sys_platform"), "Win", 3))
|
|
fontname = menu_font_win;
|
|
else if (menu_font != "")
|
|
fontname = menu_font;
|
|
drawfont = loadfont("", fontname, "8 12 16", -1);
|
|
}
|
|
|
|
item_text = "desktop";
|
|
if (!item_flags)
|
|
{
|
|
item_size = ui.screensize;
|
|
item_flags = IF_SELECTABLE | IF_MFOCUSED | IF_KFOCUSED | IF_RESIZABLE | IF_NOCURSOR;
|
|
}
|
|
|
|
if (!ui.kgrabs && !ui.mgrabs && (item_flags & IF_NOCURSOR))
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
};
|
|
|
|
void(mitem newfocus, float flag) mitem_desktop::item_focuschange =
|
|
{
|
|
super::item_focuschange(newfocus, flag);
|
|
|
|
if (flag & IF_KFOCUSED)
|
|
{
|
|
//if we're deselecting the current one, reenable grabs
|
|
if (newfocus == __NULL__)
|
|
{
|
|
if(item_flags & IF_NOCURSOR)
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ui.kgrabs == this)
|
|
{
|
|
ui.kgrabs = __NULL__;
|
|
ui.mgrabs = __NULL__;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
//the interact flag says that the mouse is held down on the desktop
|
|
float(vector pos, float scan, float char, float down) mitem_desktop::item_keypress =
|
|
{
|
|
float oldfl = item_flags;
|
|
|
|
if (down & 2)
|
|
{
|
|
down &= 1;
|
|
//if we're grabbing, then cancel if they press escape, otherwise block other items from taking the keys.
|
|
if (scan >= K_MOUSE1 && scan <= K_MOUSE5)
|
|
return 2; //block other wigits, don't cancel the event so the engine still does its thing
|
|
else
|
|
{
|
|
if (scan == K_ESCAPE && down)
|
|
{
|
|
local mitem sc;
|
|
//block the keyevent if we already have menus loaded but not focused (select one if we do).
|
|
for (sc = item_children; sc; sc = sc.item_next)
|
|
{
|
|
if (sc.item_flags & IF_SELECTABLE)
|
|
{
|
|
if (!item_kactivechild)
|
|
item_focuschange(sc, IF_KFOCUSED);
|
|
return 3;
|
|
}
|
|
}
|
|
//make sure our code takes it, instead of showing the engine menu...
|
|
#ifdef MENU
|
|
m_toggle(0);
|
|
return 3;
|
|
#else
|
|
return 2|CSQC_ConsoleCommand("togglemenu");
|
|
#endif
|
|
}
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
if (mitem_frame::item_keypress(pos, scan, char, down))
|
|
return TRUE;
|
|
|
|
if (scan == K_MOUSE1 && down)
|
|
{
|
|
#if defined(CSQC) && defined(FTE_SPLITSCREEN)
|
|
if (numclientseats)
|
|
localcmd("in_forcesplitclient 0\n");
|
|
#endif
|
|
if (item_flags & IF_NOCURSOR)
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
return TRUE;
|
|
}
|
|
if (scan == K_MOUSE2 && down)
|
|
{
|
|
#if defined(CSQC) && defined(FTE_SPLITSCREEN)
|
|
if (numclientseats > 3)
|
|
localcmd(strcat("in_forcesplitclient ", ftos(1 + ((ui.mousepos[0]>ui.screensize[0]/2)?1:0) + ((ui.mousepos[1]>ui.screensize[1]/2)?2:0)), "\n"));
|
|
else if (numclientseats > 1)
|
|
localcmd(strcat("in_forcesplitclient ", ftos(1 + floor(ui.mousepos[1]*numclientseats/ui.screensize[1])), "\n"));
|
|
else if (numclientseats)
|
|
localcmd("in_forcesplitclient 0\n");
|
|
#endif
|
|
if (item_flags & IF_NOCURSOR)
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef CSQC
|
|
//catch otherwise unhangled escape presses, just to be sure we can use escape to toggle the menu
|
|
if (scan == K_ESCAPE && down)
|
|
{
|
|
return CSQC_ConsoleCommand("togglemenu");
|
|
}
|
|
#endif
|
|
return FALSE;
|
|
};
|
|
|
|
#if !defined(MENU) && !defined(CSQC_SIMPLE)
|
|
static vector(vector v) vtodpp =
|
|
{
|
|
//so fucking disgustingly ugly.
|
|
if (dp_workarounds)
|
|
{
|
|
v_x *= cvar("vid_width") / cvar("vid_conwidth");
|
|
v_y *= cvar("vid_height") / cvar("vid_conheight");
|
|
}
|
|
return v;
|
|
};
|
|
|
|
//vector pmove_org;
|
|
void(float seat, vector minpos, vector size) mitem_desktop::drawgame_helper =
|
|
{
|
|
if not(seat)
|
|
{
|
|
clearscene();
|
|
addentities(MASK_ENGINE|MASK_VIEWMODEL);
|
|
}
|
|
else
|
|
{
|
|
setviewprop(VF_LPLAYER, seat);
|
|
setproperty(VF_VIEWENTITY, player_localentnum);
|
|
addentities(MASK_VIEWMODEL); //don't do mask_engine because that's already done
|
|
}
|
|
// if (dp_workarounds)
|
|
// setproperty(VF_ORIGIN, pmove_org);
|
|
setproperty(VF_MIN, minpos);
|
|
setproperty(VF_SIZE, vtodpp(size));
|
|
|
|
setproperty(VF_DRAWCROSSHAIR, (ui.mgrabs == this));
|
|
|
|
drawgame(seat, minpos, size);
|
|
if (mouseinbox(minpos, size))
|
|
{
|
|
ui.havemouseworld = TRUE;
|
|
ui.mouseworldnear = unproject([ui.mousepos[0], ui.mousepos[1], 0]);
|
|
ui.mouseworldfar = unproject([ui.mousepos[0], ui.mousepos[1], 100000]);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
void(vector pos) mitem_desktop::item_draw =
|
|
{
|
|
#if !defined(MENU) && !defined(CSQC_SIMPLE)
|
|
//menuqc picks up the game/console as a background
|
|
string constate = serverkey("constate");
|
|
if (constate != "" && constate != "active") //allow empty, so things still kinda work with dp too.
|
|
{
|
|
drawfill(pos, ui.screensize, '0 0 0', 1, 0);
|
|
}
|
|
else if (this.drawgame != __NULL__)
|
|
{
|
|
#ifdef FTE_SPLITSCREEN
|
|
if (numclientseats > 3)
|
|
{
|
|
drawgame_helper(0, [0, 0], 0.5*ui.screensize);
|
|
drawgame_helper(1, [ui.screensize[0]*0.5, 0], 0.5*ui.screensize);
|
|
drawgame_helper(2, [0, ui.screensize[1]*0.5], 0.5*ui.screensize);
|
|
drawgame_helper(3, [ui.screensize[0]*0.5, ui.screensize[1]*0.5], 0.5*ui.screensize);
|
|
setviewprop(VF_LPLAYER, 0);
|
|
}
|
|
else if (numclientseats > 2)
|
|
{
|
|
drawgame_helper(0, [0, 0], [ui.screensize[0], ui.screensize[1]*0.333]);
|
|
drawgame_helper(1, [0, ui.screensize[1]*0.333], [ui.screensize[0], ui.screensize[1]*0.333]);
|
|
drawgame_helper(2, [0, ui.screensize[1]*0.666], [ui.screensize[0], ui.screensize[1]*0.333]);
|
|
setviewprop(VF_LPLAYER, 0);
|
|
}
|
|
else if (numclientseats > 1)
|
|
{
|
|
drawgame(0, [0, 0], [ui.screensize[0], ui.screensize[1]*0.5]);
|
|
drawgame(1, [0, ui.screensize[1]*0.5], [ui.screensize[0], ui.screensize[1]*0.5]);
|
|
setviewprop(VF_LPLAYER, 0);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
drawgame_helper(0, '0 0', ui.screensize);
|
|
}
|
|
}
|
|
#endif
|
|
super::item_draw(pos);
|
|
|
|
if (ui.kgrabs == this)
|
|
{
|
|
#if defined(CSQC) && !defined(CSQC_SIMPLE)
|
|
if (sb_showscores && ui.mgrabs == this)
|
|
ui.mgrabs = __NULL__;
|
|
else
|
|
#endif
|
|
if (!ui.mgrabs)
|
|
ui.mgrabs = this;
|
|
}
|
|
};
|
|
|
|
|
|
var string autocvar_cl_cursor = "gfx/cursor.lmp";
|
|
var float autocvar_cl_cursorsize = 32;
|
|
var float autocvar_cl_cursorbias = 4;
|
|
|
|
static var float oldgrabstate; //to work around a DP bug (as well as unnecessary spam)
|
|
|
|
void(float force) items_updategrabs =
|
|
{
|
|
if (!ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR))
|
|
{
|
|
if (!oldgrabstate || force)
|
|
{
|
|
oldgrabstate = TRUE;
|
|
#ifdef MENU
|
|
setkeydest(2);
|
|
setmousetarget(2);
|
|
#else
|
|
setcursormode(TRUE);
|
|
//setcursormode(TRUE, autocvar_cl_cursor, autocvar_cl_cursorbias*'1 1', autocvar_cl_cursorscale);
|
|
#endif
|
|
}
|
|
}
|
|
else if (oldgrabstate || force)
|
|
{
|
|
oldgrabstate = FALSE;
|
|
#ifdef MENU
|
|
setkeydest(0);
|
|
setmousetarget(1);
|
|
#else
|
|
setcursormode(FALSE);
|
|
#endif
|
|
}
|
|
};
|
|
|
|
void(mitem_desktop desktop) items_draw =
|
|
{
|
|
queryscreensize();
|
|
|
|
#ifdef MENU
|
|
ui.mousepos = getmousepos();
|
|
#else
|
|
if (ui.havemouseworld)
|
|
ui.havemouseworld = 2; //stale, but not too stale
|
|
#endif
|
|
|
|
if (desktop.item_size != ui.screensize)
|
|
{
|
|
desktop.item_size = ui.screensize;
|
|
desktop.item_resized();
|
|
}
|
|
ui.drawrectmax = ui.screensize;
|
|
|
|
desktop.item_draw(desktop.item_position);
|
|
drawresetcliparea();
|
|
|
|
items_updategrabs(FALSE);
|
|
if (dp_workarounds && oldgrabstate)
|
|
{
|
|
if (drawgetimagesize(autocvar_cl_cursor) == '0 0')
|
|
ui.drawcharacter(ui.mousepos - [stringwidth("+", TRUE, '4 4')*0.5, 4], '+', '8 8', '1 1 1', 1, 0);
|
|
else
|
|
ui.drawpic(ui.mousepos - autocvar_cl_cursorbias*'1 1', autocvar_cl_cursor, autocvar_cl_cursorsize*'1 1', '1 1 1', 1, 0);
|
|
}
|
|
|
|
#ifndef MENU
|
|
if (ui.havemouseworld == 2) //if its still stale then its totally invalid.
|
|
ui.havemouseworld = FALSE;
|
|
#endif
|
|
ui.oldmousepos = ui.mousepos;
|
|
};
|
|
|
|
#ifdef CSQC
|
|
//items_keypress has quite strong dimorphism. These are meant to tailored to the target's available event notifications, rather than being really rather annoying.
|
|
csqconly float(mitem_desktop desktop, float evtype, float scanx, float chary, float devid) items_keypress =
|
|
{
|
|
local float result = FALSE;
|
|
vector pos;
|
|
mitem p;
|
|
switch(evtype)
|
|
{
|
|
case IE_KEYDOWN:
|
|
case IE_KEYUP:
|
|
if (scanx == K_SHIFT)
|
|
ui.shiftheld = evtype==IE_KEYDOWN;
|
|
#ifdef HEIRACHYDEBUG
|
|
if (scanx == K_F1 && evtype == IE_KEYDOWN)
|
|
{
|
|
mitem_printtree(desktop, "items_keypress", __LINE__);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
if (scanx >= K_MOUSE1 && scanx <= K_MOUSE5)
|
|
{
|
|
if (ui.mgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.mgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.mgrabs.item_keypress(pos, scanx, chary, (evtype == IE_KEYDOWN)|2);
|
|
if (result & 2)
|
|
{
|
|
ui.mousedown = 0;
|
|
return result & 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ui.kgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.kgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.kgrabs.item_keypress(pos, scanx, chary, (evtype == IE_KEYDOWN)|2);
|
|
if (result & 2)
|
|
return result & 1;
|
|
}
|
|
}
|
|
if (desktop && desktop.item_keypress)
|
|
result = desktop.item_keypress(desktop.item_position, scanx, chary, evtype == IE_KEYDOWN);
|
|
if (scanx >= K_MOUSE1 && scanx <= K_MOUSE5)
|
|
{
|
|
if (evtype == IE_KEYDOWN)
|
|
ui.mousedown |= pow(1, scanx-K_MOUSE1);
|
|
else
|
|
ui.mousedown &~= pow(1, scanx-K_MOUSE1);
|
|
}
|
|
result = result & 1;
|
|
break;
|
|
case IE_MOUSEDELTA:
|
|
result = !ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR);
|
|
if (result)
|
|
{
|
|
queryscreensize();
|
|
ui.mousepos[0] = bound(0, ui.mousepos[0]+scanx, ui.screensize[0]);
|
|
ui.mousepos[1] = bound(0, ui.mousepos[1]+chary, ui.screensize[1]);
|
|
}
|
|
break;
|
|
case IE_MOUSEABS:
|
|
ui.mousepos[0] = scanx;
|
|
ui.mousepos[1] = chary;
|
|
result = !ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR);
|
|
break;
|
|
}
|
|
return result;
|
|
};
|
|
#endif
|
|
|
|
#ifdef MENU
|
|
menuonly float(mitem_desktop desktop, float scan, float char, float down) items_keypress =
|
|
{
|
|
local float result = FALSE;
|
|
local vector pos;
|
|
local mitem p;
|
|
ui.mousepos = getmousepos();
|
|
queryscreensize();
|
|
#ifdef HEIRACHYDEBUG
|
|
if (scan == K_F1 && down)
|
|
{
|
|
mitem_printtree(desktop, "items_keypress", __LINE__);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (scan >= K_MOUSE1 && scan <= K_MOUSE5)
|
|
{
|
|
if (ui.mgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.mgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.mgrabs.item_keypress(pos, scan, char, (down)|2);
|
|
if (result & 2)
|
|
{
|
|
ui.mousedown = 0;
|
|
return result & 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ui.kgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.kgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.kgrabs.item_keypress(pos, scan, char, (down)|2);
|
|
if (result & 2)
|
|
return result & 1;
|
|
}
|
|
}
|
|
|
|
if (desktop && desktop.item_keypress)
|
|
result = desktop.item_keypress(desktop.item_position, scan, char, down);
|
|
|
|
return result;
|
|
};
|
|
#endif
|
|
|
|
|