fteqw/quakec/menusys/menusys/mitem_desktop.qc
Spoike 9e8bb446f4 implemented pm_stepdown.
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
2018-01-22 19:18:04 +00:00

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