Custom hardware cursors, fix missing cursor when running fullscreen.

This commit is contained in:
Shpoike 2020-07-08 15:38:08 +01:00
parent 54538a054a
commit 06fd012dfe
6 changed files with 115 additions and 70 deletions

View file

@ -75,6 +75,7 @@ static int nummodes;
static qboolean vid_initialized = false;
static SDL_Cursor *vid_cursor;
#if defined(USE_SDL2)
static SDL_Window *draw_context;
static SDL_GLContext gl_context;
@ -2346,3 +2347,70 @@ static void VID_Menu_f (void)
VID_Menu_RebuildRateList ();
}
void VID_UpdateCursor(void)
{
SDL_Cursor *nc;
qcvm_t *vm;
if (key_dest == key_menu)
vm = &cls.menu_qcvm;
else if (key_dest == key_game)
vm = &cl.qcvm;
else
vm = NULL;
nc = vm?vm->cursorhandle:NULL;
if (vid_cursor != nc)
{
vid_cursor = nc;
if (nc) //null is an invalid sdl cursor handle
SDL_SetCursor(nc);
else
SDL_SetCursor(SDL_GetDefaultCursor()); //doesn't need freeing or anything.
}
}
void VID_SetCursor(qcvm_t *vm, const char *cursorname, float hotspot[2], float cursorscale)
{
SDL_Cursor *oldcursor;
int mark = Hunk_LowMark();
qboolean malloced = false;
char npath[MAX_QPATH];
SDL_Surface *surf = NULL;
byte *imagedata = NULL;
if (cursorname && *cursorname)
{
enum srcformat fmt;
int width, height;
COM_StripExtension(cursorname, npath, sizeof(npath));
imagedata = Image_LoadImage(npath, &width, &height, &fmt, &malloced);
if (imagedata && fmt == SRC_RGBA)
{ //simple 32bit RGBA byte-ordered data.
surf = SDL_CreateRGBSurfaceFrom(imagedata, width, height, 32, width*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
if (cursorscale != 1 && surf)
{ //rescale image by cursorscale
int nwidth = q_max(1,width*cursorscale);
int nheight = q_max(1,height*cursorscale);
SDL_Surface *scaled = SDL_CreateRGBSurface(0, nwidth, nheight, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
SDL_BlitScaled(surf, NULL, scaled, NULL);
SDL_FreeSurface(surf);
surf = scaled;
}
}
}
oldcursor = vm->cursorhandle;
if (surf)
{
vm->cursorhandle = SDL_CreateColorCursor(surf, hotspot[0], hotspot[1]);
SDL_FreeSurface(surf);
}
else
vm->cursorhandle = NULL;
Hunk_FreeToLowMark(mark);
if (malloced)
free(imagedata);
VID_UpdateCursor();
if (oldcursor)
SDL_FreeCursor(oldcursor);
}

View file

@ -289,8 +289,9 @@ static void IN_UpdateGrabs_Internal(qboolean forecerelease)
qboolean freemouse; //the OS should have a free cursor too...
qboolean needevents; //whether we want to receive events still
wantcursor = (key_dest == key_console || (key_dest == key_menu&&!bind_grab)) || (key_dest == key_game && cl.qcvm.cursorforced);
freemouse = wantcursor && (modestate == MS_WINDOWED || (key_dest == key_game && cl.qcvm.cursorforced));
qboolean gamecodecursor = (key_dest == key_game && cl.qcvm.cursorforced) || (key_dest == key_menu && cls.menu_qcvm.cursorforced);
wantcursor = (key_dest == key_console || (key_dest == key_menu&&!bind_grab)) || gamecodecursor;
freemouse = wantcursor && (modestate == MS_WINDOWED || gamecodecursor);
needevents = (!wantcursor) || key_dest == key_game;
if (isDedicated)
@ -310,6 +311,16 @@ static void IN_UpdateGrabs_Internal(qboolean forecerelease)
#endif
#if defined(USE_SDL2)
if (wantcursor)
{
VID_UpdateCursor();
SDL_ShowCursor(SDL_ENABLE);
}
else
{
SDL_ShowCursor(SDL_DISABLE);
VID_UpdateCursor();
}
if (SDL_SetRelativeMouseMode(freemouse?SDL_FALSE:SDL_TRUE) != 0)
{
Con_Printf("WARNING: SDL_SetRelativeMouseMode(%s) failed.\n", freemouse?"SDL_FALSE":"SDL_TRUE");

View file

@ -54,9 +54,9 @@ static inline int IS_NAN (float x) {
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define DotProduct2(x,y) (x[0]*y[0]+x[1]*y[1])
#define DoublePrecisionDotProduct(x,y) ((double)x[0]*y[0]+(double)x[1]*y[1]+(double)x[2]*y[2])
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
#define VectorSubtract(a,b,c) (c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
#define VectorAdd(a,b,c) (c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
#define VectorCopy(a,b) (b[0]=a[0],b[1]=a[1],b[2]=a[2])
//johnfitz -- courtesy of lordhavoc
// QuakeSpasm: To avoid strict aliasing violations, use a float/int union instead of type punning.

View file

@ -37,7 +37,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern cvar_t sv_gameplayfix_setmodelrealbox;
cvar_t pr_checkextension = {"pr_checkextension", "1", CVAR_NONE}; //spike - enables qc extensions. if 0 then they're ALL BLOCKED! MWAHAHAHA! *cough* *splutter*
int pr_ext_warned_particleeffectnum; //so these only spam once per map
static int pr_ext_warned_particleeffectnum; //so these only spam once per map
static void *PR_FindExtGlobal(int type, const char *name);
void SV_CheckVelocity (edict_t *ent);
@ -1349,7 +1349,7 @@ static struct {
unsigned int start;
unsigned int end;
} qctoken[MAXQCTOKENS];
unsigned int qctoken_count;
static unsigned int qctoken_count;
static void tokenize_flush(void)
{
@ -1379,7 +1379,7 @@ static int tokenizeqc(const char *str, qboolean dpfuckage)
while (qctoken_count < MAXQCTOKENS)
{
/*skip whitespace here so the token's start is accurate*/
while (*str && *(unsigned char*)str <= ' ')
while (*str && *(const unsigned char*)str <= ' ')
str++;
if (!*str)
@ -2900,7 +2900,7 @@ static void PF_fsize(void)
}
#endif
struct filesearch_s
static struct filesearch_s
{
qcvm_t *owner;
size_t numfiles;
@ -3061,7 +3061,7 @@ struct strbuf {
#define BUFSTRBASE 1
#define NUMSTRINGBUFS 64u
struct strbuf strbuflist[NUMSTRINGBUFS];
static struct strbuf strbuflist[NUMSTRINGBUFS];
static void PF_buf_shutdown(void)
{
@ -3184,11 +3184,11 @@ static void PF_buf_copy(void)
static int PF_buf_sort_sortprefixlen;
static int PF_buf_sort_ascending(const void *a, const void *b)
{
return strncmp(*(char**)a, *(char**)b, PF_buf_sort_sortprefixlen);
return strncmp(*(char*const*)a, *(char*const*)b, PF_buf_sort_sortprefixlen);
}
static int PF_buf_sort_descending(const void *b, const void *a)
{
return strncmp(*(char**)a, *(char**)b, PF_buf_sort_sortprefixlen);
return strncmp(*(char*const*)a, *(char*const*)b, PF_buf_sort_sortprefixlen);
}
// #444 void(float bufhandle, float sortprefixlen, float backward) buf_sort (DP_QC_STRINGBUFFERS)
static void PF_buf_sort(void)
@ -4161,7 +4161,7 @@ static void PF_crc16(void)
G_FLOAT(OFS_RETURN) = crc;
}
else
G_FLOAT(OFS_RETURN) = CRC_Block((byte*)str, len);
G_FLOAT(OFS_RETURN) = CRC_Block((const byte*)str, len);
}
static void PF_digest_hex(void)
{
@ -4619,14 +4619,14 @@ static void PF_cl_getstat_string(void)
}
}
struct
static struct
{
char name[MAX_QPATH];
int type;
qpic_t *pic;
} *qcpics;
size_t numqcpics;
size_t maxqcpics;
static size_t numqcpics;
static size_t maxqcpics;
void PR_ReloadPics(qboolean purge)
{
numqcpics = 0;
@ -4902,8 +4902,8 @@ static void PF_cl_drawfill(void)
static qpic_t *polygon_pic;
#define MAX_POLYVERTS
polygonvert_t polygon_verts[256];
unsigned int polygon_numverts;
static polygonvert_t polygon_verts[256];
static unsigned int polygon_numverts;
static void PF_R_PolygonBegin(void)
{
qpic_t *pic = DrawQC_CachePic(G_STRING(OFS_PARM0), false);
@ -5087,37 +5087,11 @@ static void PF_cl_findkeysforcommandex(void)
static void PF_cl_setcursormode(void)
{
qboolean absmode = G_FLOAT(OFS_PARM0);
// const char *cursorname = (qcvm->argc<=1)?"":G_STRING(OFS_PARM1);
// float *hotspot = (qcvm->argc<=2)?NULL:G_VECTOR(OFS_PARM2);
// float cursorscale = (qcvm->argc<=3)?1:G_FLOAT(OFS_PARM3);
/* if (absmode)
{
int mark = Hunk_LowMark();
int width, height;
qboolean malloced;
byte *imagedata = Image_LoadImage(cursorname, &width, &height, &malloced);
//TODO: rescale image by cursorscale
SDL_Surface *surf = !imagedata?NULL:SDL_CreateRGBSurfaceFrom(imagedata, width, height, 32, width*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
Hunk_FreeToLowMark(mark);
if (malloced)
free(imagedata);
if (surf)
{
cursor = SDL_CreateColorCursor(surf, hotspot[0], hotspot[1]);
SDL_FreeSurface(surf);
SDL_SetCursor(cursor);
}
else
{
SDL_SetCursor(SDL_GetDefaultCursor());
cursor = NULL;
}
if (oldcursor)
SDL_FreeCursor(oldcursor);
oldcursor = cursor;
}*/
const char *cursorname = (qcvm->argc<=1)?"":G_STRING(OFS_PARM1);
float *hotspot = (qcvm->argc<=2)?NULL:G_VECTOR(OFS_PARM2);
float cursorscale = (qcvm->argc<=3)?1:G_FLOAT(OFS_PARM3);
VID_SetCursor(qcvm, cursorname, hotspot, cursorscale);
qcvm->cursorforced = absmode;
}
static void PF_cl_getcursormode(void)
@ -5391,40 +5365,25 @@ static void PF_m_getmousepos(void)
}
static void PF_m_setmousetarget(void)
{
/*int d = G_FLOAT(OFS_PARM0);
int d = G_FLOAT(OFS_PARM0);
switch(d)
{
case 0:
key_dest = key_game;
break;
case 1:
key_dest = key_message;
qcvm->cursorforced = false;
break;
case 2:
key_dest = key_menu;
qcvm->cursorforced = true;
break;
default:
break;
}*/
}
}
static void PF_m_getmousetarget(void)
{
G_FLOAT(OFS_RETURN) = 0;
/*switch(key_dest)
{
case key_game:
G_FLOAT(OFS_RETURN) = 0;
break;
case key_message:
G_FLOAT(OFS_RETURN) = 1;
break;
case key_menu:
if (qcvm->cursorforced)
G_FLOAT(OFS_RETURN) = 2;
break;
default:
G_FLOAT(OFS_RETURN) = 0;
break;
}*/
else
G_FLOAT(OFS_RETURN) = 1;
}
static void PF_cl_getresolution(void)
{
@ -6321,6 +6280,7 @@ static struct
{"soundlength", PF_NoSSQC, PF_cl_soundlength, 534, PF_cl_soundlength,534, D("float(string sample)", "Provides a way to query the duration of a sound sample, allowing you to set up a timer to chain samples.")},
{"buf_loadfile", PF_buf_loadfile, PF_buf_loadfile, 535, PF_buf_loadfile,535, D("float(string filename, strbuf bufhandle)", "Appends the named file into a string buffer (which must have been created in advance). The return value merely says whether the file was readable.")},
{"buf_writefile", PF_buf_writefile, PF_buf_writefile, 536, PF_buf_writefile,536, D("float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings)", "Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer.")},
//{"bufstr_find", PF_bufstr_find, PF_bufstr_find, 537, PF_bufstr_find,537, D("float(strbuf bufhandle, string match, float matchtype=5, optional float firstidx=0, optional float step=1)", "Finds the first occurence of the requested string, returning its index (or -1).")},
{"setkeydest", PF_NoSSQC, PF_NoCSQC, 601, PF_m_setkeydest,601, D("void(float dest)", "Grab key focus")},
{"getkeydest", PF_NoSSQC, PF_NoCSQC, 602, PF_m_getkeydest,602, D("float()", "Returns key focus")},
@ -6436,6 +6396,7 @@ static const char *extnames[] =
#endif
"FTE_QC_CHECKCOMMAND",
"FTE_QC_CROSSPRODUCT",
"FTE_QC_HARDWARECURSORS",
"FTE_QC_INFOKEY",
"FTE_QC_INTCONV",
"FTE_QC_MULTICAST",

View file

@ -287,7 +287,9 @@ struct qcvm_s
struct pr_extglobals_s extglobals;
struct pr_extfuncs_s extfuncs;
struct pr_extfields_s extfields;
qboolean cursorforced;
void *cursorhandle; //video code.
//was static inside pr_edict
char *strings;

View file

@ -91,5 +91,8 @@ qboolean VID_IsMinimized (void);
void VID_Lock (void);
void VID_SetWindowCaption(const char *newcaption);
void VID_UpdateCursor(void);
void VID_SetCursor(qcvm_t *vm, const char *cursorname, float hotspot[2], float cursorscale);
#endif /* __VID_DEFS_H */