curtesy molgrum: allow_download_loc permits locs/*.loc to be downloaded. also fixes an strncmp. oops.

device ids with rawinput and xinput are now assigned only on the first event. this means the ordering is easily controllable, thus helping splitscreen usability.
fix compile errors with the nolegacy builds.
client updates "chat" userinfo to match ezquake. does not display them still. server now forwards them correctly for ezquake.
android can now switch gles version. a bit crashy with it though.
android: gyroscope is now available to csqc.
android: added vid_dpi_x/y cvars. will be 0 on other platforms, for now.
added screenshot_vr command, for 360-degree stereoscopic screenshots.
fix a potential crash from frag parsing.
added m_accel_style and friends, for nicer mouse acceleration.
fixed const-correctness in a few places.
added friendly spectate button to the server browser
display a warning if an mdl has dodgy seam values. this won't affect fte, but can crash winquake.
qcc: fix struct fields to at least appear to work.
qcc: -I is finally implemented.
qccgui: options now has tooltips, so people might have a chance of actually figuring out what each option does.
menusys: game configs menu now scans for files rather than listing specific ones. should probably be tested more.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4998 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2016-02-10 23:23:43 +00:00
parent 9360a016c2
commit 46c63cbedb
91 changed files with 2150 additions and 1213 deletions

View file

@ -266,11 +266,14 @@ ifeq ($(FTE_TARGET),linux64)
CC=gcc -m64
BITS=64
endif
ifeq ($(FTE_TARGET),cygwin)
FTE_TARGET=cyg
endif
ifeq ($(FTE_TARGET),) #user didn't specify prefered target
ifneq ($(shell uname 2>&1 | grep CYGWIN),)
FTE_TARGET=cygwin
FTE_TARGET=cyg
ANDROID_SCRIPT=android.bat
endif
ifneq ($(shell $(CC) -v 2>&1 | grep mingw),)
@ -341,7 +344,7 @@ DO_CC=$(DO_ECHO) $(CC) $(LTO_CC) $(ALL_CFLAGS) -o $@ -c $<
ifeq ($(FTE_TARGET),vc)
BASELDFLAGS=
endif
ifeq ($(FTE_TARGET),cygwin)
ifeq ($(FTE_TARGET),cyg)
BASELDFLAGS=-lm
endif
ifeq ($(FTE_TARGET),morphos)
@ -618,7 +621,8 @@ SERVER_OBJS = \
httpserver.o
SERVERONLY_OBJS = \
sv_sys_unix.o
sv_sys_unix.o \
sys_linux_threads.o
WINDOWSSERVERONLY_OBJS = \
net_ssl_winsspi.o \
@ -1220,8 +1224,7 @@ ifeq ($(FTE_TARGET),morphos)
endif
ifeq ($(FTE_TARGET),cygwin)
ifeq ($(FTE_TARGET),cyg)
SV_DIR=sv_cygwin
SV_LDFLAGS=-lz

View file

@ -1090,12 +1090,14 @@ void CL_RecordMap_f (void)
CL_Disconnect_f();
return;
}
#ifdef NQPROT
if (!strcmp(demoext, "dem"))
{
cls.demorecording = DPB_NETQUAKE;
VFS_PUTS(cls.demooutfile, "-1\n");
}
else
#endif
cls.demorecording = DPB_QUAKEWORLD;
CL_WriteSetDemoMessage();
}
@ -1343,19 +1345,25 @@ void CL_Record_f (void)
{
char buffer[1024];
FS_GetPackNames(buffer, sizeof(buffer), 2, true); /*retain extensions, or we'd have to assume pk3*/
MSG_WriteByte(&buf, svc_stufftext);
SZ_Write(&buf, "//paknames ", 11);
SZ_Write(&buf, buffer, strlen(buffer));
MSG_WriteString(&buf, "\n");
if (*buffer)
{
MSG_WriteByte(&buf, svc_stufftext);
SZ_Write(&buf, "//paknames ", 11);
SZ_Write(&buf, buffer, strlen(buffer));
MSG_WriteString(&buf, "\n");
}
}
//Paks
{
char buffer[1024];
FS_GetPackHashes(buffer, sizeof(buffer), false);
MSG_WriteByte(&buf, svc_stufftext);
SZ_Write(&buf, "//paks ", 7);
SZ_Write(&buf, buffer, strlen(buffer));
MSG_WriteString(&buf, "\n");
if (*buffer)
{
MSG_WriteByte(&buf, svc_stufftext);
SZ_Write(&buf, "//paks ", 7);
SZ_Write(&buf, buffer, strlen(buffer));
MSG_WriteString(&buf, "\n");
}
}
//FIXME: //at

View file

@ -1564,6 +1564,7 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
int clientcount, lost;
int curframe;
int st = buf->cursize;
int chatstate;
cl.movesequence = cls.netchan.outgoing_sequence; //make sure its correct even over map changes.
curframe = cl.movesequence & UPDATE_MASK;
@ -1582,8 +1583,20 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
clientcount = 1;
chatstate = 0;
chatstate |= Key_Dest_Has(~kdm_game)?1:0;
chatstate |= vid.activeapp?0:2;
for (plnum = 0; plnum<clientcount; plnum++)
{
if (cl.playerview[plnum].chatstate != chatstate)
{
if (chatstate)
CL_SetInfo(plnum, "chat", va("%i", chatstate));
else
CL_SetInfo(plnum, "chat", "");
cl.playerview[plnum].chatstate = chatstate;
}
cmd = &cl.outframes[curframe].cmd[plnum];
*cmd = independantphysics[plnum];

View file

@ -860,19 +860,23 @@ void CL_CheckForResend (void)
connectinfo.fteext1 = Net_PextMask(1, false);
connectinfo.fteext2 = Net_PextMask(2, false);
}
#ifdef NQPROT
else if (cls.demorecording == DPB_NETQUAKE && cls.protocol != CP_NETQUAKE)
{
connectinfo.protocol = CP_NETQUAKE;
connectinfo.subprotocol = CPNQ_FITZ666;
//FIXME: use pext.
}
else if (cls.demorecording == DPB_QUAKE2 && cls.protocol != CP_NETQUAKE)
#endif
#ifdef Q2CLIENT
else if (cls.demorecording == DPB_QUAKE2 && cls.protocol != CP_QUAKE2)
{
connectinfo.protocol = CP_QUAKE2;
connectinfo.subprotocol = PROTOCOL_VERSION_Q2;
connectinfo.fteext1 = PEXT_MODELDBL|PEXT_SOUNDDBL|PEXT_SPLITSCREEN;
//FIXME: use pext.
}
#endif
break;
}
@ -1553,6 +1557,8 @@ void CL_ClearState (void)
cl.playerview[i].viewheight = DEFAULT_VIEWHEIGHT;
cl.playerview[i].maxspeed = 320;
cl.playerview[i].entgravity = 1;
cl.playerview[i].chatstate = atoi(Info_ValueForKey(cls.userinfo[i], "chat"));
}
#ifdef QUAKESTATS
for (i = 0; i < MAX_CLIENTS; i++) //in case some server doesn't support it
@ -1672,6 +1678,8 @@ void CL_Disconnect (void)
cl.intermissionmode = IM_NONE;
cl.oldgametime = 0;
memset(&r_refdef, 0, sizeof(r_refdef));
#ifdef NQPROT
cls.signon=0;
#endif
@ -3811,9 +3819,6 @@ void CL_Init (void)
ver = va("%s v%i.%02i", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR);
Info_SetValueForStarKey (cls.userinfo[0], "*ver", ver, sizeof(cls.userinfo[0]));
Info_SetValueForStarKey (cls.userinfo[1], "*ss", "1", sizeof(cls.userinfo[1]));
Info_SetValueForStarKey (cls.userinfo[2], "*ss", "1", sizeof(cls.userinfo[2]));
Info_SetValueForStarKey (cls.userinfo[3], "*ss", "1", sizeof(cls.userinfo[3]));
InitValidation();
@ -4821,6 +4826,54 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
return true;
}
void CL_UpdateHeadAngles(void)
{
/*FIXME: no idea what I'm doing with this. lets just not break anything for now
//identity, for now
vec3_t headchange[3] =
{
{1,0,0},
{0,1,0},
{0,0,1}
};
vec3_t tmp[3], tmp2[3];
playerview_t *pv = &cl.playerview[0];
tmp2[0][0] = 0;
tmp2[0][1] = host_frametime*90;
tmp2[0][2] = 0;
AngleVectorsFLU(tmp2[0], headchange[0], headchange[1], headchange[2]);
switch(cl_headmode.ival)
{
case 3: //head angles change both
R_ConcatRotations(headchange, r_refdef.headaxis, tmp);
break;
case 2: //head changes are entirely relative to the 'view' angle
R_ConcatRotations(headchange, r_refdef.headaxis, tmp);
memcpy(r_refdef.headaxis, tmp, sizeof(r_refdef.headaxis));
break;
case 1: //head changes change the view angle directly.
AngleVectorsFLU(pv->viewangles, tmp[0], tmp[1], tmp[2]);
R_ConcatRotations(headchange, tmp, tmp2);
VectorAngles(tmp2[0], tmp2[2], pv->viewangles);
pv->viewangles[0] *= -1;
//fall through
default:
case 0: //off
VectorSet(r_refdef.headaxis[0], 1, 0, 0);
VectorSet(r_refdef.headaxis[1], 0, 1, 0);
VectorSet(r_refdef.headaxis[2], 0, 0, 1);
break;
}
*/
VectorSet(r_refdef.headaxis[0], 1, 0, 0);
VectorSet(r_refdef.headaxis[1], 0, 1, 0);
VectorSet(r_refdef.headaxis[2], 0, 0, 1);
}
/*
==================
Host_Frame
@ -4903,9 +4956,7 @@ double Host_Frame (double time)
Key_Dest_Has(kdm_gmenu) ||
Key_Dest_Has(kdm_emenu) ||
Key_Dest_Has(kdm_editor) ||
#ifdef _WIN32
!ActiveApp ||
#endif
!vid.activeapp ||
cl.paused
;
// TODO: check if minimized or unfocused
@ -5124,13 +5175,16 @@ double Host_Frame (double time)
if (SCR_UpdateScreen && !vid.isminimized)
{
extern cvar_t scr_chatmodecvar;
extern cvar_t scr_chatmodecvar, r_stereo_method;
if (scr_chatmodecvar.ival && cl.intermissionmode == IM_NONE)
scr_chatmode = (cl.spectator&&cl.splitclients<2&&cls.state == ca_active)?2:1;
else
scr_chatmode = 0;
r_refdef.stereomethod = r_stereo_method.ival;
CL_UpdateHeadAngles();
SCR_UpdateScreen ();
if (R2D_Flush)
@ -5239,7 +5293,7 @@ void CL_StartCinematicOrMenu(void)
}
if (startuppending)
{
if (startuppending == 2)
if (startuppending == 2) //installer finished.
Cbuf_AddText("\nfs_restart\nvid_restart\n", RESTRICT_LOCAL);
startuppending = false;
Key_Dest_Remove(kdm_console); //make sure console doesn't stay up weirdly.
@ -5461,45 +5515,64 @@ void CL_ExecInitialConfigs(char *resetcommand)
void Host_FinishLoading(void)
{
//the filesystem has retrieved its manifest, but might still be waiting for paks to finish downloading.
extern qboolean r_blockvidrestart;
if (r_blockvidrestart == true)
{
//1 means we need to init the filesystem
//make sure the filesystem has some default if no manifest was loaded.
FS_ChangeGame(NULL, true, true);
//the filesystem has retrieved its manifest, but might still be waiting for paks to finish downloading.
if (waitingformanifest)
//make sure the filesystem has some default if no manifest was loaded.
FS_ChangeGame(NULL, true, true);
if (waitingformanifest)
return;
Con_History_Load();
Cmd_StuffCmds();
Cbuf_Execute ();
CL_ArgumentOverrides();
#ifndef CLIENTONLY
SV_ArgumentOverrides();
#endif
Con_Printf ("\n%s\n", version_string());
Con_DPrintf("This program 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."
"\n"
"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. "
"\n"
"See the GNU General Public License for more details.\n");
#if defined(_WIN32) && !defined(FTE_SDL) && defined(WEBCLIENT)
if (Sys_RunInstaller())
Sys_Quit();
#endif
r_blockvidrestart = 2;
}
#ifdef ANDROID
//android needs to wait a bit longer before it's allowed to init its video properly.
extern int sys_glesversion;
if (!sys_glesversion)
return;
Con_History_Load();
Cmd_StuffCmds();
Cbuf_Execute ();
CL_ArgumentOverrides();
#ifndef CLIENTONLY
SV_ArgumentOverrides();
#endif
Con_Printf ("\n%s\n", version_string());
Con_DPrintf("This program 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."
"\n"
"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. "
"\n"
"See the GNU General Public License for more details.\n");
#if defined(_WIN32) && !defined(FTE_SDL) && defined(WEBCLIENT)
if (Sys_RunInstaller())
Sys_Quit();
#endif
Renderer_Start();
CL_StartCinematicOrMenu();
if (r_blockvidrestart == 2)
{ //2 is part of the initial startup
Renderer_Start();
CL_StartCinematicOrMenu();
}
else //3 flags for a renderer restart
Renderer_Start();
}
/*

View file

@ -2009,7 +2009,7 @@ void CL_ParseChunkedDownload(qdownload_t *dl)
if (flag < 0)
{
if (flag == -4)
if (flag == DLERR_REDIRECTFILE)
{
if (CL_AllowArbitaryDownload(svname))
{
@ -2019,11 +2019,11 @@ void CL_ParseChunkedDownload(qdownload_t *dl)
}
svname = dl->remotename;
}
else if (flag == -3)
else if (flag == DLERR_UNKNOWN)
Con_Printf("Server reported an error when downloading file \"%s\"\n", svname);
else if (flag == -2)
else if (flag == DLERR_PERMISSIONS)
Con_Printf("Server permissions deny downloading file \"%s\"\n", svname);
else
else //if (flag == DLERR_FILENOTFOUND)
Con_Printf("Couldn't find file \"%s\" on the server\n", svname);
if (dl)
@ -2292,7 +2292,7 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
for (b = dl->dlblocks; b; b = n)
{
if (b->state == DLB_RECEIVED)
VFS_PRINTF(parts, "c "fPRIllx" "fPRIllx"\n", (long long)b->start, (long long)b->end);
VFS_PRINTF(parts, "c %"PRIx64" %"PRIx64"\n", (long long)b->start, (long long)b->end);
else
{
for(;;)
@ -2307,7 +2307,7 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
}
break;
}
VFS_PRINTF(parts, "m "fPRIllx" "fPRIllx"\n", (long long)b->start, (long long)b->end);
VFS_PRINTF(parts, "m %"PRIx64" %"PRIx64"\n", (long long)b->start, (long long)b->end);
}
n = b->next;
@ -4774,6 +4774,8 @@ void CL_ProcessUserInfo (int slot, player_info_t *player)
Skin_FlushPlayers();
}
else if (cl.teamplay && cl.spectator && slot == Cam_TrackNum(&cl.playerview[0])) //skin forcing cares about the team of the guy we're tracking.
Skin_FlushPlayers();
else if (cls.state == ca_active)
Skin_Find (player);

View file

@ -219,11 +219,6 @@ float scr_disabled_time;
float oldsbar = 0;
void SCR_ScreenShot_f (void);
void SCR_ScreenShot_Mega_f(void);
void SCR_RSShot_f (void);
void SCR_CPrint_f(void);
cvar_t con_stayhidden = CVARFD("con_stayhidden", "0", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works");
cvar_t show_fps = SCVARF("show_fps", "0", CVAR_ARCHIVE);
cvar_t show_fps_x = SCVAR("show_fps_x", "-1");
@ -243,6 +238,15 @@ cvar_t scr_showobituaries = CVAR("scr_showobituaries", "0");
void *scr_curcursor;
static void SCR_CPrint_f(void)
{
if (Cmd_Argc() == 2)
SCR_CenterPrint(0, Cmd_Argv(1), true);
else
SCR_CenterPrint(0, Cmd_Args(), true);
}
extern char cl_screengroup[];
void CLSCR_Init(void)
{
@ -508,14 +512,6 @@ void VARGS Stats_Message(char *msg, ...)
p->time_start = cl.time;
}
void SCR_CPrint_f(void)
{
if (Cmd_Argc() == 2)
SCR_CenterPrint(0, Cmd_Argv(1), true);
else
SCR_CenterPrint(0, Cmd_Args(), true);
}
#define MAX_CPRINT_LINES 128
void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font)
{
@ -1319,56 +1315,6 @@ void SCR_SizeDown_f (void)
//============================================================================
/*
==================
SCR_Init
==================
*/
void SCR_Init (void)
{
//
// register our commands
//
Cmd_AddCommandD ("screenshot_mega",SCR_ScreenShot_Mega_f, "screenshot_mega <name> [width] [height]\nTakes a screenshot with explicit sizes that are not tied to the size of your monitor, allowing for true monstrosities.");
Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
scr_net = R2D_SafePicFromWad ("net");
scr_turtle = R2D_SafePicFromWad ("turtle");
scr_initialized = true;
}
void SCR_DeInit (void)
{
int i;
if (scr_curcursor)
{
rf->VID_SetCursor(scr_curcursor);
scr_curcursor = NULL;
}
for (i = 0; i < countof(key_customcursor); i++)
{
if (key_customcursor[i].handle)
{
rf->VID_DestroyCursor(key_customcursor[i].handle);
key_customcursor[i].handle = NULL;
}
key_customcursor[i].dirty = true;
}
if (scr_initialized)
{
scr_initialized = false;
Cmd_RemoveCommand ("screenshot");
Cmd_RemoveCommand ("screenshot_mega");
Cmd_RemoveCommand ("sizeup");
Cmd_RemoveCommand ("sizedown");
}
}
/*
==============
SCR_DrawTurtle
@ -2082,7 +2028,7 @@ typedef struct _TargaHeader {
qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight, enum uploadfmt fmt);
#endif
#ifdef AVAIL_PNGLIB
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height, enum uploadfmt fmt);
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, int width, int height, enum uploadfmt fmt);
#endif
void WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, int width, int height);
@ -2202,7 +2148,7 @@ int MipColor(int r, int g, int b)
return best;
}
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height, enum uploadfmt fmt)
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int width, int height, enum uploadfmt fmt)
{
#if defined(AVAIL_PNGLIB) || defined(AVAIL_JPEGLIB)
extern cvar_t scr_sshot_compression;
@ -2212,35 +2158,33 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buff
COM_FileExtension(filename, ext, sizeof(ext));
if (!rgb_buffer)
return false;
#ifdef AVAIL_PNGLIB
if (!Q_strcasecmp(ext, "png"))
if (!Q_strcasecmp(ext, "png") || !Q_strcasecmp(ext, "pns"))
{
//png can do bgr+rgb
//rgba bgra will result in an extra alpha chan
return Image_WritePNG(filename, fsroot, scr_sshot_compression.value, rgb_buffer, width, height, fmt);
//actual stereo is also supported. huzzah.
return Image_WritePNG(filename, fsroot, scr_sshot_compression.value, buffer, numbuffers, width, height, fmt);
}
else
#endif
#ifdef AVAIL_JPEGLIB
if (!Q_strcasecmp(ext, "jpeg") || !Q_strcasecmp(ext, "jpg"))
{
return screenshotJPEG(filename, fsroot, scr_sshot_compression.value, rgb_buffer, width, height, fmt);
return screenshotJPEG(filename, fsroot, scr_sshot_compression.value, buffer[0], width, height, fmt);
}
else
#endif
/* if (!Q_strcasecmp(ext, "bmp"))
{
return WriteBMPFile(pcxname, rgb_buffer, width, height);
return WriteBMPFile(pcxname, buffer[0], width, height);
}
else*/
if (!Q_strcasecmp(ext, "pcx"))
{
int y, x, s;
qbyte *src, *dest;
qbyte *newbuf = rgb_buffer;
qbyte *newbuf = buffer[0];
if (fmt == TF_RGB24 || fmt == TF_RGBA32)
{
s = (fmt == TF_RGB24)?3:4;
@ -2277,7 +2221,7 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buff
WritePCXfile (filename, fsroot, newbuf, width, height, width, host_basepal, false);
}
else if (!Q_strcasecmp(ext, "tga")) //tga
return WriteTGA(filename, fsroot, rgb_buffer, width, height, fmt);
return WriteTGA(filename, fsroot, buffer[0], width, height, fmt);
else //extension / type not recognised.
return false;
return true;
@ -2288,7 +2232,7 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buff
SCR_ScreenShot_f
==================
*/
void SCR_ScreenShot_f (void)
static void SCR_ScreenShot_f (void)
{
char sysname[1024];
char pcxname[MAX_QPATH];
@ -2325,7 +2269,7 @@ void SCR_ScreenShot_f (void)
//
for (i=0 ; i<stop ; i++)
{
Q_snprintfz(pcxname, sizeof(pcxname), "%s-%s-%i.%s", scr_sshot_prefix.string, date, i, scr_sshot_type.string);
Q_snprintfz(pcxname, sizeof(pcxname), "%s%s-%i.%s", scr_sshot_prefix.string, date, i, scr_sshot_type.string);
if (!(vfs = FS_OpenVFS(pcxname, "rb", FS_GAMEONLY)))
break; // file doesn't exist
@ -2343,7 +2287,7 @@ void SCR_ScreenShot_f (void)
rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
if (rgbbuffer)
{
if (SCR_ScreenShot(pcxname, FS_GAMEONLY, rgbbuffer, width, height, fmt))
if (SCR_ScreenShot(pcxname, FS_GAMEONLY, &rgbbuffer, 1, width, height, fmt))
{
Con_Printf ("Wrote %s\n", sysname);
BZ_Free(rgbbuffer);
@ -2354,43 +2298,12 @@ void SCR_ScreenShot_f (void)
Con_Printf ("Couldn't write %s\n", sysname);
}
void SCR_ScreenShot_Mega_f(void)
void *SCR_ScreenShot_FBO(int fbwidth, int fbheight, enum uploadfmt *fmt)
{
int width;
int height;
qbyte *rgbbuffer;
char filename[MAX_QPATH];
enum uploadfmt fmt;
//poke the various modes into redrawing the screen (without huds), to avoid any menus or console drawn over the top of the current backbuffer.
//FIXME: clear-to-black first
int width, height;
void *buf;
qboolean okay = false;
char *screenyname = Cmd_Argv(1);
unsigned int fbwidth = strtoul(Cmd_Argv(2), NULL, 0);
unsigned int fbheight = strtoul(Cmd_Argv(3), NULL, 0);
if (Cmd_IsInsecure())
return;
if (qrenderer <= QR_HEADLESS)
{
Con_Printf("No renderer active\n");
return;
}
if (!fbwidth)
fbwidth = sh_config.texture_maxsize;
fbwidth = bound(0, fbwidth, sh_config.texture_maxsize);
if (!fbheight)
fbheight = (fbwidth * 3)/4;
fbheight = bound(0, fbheight, sh_config.texture_maxsize);
if (!*screenyname)
screenyname = "megascreeny";
Q_snprintfz(filename, sizeof(filename), "%s-%s", scr_sshot_prefix.string, screenyname);
COM_DefaultExtension (filename, scr_sshot_type.string, sizeof(filename));
Q_strncpyz(r_refdef.rt_destcolour[0].texname, "megascreeny", sizeof(r_refdef.rt_destcolour[0].texname));
R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, fbwidth, fbheight, 1);
BE_RenderToTextureUpdate2d(true);
@ -2415,33 +2328,254 @@ void SCR_ScreenShot_Mega_f(void)
V_RenderView ();
okay = true;
}
//okay, we drew something, we're good to save a screeny.
if (okay)
//fixme: add a way to get+save the depth values too
if (!okay)
{
rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
if (rgbbuffer)
{
if (SCR_ScreenShot(filename, FS_GAMEONLY, rgbbuffer, width, height, fmt))
{
char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
}
BZ_Free(rgbbuffer);
}
buf = NULL;
width = height = 0;
*fmt = TF_INVALID;
}
else
buf = VID_GetRGBInfo(&width, &height, fmt);
R2D_RT_Configure(r_refdef.rt_destcolour[0].texname, 0, 0, 0);
Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname));
BE_RenderToTextureUpdate2d(true);
if (width != fbwidth || height != fbheight)
{
BZ_Free(buf);
return NULL;
}
return buf;
}
static void SCR_ScreenShot_Mega_f(void)
{
int width[2];
int height[2];
void *buffers[2];
enum uploadfmt fmt[2];
int numbuffers = 0;
int buf;
char filename[MAX_QPATH];
stereomethod_t osm = r_refdef.stereomethod;
//massage the rendering code to redraw the screen with an fbo forced.
//this allows us to generate screenshots which are not otherwise possible to actually draw.
//this includes larger resolutions (although the lack of stiching leaves us subject to gpu limits of about 16k)
char *screenyname = Cmd_Argv(1);
unsigned int fbwidth = strtoul(Cmd_Argv(2), NULL, 0);
unsigned int fbheight = strtoul(Cmd_Argv(3), NULL, 0);
char ext[8];
if (Cmd_IsInsecure())
return;
if (qrenderer <= QR_HEADLESS)
{
Con_Printf("No renderer active\n");
return;
}
if (!fbwidth)
fbwidth = sh_config.texture_maxsize;
fbwidth = bound(0, fbwidth, sh_config.texture_maxsize);
if (!fbheight)
fbheight = (fbwidth * 3)/4;
fbheight = bound(0, fbheight, sh_config.texture_maxsize);
if (strstr (screenyname, "..") || strchr(screenyname, ':') || *screenyname == '.' || *screenyname == '/')
screenyname = "";
if (!*screenyname)
{
screenyname = "megascreeny";
Q_snprintfz(filename, sizeof(filename), "%s%s", scr_sshot_prefix.string, screenyname);
}
else
{
char *mangle;
Q_snprintfz(filename, sizeof(filename), "%s", scr_sshot_prefix.string);
mangle = COM_SkipPath(filename);
Q_snprintfz(mangle, sizeof(filename) - (mangle-filename), "%s", screenyname);
}
if (!strcmp(Cmd_Argv(0), "screenshot_stereo"))
COM_DefaultExtension (filename, "png", sizeof(filename));
else
COM_DefaultExtension (filename, scr_sshot_type.string, sizeof(filename));
COM_FileExtension(filename, ext, sizeof(ext));
if (!strcmp(Cmd_Argv(0), "screenshot_stereo") || !strcmp(ext, "pns") || osm == STEREO_QUAD)
numbuffers = 2; //stereo png
else
numbuffers = 1;
if (numbuffers == 2 && Q_strcasecmp(ext, "png") && Q_strcasecmp(ext, "pns"))
{
Con_Printf("Only png format is supported for stereo screenshots\n");
return;
}
for(buf = 0; buf < numbuffers; buf++)
{
if (numbuffers == 2)
{
if (buf)
r_refdef.stereomethod = STEREO_RIGHTONLY;
else
r_refdef.stereomethod = STEREO_LEFTONLY;
}
buffers[buf] = SCR_ScreenShot_FBO(fbwidth, fbheight, &fmt[buf]);
if (width[buf] != width[0] || height[buf] != height[0] || fmt[buf] != fmt[0])
{ //invalid is better than unmatched.
BZ_Free(buffers[buf]);
buffers[buf] = NULL;
}
}
if (numbuffers == 2 && !buffers[1])
numbuffers = 1;
//okay, we drew something, we're good to save a screeny.
if (buffers[0])
{
if (SCR_ScreenShot(filename, FS_GAMEONLY, buffers, numbuffers, width[0], height[0], fmt[0]))
{
char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
}
}
else
Con_Printf("Unable to capture screenshot\n");
for(buf = 0; buf < numbuffers; buf++)
BZ_Free(buffers[buf]);
r_refdef.stereomethod = osm;
}
static void SCR_ScreenShot_VR_f(void)
{
char *screenyname = Cmd_Argv(1);
int width = atoi(Cmd_Argv(2));
//we spin the camera around, taking slices from equirectangular screenshots
char filename[MAX_QPATH];
int height; //equirectangular 360 * 180 gives a nice clean ratio
int px = 4;
int step = atof(Cmd_Argv(3));
unsigned int *left_buffer;
unsigned int *right_buffer;
unsigned int *buf;
enum uploadfmt fmt;
int lx, rx, x, y;
vec3_t baseang;
float ang;
extern cvar_t r_projection, r_stereo_separation;
VectorCopy(r_refdef.viewangles, baseang);
if (width <= 2)
width = 2048;
height = width/2;
if (step <= 0)
step = 5;
left_buffer = BZF_Malloc (width*height*2*px);
right_buffer = left_buffer + width*height;
if (strstr (screenyname, "..") || strchr(screenyname, ':') || *screenyname == '.' || *screenyname == '/')
screenyname = "";
if (!*screenyname)
{
screenyname = "vr";
Q_snprintfz(filename, sizeof(filename), "%s%s", scr_sshot_prefix.string, screenyname);
}
else
{
char *mangle;
Q_snprintfz(filename, sizeof(filename), "%s", scr_sshot_prefix.string);
mangle = COM_SkipPath(filename);
Q_snprintfz(mangle, sizeof(filename) - (mangle-filename), "%s", screenyname);
}
COM_DefaultExtension (filename, scr_sshot_type.string, sizeof(filename));
if (!left_buffer)
{
Con_Printf("out of memory\n");
return;
}
r_projection.ival = PROJ_EQUIRECTANGULAR;
for (lx = 0; lx < width; lx = rx)
{
rx = lx + step;
if (rx > width)
rx = width;
r_refdef.stereomethod = STEREO_OFF;
cl.playerview->simangles[0] = 0; //pitch is BAD
cl.playerview->simangles[1] = baseang[1];// - 360.0*(lx + 0.5*(rx-lx)) / width;
cl.playerview->simangles[2] = 0; //roll is BAD
VectorCopy(cl.playerview->simangles, cl.playerview->viewangles);
//FIXME: it should be possible to do this more inteligently, and get both strips with a single render.
ang = M_PI*2*(baseang[1]/360.0 + (lx+0.5*(rx-lx))/width);
r_refdef.eyeoffset[0] = sin(ang) * r_stereo_separation.value * 0.5;
r_refdef.eyeoffset[1] = cos(ang) * r_stereo_separation.value * 0.5;
r_refdef.eyeoffset[2] = 0;
buf = SCR_ScreenShot_FBO(width, height, &fmt);
if (buf && fmt == TF_BGRA32)
{
for (y = 0; y < height; y++)
for (x = lx; x < rx; x++)
left_buffer[y*width + x] = buf[y*width + /*(width-step)/2 +*/ x];
}
BZ_Free(buf);
r_refdef.eyeoffset[0] *= -1;
r_refdef.eyeoffset[1] *= -1;
r_refdef.eyeoffset[2] = 0;
buf = SCR_ScreenShot_FBO(width, height, &fmt);
if (buf && fmt == TF_BGRA32)
{
for (y = 0; y < height; y++)
for (x = lx; x < rx; x++)
right_buffer[y*width + x] = buf[y*width + /*(width-step)/2 +*/ x];
}
BZ_Free(buf);
}
if (SCR_ScreenShot(filename, FS_GAMEONLY, &left_buffer, 1, width, height*2, TF_BGRA32))
{
char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
}
BZ_Free(left_buffer);
r_projection.ival = r_projection.value;
VectorCopy(baseang, r_refdef.viewangles);
VectorClear(r_refdef.eyeoffset);
}
void SCR_ScreenShot_EnvMap_f(void)
{
Con_Printf("Not implemented\n");
}
// from gl_draw.c
qbyte *draw_chars; // 8*8 graphic characters
void SCR_DrawCharToSnap (int num, qbyte *dest, int width)
static void SCR_DrawCharToSnap (int num, qbyte *dest, int width)
{
int row, col;
qbyte *source;
@ -2472,7 +2606,7 @@ void SCR_DrawCharToSnap (int num, qbyte *dest, int width)
}
void SCR_DrawStringToSnap (const char *s, qbyte *buf, int x, int y, int width)
static void SCR_DrawStringToSnap (const char *s, qbyte *buf, int x, int y, int width)
{
qbyte *dest;
const unsigned char *p;
@ -2537,6 +2671,7 @@ qboolean SCR_RSShot (void)
BZ_Free(newbuf);
return false;
}
//FIXME: bgra
w = RSSHOT_WIDTH;
h = RSSHOT_HEIGHT;
@ -2620,7 +2755,6 @@ Brings the console down and fades the palettes back to normal
*/
void SCR_BringDownConsole (void)
{
int i;
int pnum;
for (pnum = 0; pnum < cl.splitclients; pnum++)
@ -2628,9 +2762,6 @@ void SCR_BringDownConsole (void)
scr_centerprint[pnum].charcount = 0;
cl.playerview[pnum].cshifts[CSHIFT_CONTENTS].percent = 0; // no area contents palette on next frame
}
// for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
// SCR_UpdateScreen ();
}
void SCR_TileClear (int skipbottom)
@ -2738,3 +2869,63 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
RSpeedEnd(RSPEED_2D);
}
/*
==================
SCR_Init
==================
*/
void SCR_Init (void)
{
//
// register our commands
//
Cmd_AddCommandD ("screenshot_mega",SCR_ScreenShot_Mega_f, "screenshot_mega <name> [width] [height]\nTakes a screenshot with explicit sizes that are not tied to the size of your monitor, allowing for true monstrosities.");
Cmd_AddCommandD ("screenshot_stereo",SCR_ScreenShot_Mega_f, "screenshot_stereo <name> [width] [height]\nTakes a simple stereo screenshot.");
Cmd_AddCommandD ("screenshot_vr",SCR_ScreenShot_VR_f, "screenshot_vr <name> [width]\nTakes a spherical stereoscopic panorama image, for viewing with VR displays.");
Cmd_AddCommand ("envmap",SCR_ScreenShot_EnvMap_f);
Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
scr_net = R2D_SafePicFromWad ("net");
scr_turtle = R2D_SafePicFromWad ("turtle");
scr_initialized = true;
}
void SCR_DeInit (void)
{
int i;
if (scr_curcursor)
{
rf->VID_SetCursor(scr_curcursor);
scr_curcursor = NULL;
}
for (i = 0; i < countof(key_customcursor); i++)
{
if (key_customcursor[i].handle)
{
rf->VID_DestroyCursor(key_customcursor[i].handle);
key_customcursor[i].handle = NULL;
}
key_customcursor[i].dirty = true;
}
if (scr_initialized)
{
scr_initialized = false;
Cmd_RemoveCommand ("screenshot");
Cmd_RemoveCommand ("screenshot_mega");
Cmd_RemoveCommand ("screenshot_stereo");
Cmd_RemoveCommand ("screenshot_vr");
Cmd_RemoveCommand ("envmap");
Cmd_RemoveCommand ("sizeup");
Cmd_RemoveCommand ("sizedown");
}
}

View file

@ -632,6 +632,8 @@ struct playerview_s
float rollangle;
float hdr_last;
int chatstate; //1=talking, 2=afk
float crouch; // local amount for smoothing stepups
vec3_t oldorigin; // to track step smoothing
float oldz, extracrouch, crouchspeed; // to track step smoothing
@ -1341,6 +1343,7 @@ qboolean CSQC_MouseMove(float xdelta, float ydelta, int devid);
qboolean CSQC_MousePosition(float xabs, float yabs, int devid);
qboolean CSQC_JoystickAxis(int axis, float value, int devid);
qboolean CSQC_Accelerometer(float x, float y, float z);
qboolean CSQC_Gyroscope(float x, float y, float z);
int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod, float timeofs, unsigned int flags);
void CSQC_ParseEntities(void);
void CSQC_ResetTrails(void);

View file

@ -1121,9 +1121,6 @@ return value is the top of the region
*/
int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, qboolean selactive, int selsx, int selex, int selsy, int seley)
{
#ifdef _WIN32
extern qboolean ActiveApp;
#endif
int i;
int lhs, rhs;
int p;
@ -1203,11 +1200,9 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
// else
// Plug_SpellCheckMaskedText(maskedtext+1, i-1, x, y, 8, si, con_current->linewidth);
#ifdef _WIN32
if (!ActiveApp)
if (!vid.activeapp)
cursorframe = 0;
else
#endif
cursorframe = ((int)(realtime*con_cursorspeed)&1);
//FIXME: support tab somehow

View file

@ -309,6 +309,11 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
u1 = (p1 == (cl.playerview[0].playernum));
u2 = (p2 == (cl.playerview[0].playernum));
if (p1 == -1)
p1 = p2;
if (p2 == -1)
p2 = p1;
//messages are killed weapon killer
switch(mt)
{
@ -320,7 +325,8 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
}
fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].deaths++;
if (p1 >= 0)
fragstats.clienttotals[p1].deaths++;
fragstats.totaldeaths++;
Stats_FragMessage(p1, wid, -3, true);
@ -338,8 +344,11 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].suicides++;
fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].suicides++;
fragstats.clienttotals[p1].deaths++;
if (p1 >= 0)
{
fragstats.clienttotals[p1].suicides++;
fragstats.clienttotals[p1].deaths++;
}
fragstats.totalsuicides++;
fragstats.totaldeaths++;
@ -351,7 +360,8 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1)
fragstats.weapontotals[wid].ownkills++;
fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].kills++;
if (p1 >= 0)
fragstats.clienttotals[p1].kills++;
fragstats.totalkills++;
Stats_FragMessage(-4, wid, p1, false);
@ -371,7 +381,8 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1)
fragstats.weapontotals[wid].ownteamkills++;
fragstats.weapontotals[wid].teamkills++;
fragstats.clienttotals[p1].teamkills++;
if (p1 >= 0)
fragstats.clienttotals[p1].teamkills++;
fragstats.totalteamkills++;
Stats_FragMessage(-1, wid, p1, true);
@ -385,25 +396,27 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.clienttotals[p1].grabs++;
fragstats.totaltouches++;
if (u1)
if (u1 && p1 >= 0)
{
Stats_Message("You grabbed the flag\nflag grabs: %i (%i)\n", fragstats.clienttotals[p1].grabs, fragstats.totaltouches);
}
break;
case ff_flagcaps:
fragstats.clienttotals[p1].caps++;
if (p1 >= 0)
fragstats.clienttotals[p1].caps++;
fragstats.totalcaps++;
if (u1)
if (u1 && p1 >= 0)
{
Stats_Message("You captured the flag\nflag captures: %i (%i)\n", fragstats.clienttotals[p1].caps, fragstats.totalcaps);
}
break;
case ff_flagdrops:
fragstats.clienttotals[p1].drops++;
if (p1 >= 0)
fragstats.clienttotals[p1].drops++;
fragstats.totaldrops++;
if (u1)
if (u1 && p1 >= 0)
{
Stats_Message("You dropped the flag\nflag drops: %i (%i)\n", fragstats.clienttotals[p1].drops, fragstats.totaldrops);
}
@ -414,21 +427,26 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
case ff_fragedby:
fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].deaths++;
if (p1 >= 0)
fragstats.clienttotals[p1].deaths++;
fragstats.totaldeaths++;
if (u1)
{
fragstats.weapontotals[wid].owndeaths++;
Stats_Message("%s killed you\n%s deaths: %i (%i/%i)\n", cl.players[p2].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths);
if (p1 >= 0 && p2 >= 0)
Stats_Message("%s killed you\n%s deaths: %i (%i/%i)\n", cl.players[p2].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths);
}
fragstats.clienttotals[p2].kills++;
if (p2 >= 0)
fragstats.clienttotals[p2].kills++;
fragstats.totalkills++;
if (u2)
{
Stats_OwnFrag(cl.players[p1].name);
if (p1 >= 0)
Stats_OwnFrag(cl.players[p1].name);
fragstats.weapontotals[wid].ownkills++;
Stats_Message("You killed %s\n%s kills: %i (%i/%i)\n", cl.players[p1].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills);
if (p1 >= 0 && p2 >= 0)
Stats_Message("You killed %s\n%s kills: %i (%i/%i)\n", cl.players[p1].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills);
}
Stats_FragMessage(p1, wid, p2, false);
@ -464,8 +482,11 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].ownteamdeaths++;
fragstats.weapontotals[wid].owndeaths++;
}
fragstats.clienttotals[p1].teamdeaths++;
fragstats.clienttotals[p1].deaths++;
if (p1 >= 0)
{
fragstats.clienttotals[p1].teamdeaths++;
fragstats.clienttotals[p1].deaths++;
}
fragstats.totaldeaths++;
if (u2)
@ -473,16 +494,19 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].ownkills++;
fragstats.weapontotals[wid].ownkills++;
}
fragstats.clienttotals[p2].teamkills++;
fragstats.clienttotals[p2].kills++;
if (p2 >= 0)
{
fragstats.clienttotals[p2].teamkills++;
fragstats.clienttotals[p2].kills++;
}
fragstats.totalkills++;
fragstats.totalteamkills++;
Stats_FragMessage(p1, wid, p2, false);
if (u1)
if (u1 && p2 >= 0)
Stats_Message("%s killed you\n%s deaths: %i (%i/%i)\n", cl.players[p2].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths);
if (u2)
if (u2 && p1 >= 0 && p2 >= 0)
{
Stats_OwnFrag(cl.players[p1].name);
Stats_Message("You killed %s\n%s kills: %i (%i/%i)\n", cl.players[p1].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills);

View file

@ -745,6 +745,7 @@ void (PNGAPI *qpng_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)) PSTATIC
png_voidp (PNGAPI *qpng_get_io_ptr) PNGARG((png_structp png_ptr)) PSTATIC(png_get_io_ptr);
void (PNGAPI *qpng_destroy_write_struct) PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)) PSTATIC(png_destroy_write_struct);
png_structp (PNGAPI *qpng_create_write_struct) PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn)) PSTATIC(png_create_write_struct);
void (PNGAPI *qpng_set_unknown_chunks) PNGARG((png_structp png_ptr, png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)) PSTATIC(png_set_unknown_chunks);
png_voidp (PNGAPI *qpng_get_error_ptr) PNGARG((png_structp png_ptr)) PSTATIC(png_get_error_ptr);
@ -791,6 +792,7 @@ qboolean LibPNG_Init(void)
{(void **) &qpng_get_io_ptr, "png_get_io_ptr"},
{(void **) &qpng_destroy_write_struct, "png_destroy_write_struct"},
{(void **) &qpng_create_write_struct, "png_create_write_struct"},
{(void **) &qpng_set_unknown_chunks, "png_set_unknown_chunks"},
{(void **) &qpng_get_error_ptr, "png_get_error_ptr"},
{NULL, NULL}
@ -983,7 +985,7 @@ error:
#ifndef NPFTE
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height, enum uploadfmt fmt)
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, int width, int height, enum uploadfmt fmt)
{
char name[MAX_OSPATH];
int i;
@ -993,10 +995,24 @@ int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qb
png_byte **row_pointers;
struct pngerr errctx;
int pxsize;
int stride = width;
qbyte stereochunk = 0; //cross-eyed
png_unknown_chunk unknowns = {"sTER", &stereochunk, sizeof(stereochunk), PNG_HAVE_PLTE};
if (!FS_NativePath(filename, fsroot, name, sizeof(name)))
return false;
if (numbuffers == 2)
{
stride = width;
if (stride & 7) //standard stereo images must be padded to 8 pixels width padding between
stride += 8-(stride & 7);
stride += width;
}
else //arrange them all horizontally
stride = width * numbuffers;
if (!LibPNG_Init())
return false;
@ -1046,20 +1062,67 @@ err:
if (fmt == TF_RGBA32 || fmt == TF_BGRA32)
{
pxsize = 4;
qpng_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
qpng_set_IHDR(png_ptr, info_ptr, stride, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
}
else
{
pxsize = 3;
qpng_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
qpng_set_IHDR(png_ptr, info_ptr, stride, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
}
if (numbuffers == 2) //flag it as a standard stereographic image
qpng_set_unknown_chunks(png_ptr, info_ptr, &unknowns, 1);
qpng_write_info(png_ptr, info_ptr);
row_pointers = BZ_Malloc (sizeof(png_byte *) * height);
if (!row_pointers)
goto err;
for (i = 0; i < height; i++)
row_pointers[height - i - 1] = pixels + i * width * pxsize;
if (numbuffers == 2)
{ //standard stereographic png image.
qbyte *pixels, *left, *right;
//we need to pack the data into a single image for libpng to use
row_pointers = Z_Malloc (sizeof(png_byte *) * height + stride*height*pxsize); //must be zeroed, because I'm too lazy to specially deal with padding.
if (!row_pointers)
goto err;
pixels = (qbyte*)row_pointers + height;
//png requires right then left, which is a bit weird.
right = pixels;
left = right + (stride-width)*pxsize;
for (i = 0; i < height; i++)
{
if ((qbyte*)buffers[1])
memcpy(right + i*stride*pxsize, (qbyte*)buffers[1] + i*pxsize*width, pxsize * width);
if ((qbyte*)buffers[0])
memcpy(left + i*stride*pxsize, (qbyte*)buffers[0] + i*pxsize*width, pxsize * width);
row_pointers[height - i - 1] = pixels + i * stride * pxsize;
}
}
else if (numbuffers == 1)
{
row_pointers = BZ_Malloc (sizeof(png_byte *) * height);
if (!row_pointers)
goto err;
for (i = 0; i < height; i++)
row_pointers[height - i - 1] = (qbyte*)buffers[0] + i * width * pxsize;
}
else
{ //pack all images horizontally, because preventing people from doing the whole cross-eyed thing is cool, or something.
qbyte *pixels;
int j;
//we need to pack the data into a single image for libpng to use
row_pointers = BZ_Malloc (sizeof(png_byte *) * height + stride*height*pxsize);
if (!row_pointers)
goto err;
pixels = (qbyte*)row_pointers + height;
for (i = 0; i < height; i++)
{
for (j = 0; j < numbuffers; j++)
{
if (buffers[j])
memcpy(pixels+(width*j + i*stride)*pxsize, (qbyte*)buffers[j] + i*pxsize*width, pxsize * width);
}
row_pointers[height - i - 1] = pixels + i * stride * pxsize;
}
}
qpng_write_image(png_ptr, row_pointers);
qpng_write_end(png_ptr, info_ptr);
BZ_Free(row_pointers);
@ -1572,8 +1635,64 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression
struct jpeg_compress_struct cinfo;
JSAMPROW row_pointer[1];
if (fmt != TF_RGB24)
//convert in-place if needed.
//bgr->rgb may require copying out entirely for the first pixel to work properly.
if (fmt == TF_BGRA32)
{
qbyte *in=screendata, *out=screendata;
size_t sz = screenwidth*screenheight;
while(sz --> 0)
{
int r = in[2];
int g = in[1];
int b = in[0];
out[0] = r;
out[1] = g;
out[2] = b;
in+=4;
out+=3;
}
fmt = TF_RGB24;
}
else if (fmt == TF_RGBA32)
{
qbyte *in=screendata, *out=screendata;
size_t sz = screenwidth*screenheight;
while(sz --> 0)
{
int r = in[0];
int g = in[1];
int b = in[2];
out[0] = r;
out[1] = g;
out[2] = b;
in+=4;
out+=3;
}
fmt = TF_RGB24;
}
else if (fmt == TF_BGR24)
{
qbyte *in=screendata, *out=screendata;
size_t sz = screenwidth*screenheight;
while(sz --> 0)
{
int r = in[0];
int g = in[1];
int b = in[2];
out[0] = r;
out[1] = g;
out[2] = b;
in+=3;
out+=3;
}
fmt = TF_RGB24;
}
else if (fmt != TF_RGB24)
{
Con_Printf("screenshotJPEG: image format not supported\n");
return false;
}
if (!LIBJPEG_LOADED())
return false;
@ -1640,7 +1759,7 @@ void WritePCXfile (const char *filename, enum fs_relative fsroot, qbyte *data, i
pcx = Hunk_TempAlloc (width*height*2+1000);
if (pcx == NULL)
{
Con_Printf("SCR_ScreenShot_f: not enough memory\n");
Con_Printf("WritePCXfile: not enough memory\n");
return;
}
@ -3591,14 +3710,31 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
freedata = true;
break;
case TF_TRANS8:
case TF_H2_TRANS8_0:
{
qbyte ref = (fmt==TF_H2_TRANS8_0)?0:0xff;
mips->encoding = PTI_RGBX8;
rgbadata = BZ_Malloc(imgwidth * imgheight*4);
for (i = 0; i < imgwidth * imgheight; i++)
{
if (((qbyte*)rawdata)[i] == ref)
if (((qbyte*)rawdata)[i] == 0xff)
{//fixme: blend non-0xff neighbours. no, just use premultiplied alpha instead, where it matters.
rgbadata[i] = 0;
mips->encoding = PTI_RGBA8;
}
else
rgbadata[i] = d_8to24rgbtable[((qbyte*)rawdata)[i]];
}
if (freedata)
BZ_Free(rawdata);
freedata = true;
}
break;
case TF_H2_TRANS8_0:
{
mips->encoding = PTI_RGBX8;
rgbadata = BZ_Malloc(imgwidth * imgheight*4);
for (i = 0; i < imgwidth * imgheight; i++)
{
if (((qbyte*)rawdata)[i] == 0xff || ((qbyte*)rawdata)[i] == 0)
{//fixme: blend non-0xff neighbours. no, just use premultiplied alpha instead, where it matters.
rgbadata[i] = 0;
mips->encoding = PTI_RGBA8;

View file

@ -6,7 +6,6 @@
extern qboolean mouse_active;
static cvar_t m_filter = CVARF("m_filter", "0", CVAR_ARCHIVE);
static cvar_t m_accel = CVARF("m_accel", "0", CVAR_ARCHIVE);
static cvar_t m_forcewheel = CVARD("m_forcewheel", "1", "0: ignore mousewheels in apis where it is abiguous.\n1: Use mousewheel when it is treated as a third axis. Motion above a threshold is ignored, to avoid issues with an unknown threshold.\n2: Like 1, but excess motion is retained. The threshold specifies exact z-axis distance per notice.");
static cvar_t m_forcewheel_threshold = CVARD("m_forcewheel_threshold", "32", "Mousewheel graduations smaller than this will not trigger mousewheel deltas.");
static cvar_t m_strafeonright = CVARFD("m_strafeonright", "1", CVAR_ARCHIVE, "If 1, touching the right half of the touchscreen will strafe/move, while the left side will turn.");
@ -14,6 +13,12 @@ static cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.2", CVAR_AR
static cvar_t m_touchmajoraxis = CVARFD("m_touchmajoraxis", "1", CVAR_ARCHIVE, "When using a touchscreen, use only the major axis for strafing.");
static cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "10", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event (touchscreens).");
static cvar_t m_accel = CVARAFD("m_accel", "0", "cl_mouseAccel", CVAR_ARCHIVE, "Values >0 will amplify mouse movement proportional to velocity. Small values have great effect. A lot of good Quake Live players use around the 0.1-0.2 mark, but this depends on your mouse CPI and polling rate.");
static cvar_t m_accel_style = CVARAD("m_accel_style", "1", "cl_mouseAccelStyle", "1 = Quake Live mouse acceleration, 0 = Old style accelertion.");
static cvar_t m_accel_power = CVARAD("m_accel_power", "2", "cl_mouseAccelPower", "Used when m_accel_style is 1.\nValues 1 or below are dumb. 2 is linear and the default. 99% of accel users use this. Above 2 begins to amplify exponentially and you will get more acceleration at higher velocities. Great if you want low accel for slow movements, and high accel for fast movements. Good in combination with a sensitivity cap.");
static cvar_t m_accel_offset = CVARAD("m_accel_offset", "0", "cl_mouseAccelOffset", "Used when m_accel_style is 1.\nAcceleration will not be active until the mouse movement exceeds this speed (counts per millisecond). Negative values are supported, which has the effect of causing higher rates of acceleration to happen at lower velocities.");
static cvar_t m_accel_senscap = CVARAD("m_accel_senscap", "0", "cl_mouseSensCap", "Used when m_accel_style is 1.\nSets an upper limit on the amplified mouse movement. Great for tuning acceleration around lower velocities while still remaining in control of fast motion such as flicking.");
void QDECL joyaxiscallback(cvar_t *var, char *oldvalue)
{
int sign;
@ -63,12 +68,13 @@ void QDECL joyaxiscallback(cvar_t *var, char *oldvalue)
static cvar_t joy_advaxis[6] =
{
CVARCD("joyadvaxisx", "turnright", joyaxiscallback, "Provides a way to remap each joystick/controller axis.\n0:dead, 1:fwd, 2:pitch, 3:side, 4:yaw, 5:up, 6:roll"),
CVARC("joyadvaxisy", "lookup", joyaxiscallback),
CVARC("joyadvaxisz", "moveup", joyaxiscallback),
CVARC("joyadvaxisr", "moveright", joyaxiscallback),
CVARC("joyadvaxisu", "moveforward", joyaxiscallback),
CVARC("joyadvaxisv", "rollright", joyaxiscallback)
#define ADVAXISDESC (const char *)"Provides a way to remap each joystick/controller axis.\nShould be set to one of: moveforward, moveback, lookup, lookdown, turnleft, turnright, moveleft, moveright, moveup, movedown, rollleft, rollright"
CVARCD("joyadvaxisx", "turnright", joyaxiscallback, ADVAXISDESC),
CVARCD("joyadvaxisy", "lookup", joyaxiscallback, ADVAXISDESC),
CVARCD("joyadvaxisz", "moveup", joyaxiscallback, ADVAXISDESC),
CVARCD("joyadvaxisr", "moveright", joyaxiscallback, ADVAXISDESC),
CVARCD("joyadvaxisu", "moveforward", joyaxiscallback, ADVAXISDESC),
CVARCD("joyadvaxisv", "rollright", joyaxiscallback, ADVAXISDESC)
};
static cvar_t joy_advaxisscale[6] =
{
@ -240,6 +246,8 @@ void IN_DeviceIDs_Enumerate(void *ctx, const char *type, const char *devicename,
devicename = COM_QuotedString(devicename, buf, sizeof(buf), false);
if (!qdevid)
Con_Printf("%s\t%s\t%s\n", type, "N/A", devicename);
else if (*qdevid == DEVID_UNSET)
Con_Printf("%s\t%s\t%s\n", type, "Unset", devicename);
else
Con_Printf("%s\t%i\t%s\n", type, *qdevid, devicename);
}
@ -291,13 +299,17 @@ void IN_Init(void)
events_used = 0;
Cvar_Register (&m_filter, "input controls");
Cvar_Register (&m_accel, "input controls");
Cvar_Register (&m_forcewheel, "Input Controls");
Cvar_Register (&m_forcewheel_threshold, "Input Controls");
Cvar_Register (&m_strafeonright, "input controls");
Cvar_Register (&m_fatpressthreshold, "input controls");
Cvar_Register (&m_slidethreshold, "input controls");
Cvar_Register (&m_touchmajoraxis, "input controls");
Cvar_Register (&m_accel, "input controls");
Cvar_Register (&m_accel_style, "input controls");
Cvar_Register (&m_accel_power, "input controls");
Cvar_Register (&m_accel_offset, "input controls");
Cvar_Register (&m_accel_senscap, "input controls");
for (i = 0; i < 6; i++)
{
@ -498,7 +510,7 @@ void IN_Commands(void)
}
}
void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frametime)
{
int mx, my;
double mouse_x, mouse_y, mouse_deltadist;
@ -684,9 +696,30 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
if (m_accel.value)
{
mouse_deltadist = sqrt(mx*mx + my*my);
mouse_x *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale);
mouse_y *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale);
if (m_accel_style.ival)
{
float accelsens = sensitivity.value*in_sensitivityscale;
float mousespeed = (sqrt (mx * mx + my * my)) / (1000.0f * (float) frametime);
mousespeed -= m_accel_offset.value;
if (mousespeed > 0)
{
mousespeed *= m_accel.value;
if (m_accel_power.value > 1)
accelsens += exp((m_accel_power.value - 1) * log(mousespeed));
else
accelsens = 1;
}
if (m_accel_senscap.value > 0 && accelsens > m_accel_senscap.value)
accelsens = m_accel_senscap.value;
mouse_x *= accelsens;
mouse_y *= accelsens;
}
else
{
mouse_deltadist = sqrt(mx*mx + my*my);
mouse_x *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale);
mouse_y *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale);
}
}
else
{
@ -873,7 +906,7 @@ void IN_Move (float *movements, int pnum, float frametime)
int i;
INS_Move(movements, pnum);
for (i = 0; i < MAXPOINTERS; i++)
IN_MoveMouse(&ptr[i], movements, pnum);
IN_MoveMouse(&ptr[i], movements, pnum, frametime);
for (i = 0; i < MAXJOYSTICKS; i++)
IN_MoveJoystick(&joy[i], movements, pnum, frametime);

View file

@ -8,7 +8,6 @@ SDL_Window *sdlwindow;
extern SDL_Surface *sdlsurf;
#endif
qboolean ActiveApp;
qboolean mouseactive;
extern qboolean mouseusedforgui;
extern qboolean vid_isfullscreen;
@ -705,10 +704,10 @@ void Sys_SendKeyEvents(void)
}
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
ActiveApp = true;
vid.activeapp = true;
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
ActiveApp = false;
vid.activeapp = false;
break;
case SDL_WINDOWEVENT_CLOSE:
Cbuf_AddText("quit prompt\n", RESTRICT_LOCAL);
@ -720,7 +719,7 @@ void Sys_SendKeyEvents(void)
case SDL_ACTIVEEVENT:
if (event.active.state & SDL_APPINPUTFOCUS)
{ //follow keyboard status
ActiveApp = !!event.active.gain;
vid.activeapp = !!event.active.gain;
break;
}
break;

View file

@ -55,6 +55,7 @@ typedef struct _XINPUT_VIBRATION {
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
DWORD (WINAPI *pXInputGetState)(DWORD dwUserIndex, XINPUT_STATE *pState);
DWORD (WINAPI *pXInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION *pState);
DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid);
enum
{
XINPUT_GAMEPAD_DPAD_UP = 0x0001,
@ -72,6 +73,7 @@ enum
XINPUT_GAMEPAD_X = 0x4000,
XINPUT_GAMEPAD_Y = 0x8000
};
static qboolean xinput_useaudio;
#endif
@ -173,6 +175,7 @@ static struct wjoy_s {
DWORD oldpovstate;
DWORD buttonstate;
DWORD oldbuttonstate;
soundcardinfo_t *audiodev;
} wjoy[MAX_JOYSTICKS];
static int joy_count;
@ -351,6 +354,51 @@ static void INS_HideMouse (void)
}
}
//scan for an unused device id for joysticks (now that something was pressed).
static int Joy_AllocateDevID(void)
{
int id = 0, j;
for (id = 0; ; id++)
{
for (j = 0; j < joy_count; j++)
{
if (wjoy[j].devid == id)
break;
}
if (j == joy_count)
return id;
}
}
#ifdef USINGRAWINPUT
static int Mouse_AllocateDevID(void)
{
int id = 0, j;
for (id = 0; ; id++)
{
for (j = 0; j < rawmicecount; j++)
{
if (rawmice[j].qdeviceid == id)
break;
}
if (j == rawmicecount)
return id;
}
}
static int Keyboard_AllocateDevID(void)
{
int id = 0, j;
for (id = 0; ; id++)
{
for (j = 0; j < rawkbdcount; j++)
{
if (rawkbd[j].qdeviceid == id)
break;
}
if (j == rawkbdcount)
return id;
}
}
#endif
/*
===========
@ -1008,7 +1056,7 @@ void INS_RawInput_Init(void)
Q_strncpyz(rawmice[rawmicecount].sysname, dname, sizeof(rawmice[rawmicecount].sysname));
rawmice[rawmicecount].numbuttons = 16;
rawmice[rawmicecount].oldbuttons = 0;
rawmice[rawmicecount].qdeviceid = rawmicecount;
rawmice[rawmicecount].qdeviceid = DEVID_UNSET;
rawmicecount++;
break;
case RIM_TYPEKEYBOARD:
@ -1017,7 +1065,7 @@ void INS_RawInput_Init(void)
rawkbd[rawkbdcount].handles.rawinputhandle = pRawInputDeviceList[i].hDevice;
Q_strncpyz(rawkbd[rawkbdcount].sysname, dname, sizeof(rawkbd[rawkbdcount].sysname));
rawkbd[rawkbdcount].qdeviceid = rawkbdcount;
rawkbd[rawkbdcount].qdeviceid = DEVID_UNSET;
rawkbdcount++;
break;
default:
@ -1229,13 +1277,13 @@ void INS_MouseEvent (int mstate)
if ( (mstate & (1<<i)) &&
!(sysmouse.oldbuttons & (1<<i)) )
{
IN_KeyEvent (0, true, K_MOUSE1 + i, 0);
IN_KeyEvent (sysmouse.qdeviceid, true, K_MOUSE1 + i, 0);
}
if ( !(mstate & (1<<i)) &&
(sysmouse.oldbuttons & (1<<i)) )
{
IN_KeyEvent (0, false, K_MOUSE1 + i, 0);
IN_KeyEvent (sysmouse.qdeviceid, false, K_MOUSE1 + i, 0);
}
}
@ -1343,7 +1391,7 @@ INS_Move
*/
void INS_Move (float *movements, int pnum)
{
if (ActiveApp && !Minimized)
if (vid.activeapp && !Minimized)
{
INS_MouseMove (movements, pnum);
INS_JoyMove (movements, pnum);
@ -1407,6 +1455,17 @@ void INS_RawInput_MouseRead(void)
return;
mouse = &rawmice[i];
if (mouse->qdeviceid == DEVID_UNSET)
{
if ((raw->data.mouse.usButtonFlags & (RI_MOUSE_BUTTON_1_DOWN|RI_MOUSE_BUTTON_2_DOWN|RI_MOUSE_BUTTON_3_DOWN|RI_MOUSE_BUTTON_4_DOWN|RI_MOUSE_BUTTON_5_DOWN|RI_MOUSE_WHEEL))
|| (raw->data.mouse.ulRawButtons & RI_RAWBUTTON_MASK) || raw->data.mouse.lLastX || raw->data.mouse.lLastY)
{
mouse->qdeviceid = Mouse_AllocateDevID();
}
else
return;
}
multicursor_active[mouse->qdeviceid&7] = 0;
// movement
@ -1507,6 +1566,9 @@ void INS_RawInput_KeyboardRead(void)
if (i == rawkbdcount) // not tracking this device
return;
if (rawkbd[i].qdeviceid == DEVID_UNSET)
rawkbd[i].qdeviceid = Keyboard_AllocateDevID();
down = !(raw->data.keyboard.Flags & RI_KEY_BREAK);
wParam = raw->data.keyboard.VKey ;//(-down) & 0xC0000000;
lParam = (MapVirtualKey(raw->data.keyboard.VKey, 0)<<16) | ((!!(raw->data.keyboard.Flags & RI_KEY_E0))<<24);
@ -1575,7 +1637,7 @@ static void INS_StartupJoystickId(unsigned int id)
joy = &wjoy[joy_count];
memset(joy, 0, sizeof(*joy));
joy->id = id;
joy->devid = 1+joy_count; //FIXME: this is a hack. make joysticks 1-based. this means mouse0 controls 1st player, joy0 controls 2nd player (controls wrap so joy1 controls 1st player too.
joy->devid = DEVID_UNSET;//1+joy_count; //FIXME: this is a hack. make joysticks 1-based. this means mouse0 controls 1st player, joy0 controls 2nd player (controls wrap so joy1 controls 1st player too.
// get the capabilities of the selected joystick
// abort startup if command fails
@ -1597,45 +1659,52 @@ static void INS_StartupJoystickId(unsigned int id)
joy_count++;
}
void INS_SetupControllerAudioDevices(void)
static void IN_XInput_SetupAudio(struct wjoy_s *joy)
{
#ifdef AVAIL_XINPUT
char audiodevicename[MAX_QPATH];
wchar_t mssuck[MAX_QPATH];
static GUID GUID_NULL;
GUID gplayback = GUID_NULL;
GUID gcapture = GUID_NULL;
if (joy->audiodev)
{
S_ShutdownCard(joy->audiodev);
joy->audiodev = NULL;
}
if (!xinput_useaudio)
return;
if (!joy->isxinput)
return;
if (joy->devid == DEVID_UNSET)
return;
if (pXInputGetDSoundAudioDeviceGuids(joy->id, &gplayback, &gcapture) != ERROR_SUCCESS)
return; //probably not plugged in
if (!memcmp(&gplayback, &GUID_NULL, sizeof(gplayback)))
return; //we have a controller, but no headset.
StringFromGUID2(&gplayback, mssuck, sizeof(mssuck)/sizeof(mssuck[0]));
narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses audio device %s\n", joy->id, audiodevicename);
joy->audiodev = S_SetupDeviceSeat("DirectSound", audiodevicename, joy->devid);
#endif
}
void INS_SetupControllerAudioDevices(qboolean enabled)
{
#ifdef AVAIL_XINPUT
int i;
static DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid);
static dllhandle_t *xinput;
if (!xinput)
{
dllfunction_t funcs[] =
{
{(void**)&pXInputGetDSoundAudioDeviceGuids, "XInputGetDSoundAudioDeviceGuids"},
{NULL}
};
xinput = Sys_LoadLibrary(AVAIL_XINPUT_DLL, funcs);
}
if (!pXInputGetDSoundAudioDeviceGuids)
return;
xinput_useaudio = enabled;
for (i = 0; i < joy_count; i++)
{
char audiodevicename[MAX_QPATH];
wchar_t mssuck[MAX_QPATH];
static GUID GUID_NULL;
GUID gplayback = GUID_NULL;
GUID gcapture = GUID_NULL;
if (!wjoy[i].isxinput)
continue;
if (pXInputGetDSoundAudioDeviceGuids(wjoy[i].id, &gplayback, &gcapture) != ERROR_SUCCESS)
continue; //probably not plugged in
if (!memcmp(&gplayback, &GUID_NULL, sizeof(gplayback)))
continue; //we have a controller, but no headset.
StringFromGUID2(&gplayback, mssuck, sizeof(mssuck)/sizeof(mssuck[0]));
narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses audio device %s\n", wjoy[i].id, audiodevicename);
S_SetupDeviceSeat("DirectSound", audiodevicename, wjoy[i].devid);
}
IN_XInput_SetupAudio(&wjoy[i]);
#endif
}
void INS_StartupJoystick (void)
@ -1659,12 +1728,12 @@ void INS_StartupJoystick (void)
{NULL}
};
xinput = Sys_LoadLibrary(AVAIL_XINPUT_DLL, funcs);
if (xinput)
pXInputGetDSoundAudioDeviceGuids = Sys_GetAddressForName(xinput, "XInputGetDSoundAudioDeviceGuids");
}
if (pXInputGetState)
{
DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid);
pXInputGetDSoundAudioDeviceGuids = Sys_GetAddressForName(xinput, "XInputGetDSoundAudioDeviceGuids");
for (id = 0; id < 4; id++)
{
if (joy_count == countof(wjoy))
@ -1672,7 +1741,7 @@ void INS_StartupJoystick (void)
memset(&wjoy[id], 0, sizeof(wjoy[id]));
wjoy[joy_count].isxinput = true;
wjoy[joy_count].id = id;
wjoy[joy_count].devid = id;
wjoy[joy_count].devid = DEVID_UNSET;//id;
wjoy[joy_count].numbuttons = 16;
joy_count++;
}
@ -1790,29 +1859,38 @@ void INS_Commands (void)
// loop through the joystick buttons
// key a joystick event or auxillary event for higher number buttons for each state change
buttonstate = joy->buttonstate;
if (joy->isxinput)
if (buttonstate != joy->oldbuttonstate)
{
for (i=0 ; i < joy->numbuttons ; i++)
if (joy->devid == DEVID_UNSET)
{
if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, xinputjbuttons[i], 0, true);
if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, xinputjbuttons[i], 0, false);
joy->devid = Joy_AllocateDevID();
IN_XInput_SetupAudio(joy);
}
}
else
{
for (i=0 ; i < joy->numbuttons ; i++)
if (joy->isxinput)
{
if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, dinputjbuttons[i], 0, true);
for (i=0 ; i < joy->numbuttons ; i++)
{
if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, xinputjbuttons[i], 0, true);
if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, dinputjbuttons[i], 0, false);
if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, xinputjbuttons[i], 0, false);
}
}
else
{
for (i=0 ; i < joy->numbuttons ; i++)
{
if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, dinputjbuttons[i], 0, true);
if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
Key_Event (joy->devid, dinputjbuttons[i], 0, false);
}
}
joy->oldbuttonstate = buttonstate;
}
joy->oldbuttonstate = buttonstate;
if (joy->haspov)
{
@ -1831,20 +1909,26 @@ void INS_Commands (void)
if (joy->povstate == JOY_POVLEFT)
povstate |= 0x08;
}
// determine which bits have changed and key an auxillary event for each change
for (i=0 ; i < 4 ; i++)
if (joy->oldpovstate != povstate)
{
if ( (povstate & (1<<i)) && !(joy->oldpovstate & (1<<i)) )
{
Key_Event (joy->devid, K_AUX29 + i, 0, true);
}
if (joy->devid == DEVID_UNSET)
joy->devid = Joy_AllocateDevID();
if ( !(povstate & (1<<i)) && (joy->oldpovstate & (1<<i)) )
// determine which bits have changed and key an auxillary event for each change
for (i=0 ; i < 4 ; i++)
{
Key_Event (joy->devid, K_AUX29 + i, 0, false);
if ( (povstate & (1<<i)) && !(joy->oldpovstate & (1<<i)) )
{
Key_Event (joy->devid, K_AUX29 + i, 0, true);
}
if ( !(povstate & (1<<i)) && (joy->oldpovstate & (1<<i)) )
{
Key_Event (joy->devid, K_AUX29 + i, 0, false);
}
}
joy->oldpovstate = povstate;
}
joy->oldpovstate = povstate;
}
}
}
@ -1886,16 +1970,19 @@ qboolean INS_ReadJoystick (struct wjoy_s *joy)
//do we care about the dwPacketNumber?
joy->buttonstate = xistate.Gamepad.wButtons & 0xffff;
IN_JoystickAxisEvent(joy->devid, 0, xistate.Gamepad.sThumbRX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 1, xistate.Gamepad.sThumbRY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 2, xistate.Gamepad.bRightTrigger/255.0);
IN_JoystickAxisEvent(joy->devid, 3, xistate.Gamepad.sThumbLX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 4, xistate.Gamepad.sThumbLY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 5, xistate.Gamepad.bLeftTrigger/255.0);
if (joy->devid != DEVID_UNSET)
{
IN_JoystickAxisEvent(joy->devid, 0, xistate.Gamepad.sThumbRX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 1, xistate.Gamepad.sThumbRY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 2, xistate.Gamepad.bRightTrigger/255.0);
IN_JoystickAxisEvent(joy->devid, 3, xistate.Gamepad.sThumbLX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 4, xistate.Gamepad.sThumbLY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 5, xistate.Gamepad.bLeftTrigger/255.0);
vibrator.wLeftMotorSpeed = xinput_leftvibrator.value * 0xffff;
vibrator.wRightMotorSpeed = xinput_rightvibrator.value * 0xffff;
pXInputSetState(joy->id, &vibrator);
vibrator.wLeftMotorSpeed = xinput_leftvibrator.value * 0xffff;
vibrator.wRightMotorSpeed = xinput_rightvibrator.value * 0xffff;
pXInputSetState(joy->id, &vibrator);
}
return true;
}
}
@ -1910,24 +1997,30 @@ qboolean INS_ReadJoystick (struct wjoy_s *joy)
{
joy->povstate = ji.dwPOV;
joy->buttonstate = ji.dwButtons;
IN_JoystickAxisEvent(joy->devid, 0, (ji.dwXpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 1, (ji.dwYpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 2, (ji.dwZpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 3, (ji.dwRpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 4, (ji.dwUpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 5, (ji.dwVpos - 32768.0) / 32768);
if (joy->devid != DEVID_UNSET)
{
IN_JoystickAxisEvent(joy->devid, 0, (ji.dwXpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 1, (ji.dwYpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 2, (ji.dwZpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 3, (ji.dwRpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 4, (ji.dwUpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 5, (ji.dwVpos - 32768.0) / 32768);
}
return true;
}
}
joy->povstate = 0;
joy->buttonstate = 0;
IN_JoystickAxisEvent(joy->devid, 0, 0);
IN_JoystickAxisEvent(joy->devid, 1, 0);
IN_JoystickAxisEvent(joy->devid, 2, 0);
IN_JoystickAxisEvent(joy->devid, 3, 0);
IN_JoystickAxisEvent(joy->devid, 4, 0);
IN_JoystickAxisEvent(joy->devid, 5, 0);
if (joy->devid != DEVID_UNSET)
{
IN_JoystickAxisEvent(joy->devid, 0, 0);
IN_JoystickAxisEvent(joy->devid, 1, 0);
IN_JoystickAxisEvent(joy->devid, 2, 0);
IN_JoystickAxisEvent(joy->devid, 3, 0);
IN_JoystickAxisEvent(joy->devid, 4, 0);
IN_JoystickAxisEvent(joy->devid, 5, 0);
}
// read error occurred
// turning off the joystick seems too harsh for 1 read error,
@ -1977,10 +2070,12 @@ void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char
{
int idx;
for (idx = 0; idx < rawmicecount; idx++)
callback(ctx, "mouse", rawmice[idx].sysname?rawmice[idx].sysname:va("raw%i", idx), &rawmice[idx].qdeviceid);
for (idx = 0; idx < rawkbdcount; idx++)
callback(ctx, "keyboard", rawkbd[idx].sysname?rawkbd[idx].sysname:va("rawk%i", idx), &rawkbd[idx].qdeviceid);
callback(ctx, "keyboard", "system", NULL);
for (idx = 0; idx < rawmicecount; idx++)
callback(ctx, "mouse", rawmice[idx].sysname?rawmice[idx].sysname:va("raw%i", idx), &rawmice[idx].qdeviceid);
#if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7)
if (dinput >= DINPUT_VERSION_DX7 && g_pMouse7)
@ -1993,10 +2088,13 @@ void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char
for (idx = 0; idx < joy_count; idx++)
{
int odevid = wjoy[idx].devid;
if (wjoy[idx].isxinput)
callback(ctx, "joy", va("xi%i", wjoy[idx].id), &wjoy[idx].devid);
else
callback(ctx, "joy", va("mmj%i", wjoy[idx].id), &wjoy[idx].devid);
if (odevid != wjoy[idx].devid)
IN_XInput_SetupAudio(&wjoy[idx]);
}
}

View file

@ -59,7 +59,9 @@ void INS_Init (void);
void INS_Shutdown (void);
void INS_Commands (void); //final chance to call IN_MouseMove/IN_KeyEvent each frame
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid));
void INS_SetupControllerAudioDevices(void); //creates audio devices for each controller (where controllers have their own audio devices)
void INS_SetupControllerAudioDevices(qboolean enabled); //creates audio devices for each controller (where controllers have their own audio devices)
#define DEVID_UNSET -1
extern cvar_t cl_nodelta;
extern cvar_t cl_c2spps;

View file

@ -323,7 +323,7 @@ int con_commandmatch;
void CompleteCommand (qboolean force)
{
char *cmd, *s;
char *desc;
const char *desc;
s = key_lines[edit_line]+1;
if (*s == '\\' || *s == '/')
@ -2172,7 +2172,7 @@ qboolean Key_MouseShouldBeFree(void)
if (Key_Dest_Has(kdm_editor))
return true;
// if (!ActiveApp)
// if (!vid.activeapp)
// return true;
if (Key_Dest_Has(kdm_emenu))

View file

@ -805,8 +805,9 @@ menubind_t *MC_AddBind(menu_t *menu, int cx, int bx, int y, const char *caption,
strcpy(n->command, command);
if (tooltip)
{
n->common.tooltip = n->command+strlen(n->command)+1;
strcpy(n->common.tooltip, tooltip);
char *tip = n->command+strlen(n->command)+1;
n->common.tooltip = tip;
strcpy(tip, tooltip);
}
n->common.width = n->captionwidth + 64;
n->common.height = 8;

View file

@ -25,7 +25,7 @@ static cvar_t sb_showtimelimit = CVARF("sb_showtimelimit", "0", CVAR_ARCHIVE);
static cvar_t sb_alpha = CVARF("sb_alpha", "0.7", CVAR_ARCHIVE);
vrect_t joinbutton;
vrect_t joinbutton, specbutton;
static float refreshedtime;
static int isrefreshing;
static int serverpreview;
@ -62,6 +62,7 @@ void M_Serverlist_Init(void)
}
typedef struct {
int servers_top;
int visibleslots;
int scrollpos;
int selectedpos;
@ -278,7 +279,7 @@ static void SL_ServerDraw (int x, int y, menucustom_t *ths, menu_t *menu)
serverhighlight[(int)stype][2],
1.0);
}
else if (thisone == info->scrollpos + (int)(mousecursor_y-16)/8 && mousecursor_x < x)
else if (thisone == info->scrollpos + (int)(mousecursor_y-info->servers_top)/8 && mousecursor_x < x)
R2D_ImageColours((sin(realtime*4.4)*0.25)+0.5, (sin(realtime*4.4)*0.25)+0.5, 0.08, sb_alpha.value);
else if (selectedserver.inuse && NET_CompareAdr(&si->adr, &selectedserver.adr))
R2D_ImageColours(((sin(realtime*4.4)*0.25)+0.5) * 0.5, ((sin(realtime*4.4)*0.25)+0.5)*0.5, 0.08*0.5, sb_alpha.value);
@ -317,7 +318,7 @@ static qboolean SL_ServerKey (menucustom_t *ths, menu_t *menu, int key, unsigned
if (key == K_MOUSE1)
{
oldselection = info->selectedpos;
info->selectedpos = info->scrollpos + (mousecursor_y-16)/8;
info->selectedpos = info->scrollpos + (mousecursor_y-info->servers_top)/8;
server = Master_SortedServer(info->selectedpos);
selectedserver.inuse = true;
@ -559,6 +560,7 @@ static void SL_PostDraw (menu_t *menu)
R2D_FillBlock (x, y+1, 32, 3);
R2D_ImagePaletteColour (Sbar_ColorForMap(server->moreinfo->players[i].botc), 1.0);
R2D_FillBlock (x, y+4, 32, 4);
R2D_ImageColours (1.0, 1.0, 1.0, 1.0);
Draw_FunStringWidth (x, y, va("%3i", server->moreinfo->players[i].frags), 32-4, true, false);
}
x += 32+8;
@ -586,24 +588,53 @@ static void SL_PostDraw (menu_t *menu)
Draw_FunStringWidth(vid.width/2 - 100, vid.height/2 + 0, "Please wait", 200, 2, false);
}
if ((server->special & SS_PROTOCOLMASK) == SS_QUAKEWORLD)
{
int lx = vid.width/2 - w/2;
int y = vid.height/2 - h/2 - 4 + h;
int sw;
int bh, bw;
qboolean active = false;
w += 16;
h = 24;
bw = w+16+12;
bh = 24;
// lx += bw-12;
bw = strlen("Observe")*8 + 24;
bw = ((bw+15)/16) * 16; //width must be a multiple of 16
// lx -= bw;
specbutton.x = lx;
specbutton.y = y;
specbutton.width = bw + 16;
specbutton.height = bh + 16;
R2D_ImageColours(1,1,1,1);
Draw_TextBox(lx, y, bw/8, bh/8);
y += 8;
lx += 8;
if (mousecursor_x >= specbutton.x && mousecursor_x < specbutton.x+specbutton.width)
if (mousecursor_y >= specbutton.y && mousecursor_y < specbutton.y+specbutton.height)
active = true;
Draw_FunStringWidth(lx, y + (bh-8)/2, "Observe", bw, 2, active);y+=8;
}
{
int lx = vid.width/2 - w/2;
int y = vid.height/2 - h/2 - 4 + h;
int bw, bh;
qboolean active = false;
bw = w+16;
bh = 24;
lx += w-12;
w = strlen("join")*8 + 24;
w = ((w+15)/16) * 16; //width must be a multiple of 16
lx -= w;
bw = strlen("Join")*8 + 24;
bw = ((bw+15)/16) * 16; //width must be a multiple of 16
lx -= bw;
joinbutton.x = lx;
joinbutton.y = y;
joinbutton.width = w + 16;
joinbutton.height = h + 16;
joinbutton.width = bw + 16;
joinbutton.height = bh + 16;
R2D_ImageColours(1,1,1,1);
Draw_TextBox(lx, y, w/8, h/8);
Draw_TextBox(lx, y, bw/8, bh/8);
y += 8;
lx += 8;
@ -611,7 +642,7 @@ static void SL_PostDraw (menu_t *menu)
if (mousecursor_y >= joinbutton.y && mousecursor_y < joinbutton.y+joinbutton.height)
active = true;
Draw_FunStringWidth(lx, y + (h-8)/2, "Join", w, 2, active);y+=8;
Draw_FunStringWidth(lx, y + (bh-8)/2, "Join", bw, 2, active);y+=8;
}
}
else if (isrefreshing)
@ -658,7 +689,13 @@ static qboolean SL_Key (int key, menu_t *menu)
if (mousecursor_y >= joinbutton.y && mousecursor_y < joinbutton.y+joinbutton.height)
{
serverpreview = false;
goto doconnect;
goto dojoin;
}
if (mousecursor_x >= specbutton.x && mousecursor_x < specbutton.x+joinbutton.width)
if (mousecursor_y >= specbutton.y && mousecursor_y < specbutton.y+joinbutton.height)
{
serverpreview = false;
goto dospec;
}
return true;
}
@ -698,10 +735,13 @@ static qboolean SL_Key (int key, menu_t *menu)
else if (key == 'b' || key == 'o' || key == 'j' || key == K_ENTER || key == K_KP_ENTER) //join
{
if (key == 's' || key == 'o')
{
dospec:
Cbuf_AddText("spectator 1\n", RESTRICT_LOCAL);
}
else if (key == 'j')
{
doconnect:
dojoin:
Cbuf_AddText("spectator 0\n", RESTRICT_LOCAL);
}
@ -834,7 +874,7 @@ static void SL_ServerPlayer (int x, int y, menucustom_t *ths, menu_t *menu)
R2D_FillBlock (x, y, 32, 4);
R2D_ImagePaletteColour (Sbar_ColorForMap(selectedserver.detail->players[i].botc), 1.0);
R2D_FillBlock (x, y+4, 32, 4);
R2D_ImageColours (1.0, 1.0, 1.0, 1.0);
Draw_FunStringWidth (x, y, va("%3i", selectedserver.detail->players[i].frags), 32-4, true, false);
}
@ -1047,14 +1087,16 @@ void M_Menu_ServerList2_f(void)
info = (serverlist_t*)(menu + 1);
y = 8;
y = 16;
cust = MC_AddCustom(menu, 0, y, NULL, 0);
cust->draw = SL_TitlesDraw;
cust->key = SL_TitlesKey;
cust->common.height = 8;
cust->common.width = vid.width-8;
y+=8;
info->visibleslots = (vid.height-16 - 64);
info->servers_top = y;
info->visibleslots = (vid.height-info->servers_top - 64);
cust = MC_AddCustom(menu, vid.width-8, 16, NULL, 0);
cust->draw = SL_SliderDraw;
@ -1063,7 +1105,7 @@ void M_Menu_ServerList2_f(void)
cust->common.width = 8;
info->visibleslots = (info->visibleslots-8)/8;
for (i = 0, y = 16; i <= info->visibleslots; y +=8, i++)
for (i = 0, y = info->servers_top; i <= info->visibleslots; y +=8, i++)
{
cust = MC_AddCustom(menu, 0, y, NULL, i);
if (i==0)

View file

@ -2770,7 +2770,7 @@ static void QDECL capture_raw_video (void *vctx, void *data, int frame, int widt
char filename[MAX_OSPATH];
ctx->frames = frame+1;
Q_snprintfz(filename, sizeof(filename), "%s%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension);
SCR_ScreenShot(filename, ctx->fsroot, data, width, height, fmt);
SCR_ScreenShot(filename, ctx->fsroot, &data, 1, width, height, fmt);
}
static void QDECL capture_raw_audio (void *vctx, void *data, int bytes)
{

View file

@ -200,6 +200,7 @@ void M_Menu_Options_f (void)
"Fisheye",
"Panoramic",
"Lambert Azimuthal Equal-Area",
"Equirectangular",
NULL
};
static const char *projectionvalues[] = {

View file

@ -486,7 +486,7 @@ void M_Menu_SinglePlayer_f (void)
{
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/ttl_sgl.lmp");
menu->selecteditem = (menuoption_t*)
MC_AddConsoleCommandQBigFont (menu, 72, 32, "New Game", "closemenu;disconnect;maxclients 1;deathmatch 0;coop 0;startmap_sp\n");
@ -500,7 +500,7 @@ void M_Menu_SinglePlayer_f (void)
{ //q1
menu = M_CreateMenu(0);
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/p_option.lmp");
MC_AddCenterPicture(menu, 4, 24, "gfx/ttl_sgl.lmp");
}
break;
}

View file

@ -144,7 +144,7 @@ typedef struct { //must be first of each structure type.
int width; //total width
int height; //total height
int extracollide; // dirty hack to stretch collide box left (the real fix is to have separate collide/render rects)
char *tooltip;
const char *tooltip;
qboolean noselectionsound:1;
qboolean iszone:1;
qboolean ishidden:1;
@ -325,7 +325,7 @@ typedef struct menubulk_s {
menutype_t type;
int variant;
char *text;
char *tooltip;
const char *tooltip;
char *consolecmd; // console command
cvar_t *cvar; // check box, slider
int flags; // check box

View file

@ -72,7 +72,7 @@ typedef struct {
int numframes;
synctype_t synctype;
//qtest stops here
int flags;
int flags; //offset 0x4c
float size;
//quake stops here
int num_st;

View file

@ -6921,7 +6921,7 @@ qboolean CSQC_DrawView(void)
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
G_FLOAT(OFS_PARM0) = vid.width;
G_FLOAT(OFS_PARM1) = vid.height;
G_FLOAT(OFS_PARM2) = !m_state;
G_FLOAT(OFS_PARM2) = !m_state && !r_refdef.eyeoffset[0] && !r_refdef.eyeoffset[1];
}
//end EXT_CSQC_1
if (csqcg.f_updateviewloading && cls.state && cls.state < ca_active)
@ -6943,7 +6943,7 @@ qboolean CSQC_DrawView(void)
qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid)
{
static qbyte csqckeysdown[K_MAX/8];
static qbyte csqckeysdown[K_MAX];
void *pr_globals;
#ifdef TEXTEDITOR
extern qboolean editormodal;
@ -6962,18 +6962,24 @@ qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid)
G_FLOAT(OFS_PARM2) = unicode;
G_FLOAT(OFS_PARM3) = devid;
//small sanity check, so things don't break too much if things get big.
if (devid < 0 || (unsigned)devid >= sizeof(csqckeysdown[0])*8)
devid = sizeof(csqckeysdown[0])*8-1;
if (key < 0 || key >= K_MAX)
key = 0; //panic. everyone panic.
if (down)
{
qcinput_scan = G_FLOAT(OFS_PARM1);
qcinput_unicode = G_FLOAT(OFS_PARM2);
csqckeysdown[key>>3] |= (1<<(key&7));
csqckeysdown[key] |= (1u<<devid);
}
else
{
if (key && !(csqckeysdown[key>>3] & (1<<(key&7))))
return false;
csqckeysdown[key>>3] &= ~(1<<(key&7));
if (key && !(csqckeysdown[key] & (1u<<devid)))
return false; //prevent up events being able to leak
csqckeysdown[key] &= ~(1u<<devid);
}
PR_ExecuteProgram (csqcprogs, csqcg.input_event);
qcinput_scan = 0; //and stop replay attacks
@ -7045,6 +7051,20 @@ qboolean CSQC_Accelerometer(float x, float y, float z)
PR_ExecuteProgram (csqcprogs, csqcg.input_event);
return G_FLOAT(OFS_RETURN);
}
qboolean CSQC_Gyroscope(float x, float y, float z)
{
void *pr_globals;
if (!csqcprogs || !csqcg.input_event)
return false;
pr_globals = PR_globals(csqcprogs, PR_CURRENT);
G_FLOAT(OFS_PARM0) = CSIE_GYROSCOPE;
G_FLOAT(OFS_PARM1) = x;
G_FLOAT(OFS_PARM2) = y;
G_FLOAT(OFS_PARM3) = z;
PR_ExecuteProgram (csqcprogs, csqcg.input_event);
return G_FLOAT(OFS_RETURN);
}
qboolean CSQC_ConsoleLink(char *text, char *info)
{

View file

@ -230,9 +230,9 @@ void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
const char *slotname = PR_GetStringOfs(prinst, OFS_PARM0);
const char *facename = PR_GetStringOfs(prinst, OFS_PARM1);
const char *sizestr = PR_GetStringOfs(prinst, OFS_PARM2);
int slotnum = G_FLOAT(OFS_PARM3);
//float fix_scale = G_FLOAT(OFS_PARM4);
//float fix_voffset = G_FLOAT(OFS_PARM5);
int slotnum = (prinst->callargc>3)?G_FLOAT(OFS_PARM3):-1;
//float fix_scale = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):0;
//float fix_voffset = (prinst->callargc>5)G_FLOAT(OFS_PARM5):0;
int i, sz;
world_t *world = prinst->parms->user;

View file

@ -200,48 +200,37 @@ extern "C" {
#include <crtdbg.h>
#endif
//msvcrt lacks any and all c99 support.
#ifdef _WIN32
#define fPRIp "%p"
#define PRIxPTR "p"
//totally different from any other system
#define fPRIllx "%I64x"
#define fPRIllu "%I64u"
#define fPRIlli "%I64i"
#else
//make SURE we get 0xdeadbeef for this
#if FTE_WORDSIZE != 32
#define fPRIp "%#zx"
#else
#define fPRIp "%#x"
#endif
#define PRIx64 "I64x"
#define PRIu64 "I64u"
#define PRIi64 "I64i"
//assume some c99 support where we print long long int types.
#define fPRIllx "%llx"
#define fPRIllu "%llu"
#define fPRIlli "%lli"
#endif
#ifdef _WIN32
//windows does not follow c99 at all
#ifdef _WIN64
#define fPRIzx "%Ix"
#define fPRIzu "%Iu"
#define fPRIzi "%Ii"
#define PRIxSIZE "Ix"
#define PRIuSIZE "Iu"
#define PRIiSIZE "Ii"
#else
#define fPRIzx "%x"
#define fPRIzu "%u"
#define fPRIzi "%i"
#define PRIxSIZE "x"
#define PRIuSIZE "u"
#define PRIiSIZE "i"
#endif
#elif FTE_WORDSIZE != 32
//64bit systems are expected to have an awareness of c99
#define fPRIzx "%zx"
#define fPRIzu "%zu"
#define fPRIzi "%zi"
#else
//regular old c89 for 32bit platforms.
#define fPRIzx "%x"
#define fPRIzu "%u"
#define fPRIzi "%i"
#include <inttypes.h>
//these are non-standard. c99 would expect people to just use %zx etc
#if FTE_WORDSIZE != 32
//64bit systems are expected to have an awareness of c99
#define PRIxSIZE "zx"
#define PRIuSIZE "zu"
#define PRIiSIZE "zi"
#else
//regular old c89 for 32bit platforms.
#define PRIxSIZE "x"
#define PRIuSIZE "u"
#define PRIiSIZE "i"
#endif
#endif

View file

@ -6,7 +6,7 @@
#endif
void Mod_SetParent (mnode_t *node, mnode_t *parent);
static int D3_LeafnumForPoint (struct model_s *model, vec3_t point);
static int D3_ClusterForPoint (struct model_s *model, vec3_t point);
#ifndef SERVERONLY
static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
@ -118,7 +118,7 @@ static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
m[surf].numindexes = numindicies;
vdata = ZG_Malloc(&model->memgroup, numverts * (sizeof(vecV_t) + sizeof(vec2_t) + sizeof(vec3_t) + sizeof(vec4_t)) + numindicies * sizeof(index_t));
m[surf].colors4f_array = (vec4_t*)vdata;vdata += sizeof(vec4_t)*numverts;
m[surf].colors4f_array[0] = (vec4_t*)vdata;vdata += sizeof(vec4_t)*numverts;
m[surf].xyz_array = (vecV_t*)vdata;vdata += sizeof(vecV_t)*numverts;
m[surf].st_array = (vec2_t*)vdata;vdata += sizeof(vec2_t)*numverts;
m[surf].normals_array = (vec3_t*)vdata;vdata += sizeof(vec3_t)*numverts;
@ -156,22 +156,22 @@ static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
sub->mins[j] = f;
}
m[surf].colors4f_array[v][0] = 255;
m[surf].colors4f_array[v][1] = 255;
m[surf].colors4f_array[v][2] = 255;
m[surf].colors4f_array[v][3] = 255;
m[surf].colors4f_array[0][v][0] = 255;
m[surf].colors4f_array[0][v][1] = 255;
m[surf].colors4f_array[0][v][2] = 255;
m[surf].colors4f_array[0][v][3] = 255;
data = COM_ParseOut(data, token, sizeof(token));
/*if its not closed yet, there's an optional colour value*/
if (strcmp(token, ")"))
{
m[surf].colors4f_array[v][0] = atof(token)/255;
m[surf].colors4f_array[0][v][0] = atof(token)/255;
data = COM_ParseOut(data, token, sizeof(token));
m[surf].colors4f_array[v][1] = atof(token)/255;
m[surf].colors4f_array[0][v][1] = atof(token)/255;
data = COM_ParseOut(data, token, sizeof(token));
m[surf].colors4f_array[v][2] = atof(token)/255;
m[surf].colors4f_array[0][v][2] = atof(token)/255;
data = COM_ParseOut(data, token, sizeof(token));
m[surf].colors4f_array[v][3] = atof(token)/255;
m[surf].colors4f_array[0][v][3] = atof(token)/255;
data = COM_ParseOut(data, token, sizeof(token));
if (strcmp(token, ")"))
@ -190,7 +190,7 @@ static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
data = COM_ParseOut(data, token, sizeof(token));
if (strcmp(token, "}"))
return false;
sub->needload = false;
// sub->loadstate = MLS_LOADED;
sub->fromgame = fg_doom3;
sub->type = mod_brush;
@ -396,7 +396,7 @@ unsigned char *D3_CalcVis(model_t *mod, vec3_t org)
static unsigned char vis[256];
vec_t newbounds[4];
start = D3_LeafnumForPoint(mod, org);
start = D3_ClusterForPoint(mod, org);
/*figure out which area we're in*/
if (start < 0)
{
@ -452,7 +452,7 @@ void D3_GenerateAreas(model_t *mod)
cl_static_entities[cl.num_statics].pvscache.num_leafs = 1;
cl_static_entities[cl.num_statics].pvscache.leafnums[0] = area;
if (ent->model && !ent->model->needload)
if (ent->model && ent->model->loadstate != MLS_NOTLOADED)
cl.num_statics++;
else
break;
@ -465,12 +465,12 @@ void D3_GenerateAreas(model_t *mod)
static void D3_FindTouchedLeafs (struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs)
{
}
static qbyte *D3_LeafPVS (struct model_s *model, int num, qbyte *buffer, unsigned int buffersize)
static qbyte *D3_ClusterPVS (struct model_s *model, int num, qbyte *buffer, unsigned int buffersize)
{
memset(buffer, 0xff, buffersize);
return buffer;
}
static int D3_LeafnumForPoint (struct model_s *model, vec3_t point)
static int D3_ClusterForPoint (struct model_s *model, vec3_t point)
{
float p;
int c;
@ -841,7 +841,7 @@ return;
D3_RecursiveSurfCheck (node->child[side^1], midf, p2f, mid, p2);
}
static qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, struct trace_s *trace)
static qboolean D3_Trace (struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, struct trace_s *trace)
{
int i;
float e1,e2;
@ -1008,7 +1008,7 @@ typedef struct
int v[2];
int fl[2];
} d3edge_t;
qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf)
qboolean QDECL D3_LoadMap_CollisionMap(model_t *mod, void *buf, size_t bufsize)
{
int pedges[64];
cm_surface_t *surf;
@ -1296,17 +1296,17 @@ qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf)
/*load up the .map so we can get some entities (anyone going to bother making a qc mod compatible with this?)*/
COM_StripExtension(mod->name, token, sizeof(token));
mod->entities = FS_LoadMallocFile(va("%s.map", token));
mod->entities = FS_LoadMallocFile(va("%s.map", token), NULL);
mod->funcs.FindTouchedLeafs = D3_FindTouchedLeafs;
mod->funcs.NativeTrace = D3_Trace;
mod->funcs.PointContents = D3_PointContents;
mod->funcs.FatPVS = D3_FatPVS;
mod->funcs.LeafnumForPoint = D3_LeafnumForPoint;
mod->funcs.ClusterForPoint = D3_ClusterForPoint;
mod->funcs.StainNode = D3_StainNode;
mod->funcs.LightPointValues = D3_LightPointValues;
mod->funcs.EdictInFatPVS = D3_EdictInFatPVS;
mod->funcs.LeafPVS = D3_LeafPVS;
mod->funcs.ClusterPVS = D3_ClusterPVS;
mod->fromgame = fg_doom3;
@ -1315,7 +1315,7 @@ qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf)
if (!isDedicated)
{
COM_StripExtension(mod->name, token, sizeof(token));
buf = FS_LoadMallocFile(va("%s.proc", token));
buf = FS_LoadMallocFile(va("%s.proc", token), NULL);
Mod_LoadMap_Proc(mod, buf);
BZ_Free(buf);
}

View file

@ -202,6 +202,29 @@ typedef struct
void CL_BlendFog(fogstate_t *result, fogstate_t *oldf, float time, fogstate_t *newf);
void CL_ResetFog(int fogtype);
typedef enum {
STEREO_OFF,
STEREO_QUAD,
STEREO_RED_CYAN,
STEREO_RED_BLUE,
STEREO_RED_GREEN,
STEREO_CROSSEYED,
//these are internal methods and do not form part of any public API
STEREO_LEFTONLY,
STEREO_RIGHTONLY
} stereomethod_t;
typedef enum
{
PROJ_STANDARD = 0,
PROJ_STEREOGRAPHIC = 1, //aka panini
PROJ_FISHEYE = 2, //standard fisheye
PROJ_PANORAMA = 3, //for nice panoramas
PROJ_LAEA = 4, //lambert azimuthal equal-area
PROJ_EQUIRECTANGULAR = 5 //projects a sphere into 2d. used by vr screenshots.
} qprojection_t;
typedef struct {
char texname[MAX_QPATH];
} rtname_t;
@ -220,6 +243,8 @@ typedef struct
vec3_t vieworg; /*logical view center*/
vec3_t viewangles;
vec3_t viewaxis[3]; /*forward, left, up (NOT RIGHT)*/
vec3_t headaxis[3]; /*this is for head mounted displays. this is relative to the view*/
vec3_t eyeoffset; /*world space, for vr screenies*/
float fov_x, fov_y, afov;
@ -251,6 +276,7 @@ typedef struct
unsigned int flipcull; /*reflected/flipped view, requires inverted culling (should be set to SHADER_CULL_FLIPPED or 0)*/
qboolean useperspective; /*not orthographic*/
stereomethod_t stereomethod;
rtname_t rt_destcolour[R_MAX_RENDERTARGETS]; /*used for 2d. written by 3d*/
rtname_t rt_sourcecolour; /*read by 2d. not used for 3d. */
rtname_t rt_depth; /*read by 2d. used by 3d (renderbuffer used if not set)*/

View file

@ -202,7 +202,7 @@ cvar_t scr_showturtle = SCVAR ("showturtle", "0");
cvar_t scr_turtlefps = SCVAR ("scr_turtlefps", "10");
cvar_t scr_sshot_compression = SCVAR ("scr_sshot_compression", "75");
cvar_t scr_sshot_type = SCVAR ("scr_sshot_type", "png");
cvar_t scr_sshot_prefix = SCVAR ("scr_sshot_prefix", "screenshots/fte");
cvar_t scr_sshot_prefix = SCVAR ("scr_sshot_prefix", "screenshots/fte-");
cvar_t scr_viewsize = CVARFC("viewsize", "100",
CVAR_ARCHIVE,
SCR_Viewsize_Callback);
@ -248,8 +248,10 @@ cvar_t vid_wndalpha = CVARD ("vid_wndalpha", "1", "When running windowed,
//more readable defaults to match conwidth/conheight.
cvar_t vid_width = CVARFD ("vid_width", "0",
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "The screen width to attempt to use, in physical pixels. 0 means use desktop resolution.");
cvar_t vid_dpi_x = CVARFD ("vid_dpi_x", "0", CVAR_NOSET, "For mods that need to determine the physical screen size (like with touchscreens). 0 means unknown");
cvar_t vid_dpi_y = CVARFD ("vid_dpi_y", "0", CVAR_NOSET, "For mods that need to determine the physical screen size (like with touchscreens). 0 means unknown");
cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far your eyes are apart, in quake units. A non-zero value will enable stereoscoping rendering. You might need some of them retro 3d glasses. Hardware support is recommended, see r_stereo_context.");
cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far apart your eyes are, in quake units. A non-zero value will enable stereoscoping rendering. You might need some of them retro 3d glasses. Hardware support is recommended, see r_stereo_context.");
cvar_t r_stereo_method = CVARFD("r_stereo_method", "0", CVAR_ARCHIVE, "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain.");
extern cvar_t r_dodgytgafiles;
@ -392,7 +394,7 @@ cvar_t r_shadow_heightscale_bumpmap = CVARD ("r_shadow_heightscale_bumpmap",
cvar_t r_glsl_offsetmapping = CVARFD ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Enables the use of paralax mapping, adding fake depth to textures.");
cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04");
cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer, but noticably more expensive at high resolutions. r_glsl_offsetmapping must be set.");
cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer, but noticably more expensive at high resolutions. r_glsl_offsetmapping must be set.");
cvar_t r_glsl_turbscale = CVARFD ("r_glsl_turbscale", "1", CVAR_ARCHIVE, "Controls the strength of water ripples (used by the altwater glsl code).");
cvar_t r_fastturbcolour = CVARFD ("r_fastturbcolour", "0.1 0.2 0.3", CVAR_ARCHIVE, "The colour to use for water surfaces draw with r_waterstyle 0.\n");
@ -684,6 +686,8 @@ void Renderer_Init(void)
Cvar_Register (&vid_refreshrate, VIDCOMMANDGROUP);
Cvar_Register (&vid_multisample, GLRENDEREROPTIONS);
Cvar_Register (&vid_srgb, GLRENDEREROPTIONS);
Cvar_Register (&vid_dpi_x, GLRENDEREROPTIONS);
Cvar_Register (&vid_dpi_y, GLRENDEREROPTIONS);
Cvar_Register (&vid_desktopsettings, VIDCOMMANDGROUP);
@ -837,7 +841,7 @@ void Renderer_Init(void)
qboolean Renderer_Started(void)
{
return !!currentrendererstate.renderer;
return !r_blockvidrestart && !!currentrendererstate.renderer;
}
void Renderer_Start(void)
@ -1046,14 +1050,17 @@ void R_ShutdownRenderer(qboolean devicetoo)
TRACE(("dbg: R_ApplyRenderer: R_DeInit\n"));
R_DeInit();
}
R_DeInit = NULL;
if (Draw_Shutdown)
Draw_Shutdown();
Draw_Shutdown = NULL;
if (VID_DeInit && devicetoo)
{
TRACE(("dbg: R_ApplyRenderer: VID_DeInit\n"));
VID_DeInit();
VID_DeInit = NULL;
}
TRACE(("dbg: R_ApplyRenderer: SCR_DeInit\n"));
@ -1143,6 +1150,9 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
r_softwarebanding = r_softwarebanding_cvar.ival;
r_deluxemapping = r_deluxemapping_cvar.ival;
vid.dpi_x = 0;
vid.dpi_y = 0;
if (qrenderer != QR_NONE) //graphics stuff only when not dedicated
{
size_t sz;
@ -1260,6 +1270,9 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n"));
// host_hunklevel = Hunk_LowMark();
Cvar_ForceSetValue(&vid_dpi_x, vid.dpi_x);
Cvar_ForceSetValue(&vid_dpi_y, vid.dpi_y);
TRACE(("dbg: R_ApplyRenderer: R_PreNewMap (how handy)\n"));
Surf_PreNewMap();

View file

@ -81,7 +81,7 @@ void SCR_ShowPic_Remove_f(void);
void Draw_TextBox (int x, int y, int width, int lines);
enum fs_relative;
enum uploadfmt;
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height, enum uploadfmt fmt);
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int width, int height, enum uploadfmt fmt);
void SCR_DrawTwoDimensional(int uimenu, qboolean nohud);

View file

@ -1577,6 +1577,9 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device, int seat)
memset(sc, 0, sizeof(*sc));
sc->seat = seat;
sc->next = sndcardinfo;
sndcardinfo = sc;
// set requested rate
if (snd_khz.ival >= 1000)
sc->sn.speed = snd_khz.ival;
@ -1632,7 +1635,7 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device, int seat)
if (st)
{
S_DefaultSpeakerConfiguration(sc);
if (sndcardinfo)
if (snd_speed)
{ //if the sample speeds of multiple soundcards do not match, it'll fail.
if (snd_speed != sc->sn.speed)
{
@ -1644,8 +1647,8 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device, int seat)
else
snd_speed = sc->sn.speed;
sc->next = sndcardinfo;
sndcardinfo = sc;
if (sc->seat == -1 && sc->ListenerUpdate)
sc->seat = 0; //hardware rendering won't cope with seat=-1
return sc;
}
}
@ -1664,7 +1667,8 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device, int seat)
if (st == 1)
{
S_DefaultSpeakerConfiguration(sc);
if (sndcardinfo)
if (snd_speed)
{ //if the sample speeds of multiple soundcards do not match, it'll fail.
if (snd_speed != sc->sn.speed)
{
@ -1678,14 +1682,13 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device, int seat)
if (sc->seat == -1 && sc->ListenerUpdate)
sc->seat = 0; //hardware rendering won't cope with seat=-1
sc->next = sndcardinfo;
sndcardinfo = sc;
return sc;
}
}
}
Z_Free(sc);
S_ShutdownCard(sc);
if (!driver)
Con_TPrintf("Could not start audio device \"%s\"\n", device?device:"default");
else
@ -1693,9 +1696,9 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device, int seat)
return NULL;
}
void S_SetupDeviceSeat(char *driver, char *device, int seat)
soundcardinfo_t *S_SetupDeviceSeat(char *driver, char *device, int seat)
{
SNDDMA_Init(driver, device, seat);
return SNDDMA_Init(driver, device, seat);
/*
soundcardinfo_t *sc;
for (sc = sndcardinfo; sc; sc = sc->next)
@ -1781,7 +1784,7 @@ void S_Startup (void)
if (!sndcardinfo && !nodefault)
{
#if defined(_WIN32) && !defined(FTE_SDL)
INS_SetupControllerAudioDevices();
INS_SetupControllerAudioDevices(true);
#endif
if (!sndcardinfo)
SNDDMA_Init(NULL, NULL, -1);
@ -2021,26 +2024,28 @@ void S_Init (void)
void S_ShutdownCard(soundcardinfo_t *sc)
{
soundcardinfo_t *prev;
soundcardinfo_t **link;
if (sndcardinfo == sc)
sndcardinfo = sc->next;
else
for (link = &sndcardinfo; *link; link = &(*link)->next)
{
for (prev = sndcardinfo; prev->next; prev = prev->next)
if (*link == sc)
{
if (prev->next == sc)
prev->next = sc->next;
*link = sc->next;
if (sc->Shutdown)
sc->Shutdown(sc);
Z_Free(sc);
break;
}
}
sc->Shutdown(sc);
Z_Free(sc);
}
void S_Shutdown(qboolean final)
{
soundcardinfo_t *sc, *next;
#if defined(_WIN32) && !defined(FTE_SDL)
INS_SetupControllerAudioDevices(false);
#endif
for (sc = sndcardinfo; sc; sc=next)
{
next = sc->next;

View file

@ -824,7 +824,7 @@ void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
result = VFS_READ(f, data, filesize);
if (result != filesize)
Con_SafePrintf("S_LoadSound() fread: Filename: %s, expected "fPRIzu", result was "fPRIzu"\n", name, filesize, result);
Con_SafePrintf("S_LoadSound() fread: Filename: %s, expected %"PRIuSIZE", result was %"PRIuSIZE"\n", name, filesize, result);
VFS_CLOSE(f);
}

View file

@ -164,6 +164,7 @@ void S_EndPrecaching (void);
void S_PaintChannels(soundcardinfo_t *sc, int endtime);
void S_InitPaintChannels (soundcardinfo_t *sc);
soundcardinfo_t *S_SetupDeviceSeat(char *driver, char *device, int seat);
void S_ShutdownCard (soundcardinfo_t *sc);
void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc);
@ -341,6 +342,4 @@ typedef struct
void (QDECL *Shutdown) (void *ctx); /*destroy everything*/
} snd_capture_driver_t;
void S_SetupDeviceSeat(char *driver, char *device, int seat);
#endif

View file

@ -20,6 +20,8 @@ qboolean isDedicated = false;
void *sys_window; /*public so the renderer can attach to the correct place*/
static int sys_running = false;
int sys_glesversion;
extern qboolean r_blockvidrestart;
float sys_dpi_x, sys_dpi_y;
int sys_soundflags; /*1 means active. 2 means reset (so claim that its not active for one frame to force a reset)*/
static void *sys_memheap;
static unsigned int sys_lastframe;
@ -110,10 +112,12 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject
}
JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj,
jfloat ax, jfloat ay, jfloat az)
jfloat ax, jfloat ay, jfloat az,
jfloat gx, jfloat gy, jfloat gz)
{
int ret;
static vec3_t oac;
static vec3_t oacc;
static vec3_t ogyro;
//if we had an error, don't even run a frame any more.
if (*errormessage || !sys_running)
@ -122,20 +126,29 @@ JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject
return 8;
}
// Sys_Printf("starting frame\n");
#ifdef SERVERONLY
SV_Frame();
#else
unsigned int now = Sys_Milliseconds();
double tdelta = (now - sys_lastframe) * 0.001;
if (oac[0] != ax || oac[1] != ay || oac[2] != az)
if (oacc[0] != ax || oacc[1] != ay || oacc[2] != az)
{
//down: x= +9.8
//left: y= -9.8
//up: z= +9.8
CSQC_Accelerometer(ax, ay, az);
oac[0] = ax;
oac[1] = ay;
oac[2] = az;
oacc[0] = ax;
oacc[1] = ay;
oacc[2] = az;
}
if (ogyro[0] != gx || ogyro[1] != gy || ogyro[2] != gz)
{
CSQC_Gyroscope(gx * 180.0/M_PI, gy * 180.0/M_PI, gz * 180.0/M_PI);
ogyro[0] = gx;
ogyro[1] = gy;
ogyro[2] = gz;
}
Host_Frame(tdelta);
sys_lastframe = now;
@ -148,7 +161,7 @@ JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject
ret |= 2;
if (sys_keepscreenon.ival)
ret |= 4;
if (*errormessage)
if (*errormessage || !sys_running)
ret |= 8;
if (sys_orientation.modified || sys_glesversion_cvar.modified)
ret |= 16;
@ -159,9 +172,25 @@ JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject
else
ret |= 32;
}
// Sys_Printf("frame ended\n");
return ret;
}
//tells us that our old gl context is about to be nuked.
JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_killglcontext(JNIEnv *env, jobject obj)
{
if (!sys_running)
return;
if (qrenderer == QR_NONE)
return; //not initialised yet...
Sys_Printf("Killing resources\n");
R_ShutdownRenderer(true);
qrenderer = QR_NONE;
sys_glesversion = 0;
if (!r_blockvidrestart)
r_blockvidrestart = 3; //so video is restarted properly for the next frame
}
//tells us that our old gl context got completely obliterated
JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_newglcontext(JNIEnv *env, jobject obj)
{
@ -176,13 +205,14 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_openfile(JNIEnv *env, jobje
jstring openfile)
{
const char *fname = (*env)->GetStringUTFChars(env, openfile, NULL);
Host_RunFile(fname, strlen(fname), NULL);
if (sys_running)
Host_RunFile(fname, strlen(fname), NULL);
(*env)->ReleaseStringUTFChars(env, openfile, fname);
}
//called for init or resizes
JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject obj,
jint width, jint height, jint glesversion, jstring japkpath, jstring jusrpath)
jint width, jint height, jfloat dpix, jfloat dpiy, jint glesversion, jstring japkpath, jstring jusrpath)
{
const char *tmp;
@ -192,13 +222,17 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject o
vid.pixelwidth = width;
vid.pixelheight = height;
sys_glesversion = glesversion;
sys_dpi_x = dpix;
sys_dpi_y = dpiy;
if (sys_running)
{
Sys_Printf("vid size changed\n");
if (1)//FFS sys_running == 2)
if (!glesversion)
return; //gah!
Sys_Printf("vid size changed (%i %i gles%i)\n", width, height, glesversion);
if (!r_blockvidrestart)
{
//if our textures got destroyed, we need to reload them all
Cmd_ExecuteString("vid_restart\n", RESTRICT_LOCAL);
Cmd_ExecuteString("vid_reload\n", RESTRICT_LOCAL);
}
else
{
@ -246,6 +280,11 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject o
sys_running = true;
sys_lastframe = Sys_Milliseconds();
sys_orientation.modified = true;
while(r_blockvidrestart == 1)
Java_com_fteqw_FTEDroidEngine_frame(env, obj, 0,0,0, 0,0,0);
Sys_Printf("Engine started\n");
}
}
@ -321,6 +360,7 @@ void Sys_Quit(void)
SV_Shutdown();
#endif
sys_running = false;
LOGI("%s", "quitting");
longjmp(host_abort, 1);

View file

@ -26,7 +26,6 @@ SDL_Window *sdlwindow;
#ifndef isDedicated
qboolean isDedicated;
#endif
extern qboolean ActiveApp;
void Sys_Error (const char *error, ...)
{
@ -502,7 +501,7 @@ int QDECL main(int argc, char **argv)
// yield the CPU for a little while when paused, minimized, or not the focus
#if SDL_MAJOR_VERSION >= 2
if (!ActiveApp)
if (!vid.activeapp)
SDL_Delay(1);
#else
if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS))

View file

@ -49,7 +49,6 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; //13.35+
#ifdef WINRT //you're going to need a different sys_ port.
qboolean isDedicated = false;
qboolean ActiveApp;
void VARGS Sys_Error (const char *error, ...){} //eep
void VARGS Sys_Printf (char *fmt, ...){} //safe, but not ideal (esp for debugging)
void Sys_SendKeyEvents (void){} //safe, but not ideal
@ -483,7 +482,7 @@ char *Sys_GetNameForAddress(dllhandle_t *module, void *address)
#endif
int starttime;
qboolean ActiveApp, Minimized;
qboolean Minimized;
qboolean WinNT; //NT has a) proper unicode support that does not unconditionally result in errors. b) a few different registry paths.
static HANDLE hinput, houtput;
@ -928,7 +927,7 @@ cvar_t sys_disableTaskSwitch = SCVARF("sys_disableTaskSwitch", "0", CVAR_NOTFROM
LRESULT CALLBACK LowLevelKeyboardProc (INT nCode, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
if (ActiveApp)
if (vid.activeapp)
switch (nCode)
{
case HC_ACTION:
@ -4246,7 +4245,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
sleeptime = Host_Frame (time);
oldtime = newtime;
SetHookState(ActiveApp);
SetHookState(vid.activeapp);
/*sleep if its not yet time for a frame*/
if (sleeptime)

View file

@ -61,6 +61,7 @@ typedef struct
typedef struct
{
qboolean activeapp;
qboolean isminimized; //can omit rendering as it won't be seen anyway.
int fullbright; // index of first fullbright color
@ -79,6 +80,9 @@ typedef struct
unsigned rotpixelheight; /*pixel after rotation in pixels*/
unsigned pixelwidth; /*true height in pixels*/
unsigned pixelheight; /*true width in pixels*/
float dpi_x;
float dpi_y;
} viddef_t;
extern viddef_t vid; // global video state

View file

@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <ctype.h> // for isdigit();
cvar_t r_projection = CVARD("r_projection", "0", "0: regular perspective.\n1: stereographic (aka: pannini).\n2: fisheye.\n3: panoramic.\n4: lambert azimuthal equal-area.");
cvar_t r_projection = CVARD("r_projection", "0", "0: regular perspective.\n1: stereographic (aka: pannini).\n2: fisheye.\n3: panoramic.\n4: lambert azimuthal equal-area.\n5: Equirectangular");
cvar_t ffov = CVARFD("ffov", "", 0, "Allows you to set a specific field of view for when a custom projection is specified. If empty, will use regular fov cvar, which might get messy.");
#if defined(_WIN32) && !defined(MINIMAL)
//amusing gimmick / easteregg.
@ -1156,7 +1156,7 @@ void V_ApplyAFov(playerview_t *pv)
//aproximate fov is our regular fov value. explicit is settable by gamecode for weird aspect ratios
if (!r_refdef.fov_x || !r_refdef.fov_y)
{
extern cvar_t r_stereo_method, r_stereo_separation;
extern cvar_t r_stereo_separation;
float ws;
float afov = r_refdef.afov;
@ -1169,13 +1169,13 @@ void V_ApplyAFov(playerview_t *pv)
afov = min(afov, 170);
ws = 1;
if (r_stereo_method.ival == 5 && r_stereo_separation.value)
if (r_refdef.stereomethod == STEREO_CROSSEYED && r_stereo_separation.value)
ws = 0.5;
//attempt to retain a classic fov
if (ws*r_refdef.vrect.width < (r_refdef.vrect.height*640)/432)
{
r_refdef.fov_y = CalcFov(afov, (ws*r_refdef.vrect.width*r_refdef.pxrect.width)/vid.width, (r_refdef.vrect.height*r_refdef.pxrect.height)/vid.height);
r_refdef.fov_y = CalcFov(afov, (ws*r_refdef.vrect.width*r_refdef.pxrect.width)/vid.fbvwidth, (r_refdef.vrect.height*r_refdef.pxrect.height)/vid.fbvheight);
r_refdef.fov_x = afov;//CalcFov(r_refdef.fov_y, 432, 640);
}
else
@ -1552,7 +1552,7 @@ static void SCR_VRectForPlayer(vrect_t *vrect, int pnum, unsigned maxseats)
case 3:
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL && vid.rotpixelwidth > vid.rotpixelheight * 2
&& r_projection.ival == 2 /*panoramic view always stacks player views*/
&& r_projection.ival == PROJ_PANORAMA /*panoramic view always stacks player views*/
)
{ //over twice as wide as high, assume dual moniter, horizontal.
vrect->width = vid.fbvwidth/cl.splitclients;
@ -1888,7 +1888,7 @@ void R_DrawNameTags(void)
{
char asciibuffer[8192];
char *entstr;
int buflen;
size_t buflen;
int x, y;
sprintf(asciibuffer, "entity %i ", e->entnum);

View file

@ -90,7 +90,7 @@ extern BOOL (STDAPICALLTYPE *pShell_NotifyIconW)(DWORD dwMessage, PNOTIFYICONDAT
#endif
extern HWND mainwindow;
extern qboolean ActiveApp, Minimized;
extern qboolean Minimized;
extern qboolean WinNT;

View file

@ -1876,9 +1876,9 @@ typedef struct {
qboolean allowcutdown;
qboolean cutdown;
char result[256];
char *desc;
const char *desc;
} match_t;
void Cmd_CompleteCheck(char *check, match_t *match, char *desc) //compare cumulative strings and join the result
void Cmd_CompleteCheck(char *check, match_t *match, const char *desc) //compare cumulative strings and join the result
{
if (*match->result)
{
@ -1907,7 +1907,7 @@ void Cmd_CompleteCheck(char *check, match_t *match, char *desc) //compare cumula
match->desc = desc;
}
}
char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, char **descptr)
char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr)
{
extern cvar_group_t *cvar_groups;
cmd_function_t *cmd;

View file

@ -95,7 +95,7 @@ char *Cmd_AliasExist(const char *name, int restrictionlevel);
char *Cmd_Describe (char *cmd_name);
char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, char **descptr);
char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens, int matchnum, const char **descptr);
qboolean Cmd_IsCommand (char *line);
// attempts to match a partial command for automatic command line completion
// returns NULL if nothing fits

View file

@ -521,7 +521,7 @@ const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *sourcedat
//a->ia->ir
if (bonecount > destbonecount || bonecount > MAX_BONES)
Sys_Error("Alias_ConvertBoneData: too many bones "fPRIzu">"fPRIzu"\n", bonecount, destbonecount);
Sys_Error("Alias_ConvertBoneData: too many bones %"PRIuSIZE">%"PRIuSIZE"\n", bonecount, destbonecount);
//r(->a)->ia(->ir)
if (desttype == SKEL_INVERSE_RELATIVE && sourcetype == SKEL_RELATIVE)
@ -3611,6 +3611,12 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
if (pinstverts[i].onseam)
{
if (pinstverts[i].onseam != 0x20 && !galias->warned)
{
Con_Printf(CON_WARNING "Model %s has an invalid seam flag, which may crash software-rendered engines\n", mod->name);
//1 == ALIAS_LEFT_CLIP
galias->warned = true;
}
st_array[j][0] = st_array[i][0]+0.5;
st_array[j][1] = st_array[i][1];
seamremap[i] = j;
@ -6613,7 +6619,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
}
if (h->filesize != fsize)
{
Con_Printf("%s: size (%u != "fPRIzu")\n", mod->name, h->filesize, fsize);
Con_Printf("%s: size (%u != %"PRIuSIZE")\n", mod->name, h->filesize, fsize);
return NULL;
}

View file

@ -1855,7 +1855,7 @@ void QDECL COM_StripExtension (const char *in, char *out, int outlen)
}
}
void COM_StripAllExtensions (char *in, char *out, int outlen)
void COM_StripAllExtensions (const char *in, char *out, int outlen)
{
char *s;
@ -1998,7 +1998,7 @@ void COM_FileBase (const char *in, char *out, int outlen)
COM_DefaultExtension
==================
*/
void COM_DefaultExtension (char *path, char *extension, int maxlen)
void COM_DefaultExtension (char *path, const char *extension, int maxlen)
{
char *src;
//
@ -2022,7 +2022,7 @@ void COM_DefaultExtension (char *path, char *extension, int maxlen)
//adds .ext only if it isn't already present (either case).
//extension *must* contain a leading . as this is really a requiresuffix rather than an actual extension
//returns false if truncated. will otherwise still succeed.
qboolean COM_RequireExtension(char *path, char *extension, int maxlen)
qboolean COM_RequireExtension(char *path, const char *extension, int maxlen)
{
qboolean okay = true;
int plen = strlen(path);

View file

@ -372,11 +372,11 @@ unsigned int unicode_charcount(const char *in, size_t buffersize, qboolean marku
char *COM_SkipPath (const char *pathname);
void QDECL COM_StripExtension (const char *in, char *out, int outlen);
void COM_StripAllExtensions (char *in, char *out, int outlen);
void COM_StripAllExtensions (const char *in, char *out, int outlen);
void COM_FileBase (const char *in, char *out, int outlen);
int QDECL COM_FileSize(const char *path);
void COM_DefaultExtension (char *path, char *extension, int maxlen);
qboolean COM_RequireExtension(char *path, char *extension, int maxlen);
void COM_DefaultExtension (char *path, const char *extension, int maxlen);
qboolean COM_RequireExtension(char *path, const char *extension, int maxlen);
char *COM_FileExtension (const char *in, char *result, size_t sizeofresult);
void COM_CleanUpPath(char *str);

View file

@ -1024,6 +1024,16 @@ void Cvar_SetValue (cvar_t *var, float value)
sprintf (val, "%g",value);
Cvar_Set (var, val);
}
void Cvar_ForceSetValue (cvar_t *var, float value)
{
char val[32];
// if (value == (int)value)
// sprintf (val, "%i",(int)value); //make it look nicer.
// else
sprintf (val, "%g",value);
Cvar_ForceSet (var, val);
}
void Cvar_Free(cvar_t *tbf)
{
@ -1190,8 +1200,9 @@ cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const c
var->flags = flags|CVAR_POINTER|CVAR_USERCREATED;
if (description)
{
var->description = var->name+strlen(var->name)+1;
strcpy(var->description, description);
char *desc = var->name+strlen(var->name)+1;
strcpy(desc, description);
var->description = desc;
}
if (!Cvar_Register(var, group))

View file

@ -70,7 +70,7 @@ typedef struct cvar_s
char *name2;
void (QDECL *callback) (struct cvar_s *var, char *oldvalue);
char *description;
const char *description;
char *enginevalue; //when changing manifest dir, the cvar will be reset to this value. never freed.
char *defaultstr; //this is the current mod's default value. set on first update.
@ -164,6 +164,7 @@ cvar_t *Cvar_ForceSet (cvar_t *var, const char *value);
cvar_t *Cvar_Set (cvar_t *var, const char *value);
// equivelant to "<name> <variable>" typed at the console
void Cvar_ForceSetValue (cvar_t *var, float value);
void Cvar_SetValue (cvar_t *var, float value);
// expands value to a string and calls Cvar_Set

View file

@ -4672,13 +4672,24 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
#ifdef ANDROID
{
//write a .nomedia file to avoid people from getting random explosion sounds etc interspersed with their music
vfsfile_t *f;
//write a .nomedia file to avoid people from getting random explosion sounds etc intersperced with their music
f = FS_OpenVFS(".nomedia", "rb", FS_ROOT);
char nomedia[MAX_OSPATH];
//figure out the path we're going to end up writing to
if (com_homepathenabled)
snprintf(nomedia, sizeof(nomedia), "%s%s", com_homepath, ".nomedia");
else
snprintf(nomedia, sizeof(nomedia), "%s%s", com_gamepath, ".nomedia");
//make sure it exists.
f = VFSOS_Open(nomedia, "rb");
if (!f) //don't truncate
{
COM_CreatePath(nomedia);
f = VFSOS_Open(nomedia, "wb");
}
if (f)
VFS_CLOSE(f);
else
FS_WriteFile(".nomedia", NULL, 0, FS_ROOT);
}
#endif

View file

@ -3399,12 +3399,12 @@ handshakeerror:
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+7]<< 0ull;
if (ullpaylen < 0x10000)
{
Con_Printf ("%s: payload size ("fPRIllu") encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
Con_Printf ("%s: payload size (%"PRIu64") encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
goto closesvstream;
}
if (ullpaylen > 0x10000)
{
Con_Printf ("%s: payload size ("fPRIllu") is abusive\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
Con_Printf ("%s: payload size (%"PRIu64") is abusive\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
goto closesvstream;
}
paylen = ullpaylen;

View file

@ -722,6 +722,7 @@ enum csqc_input_event
CSIE_ACCELEROMETER = 4, /*x, y, z*/
CSIE_FOCUS = 5, /*mouse, key, devid. if has, the game window has focus. (true/false/-1)*/
CSIE_JOYAXIS = 6, /*axis, value, devid*/
CSIE_GYROSCOPE = 7, /*x, y, z rotational acceleration*/
};
#ifdef TERRAIN

View file

@ -441,6 +441,13 @@ enum clcq2_ops_e
//==============================================
#define DLERR_FILENOTFOUND -1 //server cannot serve the file
#define DLERR_PERMISSIONS -2 //server refuses to serve the file
#define DLERR_UNKNOWN -3 //server bugged out while trying to serve the request
#define DLERR_REDIRECTFILE -4 //client should download the specified file instead.
#define DLERR_REDIRECTPACK -5 //client should download the specified package instead.
#define DLERR_PACKAGE -6 //not networked. packages require special file access.
//these flags are sent as part of the svc_precache index, for any-time precaches. using the upper two bits means we still have 16k available models/sounds/etc
#define PC_TYPE 0xc000
#define PC_MODEL 0x0000

View file

@ -127,12 +127,12 @@ qboolean Sys_ConditionSignal(void *condv); //lock first
qboolean Sys_ConditionBroadcast(void *condv); //lock first
void Sys_DestroyConditional(void *condv);
#else
#define Sys_IsMainThread() true
#define Sys_CreateMutex() NULL
#define Sys_LockMutex(m) true
#define Sys_UnlockMutex(m) true
#define Sys_IsMainThread() (true)
#define Sys_CreateMutex() (NULL)
#define Sys_LockMutex(m) (true)
#define Sys_UnlockMutex(m) (true)
#define Sys_DestroyMutex(m)
#define Sys_IsThread(t) !t
#define Sys_IsThread(t) (!t)
#endif
void Sys_Sleep(double seconds);

View file

@ -94,6 +94,9 @@ void TL_InitLanguages(char *newlangpath)
int i;
char *lang;
if (!newlangpath)
newlangpath = "";
Q_strncpyz(langpath, newlangpath, sizeof(langpath));
//lang can override any environment or system settings.

View file

@ -198,25 +198,25 @@ static qboolean D3D9AppActivate(BOOL fActive, BOOL minimize)
{
static BOOL sound_active;
if (ActiveApp == fActive && Minimized == minimize)
if (vid.activeapp == fActive && Minimized == minimize)
return false; //so windows doesn't crash us over and over again.
ActiveApp = fActive;
vid.activeapp = fActive;
Minimized = minimize;
// enable/disable sound on focus gain/loss
if (!ActiveApp && sound_active)
if (!vid.activeapp && sound_active)
{
S_BlockSound ();
sound_active = false;
}
else if (ActiveApp && !sound_active)
else if (vid.activeapp && !sound_active)
{
S_UnblockSound ();
sound_active = true;
}
INS_UpdateGrabs(modestate != MS_WINDOWED, ActiveApp);
INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp);
if (fActive)
{
@ -1094,7 +1094,7 @@ static void (D3D9_SCR_UpdateScreen) (void)
window_center_y = (window_rect.top + window_rect.bottom)/2;
INS_UpdateGrabs(modestate != MS_WINDOWED, ActiveApp);
INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp);
}

View file

@ -261,25 +261,25 @@ static qboolean D3D11AppActivate(BOOL fActive, BOOL minimize)
{
static BOOL sound_active;
if (ActiveApp == fActive && Minimized == minimize)
if (vid.activeapp == fActive && Minimized == minimize)
return false; //so windows doesn't crash us over and over again.
ActiveApp = fActive;
vid.activeapp = fActive;
Minimized = minimize;
// enable/disable sound on focus gain/loss
if (!ActiveApp && sound_active)
if (!vid.activeapp && sound_active)
{
S_BlockSound ();
sound_active = false;
}
else if (ActiveApp && !sound_active)
else if (vid.activeapp && !sound_active)
{
S_UnblockSound ();
sound_active = true;
}
INS_UpdateGrabs(modestate != MS_WINDOWED, ActiveApp);
INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp);
return true;
}
@ -557,7 +557,7 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
if (modestate == MS_FULLSCREEN)
{
IDXGISwapChain_SetFullscreenState(d3dswapchain, ActiveApp, d3dscreen);
IDXGISwapChain_SetFullscreenState(d3dswapchain, vid.activeapp, d3dscreen);
D3D11_DoResize();
}
Cvar_ForceCallback(&v_gamma);
@ -1356,7 +1356,7 @@ static void (D3D11_SCR_UpdateScreen) (void)
window_center_y = (window_rect.top + window_rect.bottom)/2;
INS_UpdateGrabs(modestate != MS_WINDOWED, ActiveApp);
INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp);
}

View file

@ -348,7 +348,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include,../d3d,../d3d9,../libs/dxsdk9/include"
PreprocessorDefinitions="_DEBUG;D3DQUAKE;WIN32;_WINDOWS;MULTITHREAD"
PreprocessorDefinitions="_DEBUG;D3D9QUAKE;D3D11QUAKE;WIN32;_WINDOWS;MULTITHREAD"
RuntimeLibrary="1"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
@ -663,7 +663,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include"
PreprocessorDefinitions="_DEBUG;GLQUAKE;WIN32;_WINDOWS;MULTITHREAD;BOTLIB_STATIC;USE_MSVCRT_DEBUG"
PreprocessorDefinitions="_DEBUG;GLQUAKE;WIN32;_WINDOWS;BOTLIB_STATIC;USE_MSVCRT_DEBUG"
BasicRuntimeChecks="3"
SmallerTypeCheck="true"
RuntimeLibrary="1"
@ -1179,7 +1179,7 @@
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include,../d3d,../d3d9,../libs/dxsdk9/include"
PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;GLQUAKE;D3DQUAKE;MULTITHREAD"
PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;GLQUAKE;D3D9QUAKE;D3D11QUAKE;MULTITHREAD"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
@ -1586,7 +1586,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include,../d3d,../d3d9,../libs/dxsdk9/include"
PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;GLQUAKE;D3DQUAKE;SWQUAKE;MULTITHREAD"
PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;GLQUAKE;D3D9QUAKE;D3D11QUAKE;SWQUAKE;MULTITHREAD"
RuntimeLibrary="1"
FloatingPointModel="2"
UsePrecompiledHeader="2"

View file

@ -37,10 +37,184 @@ public class FTEDroidActivity extends Activity
{
private SensorManager sensorman;
private Sensor sensoracc;
private Sensor sensorgyro;
private FTEView view;
float acc_x, acc_y, acc_z; /*might be some minor race condition on these*/
float gyro_x, gyro_y, gyro_z; /*might be some minor race condition on these*/
private String basedir, userdir;
private audiothreadclass audiothread;
private class audiothreadclass extends Thread
{
boolean timetodie;
int schannels;
int sspeed;
int sbits;
@Override
public void run()
{
byte[] audbuf = new byte[2048];
int avail;
AudioTrack at;
int chans;
try
{
if (schannels >= 8) //the OUT enumeration allows specific speaker control. but also api level 5+
chans = AudioFormat.CHANNEL_OUT_7POINT1;
else if (schannels >= 6)
chans = AudioFormat.CHANNEL_OUT_5POINT1;
else if (schannels >= 4)
chans = AudioFormat.CHANNEL_OUT_QUAD;
else if (schannels >= 2)
chans = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
else
chans = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int enc = (sbits == 8)?AudioFormat.ENCODING_PCM_8BIT:AudioFormat.ENCODING_PCM_16BIT;
int sz = 2*AudioTrack.getMinBufferSize(sspeed, chans, enc);
// if (sz < sspeed * 0.05)
// sz = sspeed * 0.05;
at = new AudioTrack(AudioManager.STREAM_MUSIC, sspeed, chans, enc, sz, AudioTrack.MODE_STREAM);
}
catch(IllegalArgumentException e)
{
//fixme: tell the engine that its bad and that it should configure some different audio attributes, instead of simply muting.
return;
}
at.setStereoVolume(1, 1);
at.play();
while(!timetodie)
{
avail = FTEDroidEngine.paintaudio(audbuf, audbuf.length);
at.write(audbuf, 0, avail);
}
at.stop();
}
public void killoff()
{
timetodie = true;
try
{
join();
}
catch(InterruptedException e)
{
}
timetodie = false;
}
};
private void audioInit(int sspeed, int schannels, int sbits)
{
if (audiothread == null)
{
audiothread = new audiothreadclass();
audiothread.schannels = schannels;
audiothread.sspeed = sspeed;
audiothread.sbits = sbits;
audiothread.start();
}
}
public void audioStop()
{
if (audiothread != null)
{
audiothread.killoff();
audiothread = null;
}
}
public void audioResume()
{
if (audiothread != null)
{
audiothread.killoff();
audiothread.start();
}
}
class FTEMultiTouchInputEvent extends FTELegacyInputEvent
{
/*Requires API level 5+ (android 2.0+)*/
private void domove(MotionEvent event)
{
final int pointerCount = event.getPointerCount();
int i;
for (i = 0; i < pointerCount; i++)
FTEDroidEngine.motion(0, event.getPointerId(i), event.getX(i), event.getY(i), event.getSize(i));
}
public boolean go(MotionEvent event)
{
int id;
float x, y, size;
final int act = event.getAction();
domove(event);
switch(act & event.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT);
x = event.getX(id);
y = event.getY(id);
size = event.getSize(id);
id = event.getPointerId(id);
FTEDroidEngine.motion(1, id, x, y, size);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT);
x = event.getX(id);
y = event.getY(id);
size = event.getSize(id);
id = event.getPointerId(id);
FTEDroidEngine.motion(2, id, x, y, size);
break;
case MotionEvent.ACTION_MOVE:
break;
default:
return false;
}
return true;
}
}
class FTELegacyInputEvent
{
public boolean go(MotionEvent event)
{
final int act = event.getAction();
final float x = event.getX();
final float y = event.getY();
final float size = event.getSize();
FTEDroidEngine.motion(0, 0, x, y, size);
switch(act)
{
case MotionEvent.ACTION_DOWN:
FTEDroidEngine.motion(1, 0, x, y, size);
break;
case MotionEvent.ACTION_UP:
FTEDroidEngine.motion(2, 0, x, y, size);
break;
case MotionEvent.ACTION_MOVE:
break;
default:
return false;
}
return true;
}
}
private class FTEEGLConfig implements GLSurfaceView.EGLConfigChooser
{
int version;
@ -176,8 +350,11 @@ public class FTEDroidActivity extends Activity
act = parent;
theview = view;
FTEDroidEngine.init(0, 0, 0, basedir, userdir);
inited = true;
if (!inited)
{
FTEDroidEngine.init(0, 0, 0, 0, 0, basedir, userdir);
inited = true;
}
cfgchooser = new FTEEGLConfig();
// theview.setEGLConfigChooser(cfgchooser);
@ -190,7 +367,7 @@ public class FTEDroidActivity extends Activity
if (inited == true)
{
int flags;
flags = FTEDroidEngine.frame(act.acc_x, act.acc_y, act.acc_z);
flags = FTEDroidEngine.frame(act.acc_x, act.acc_y, act.acc_z, act.gyro_x, act.gyro_y, act.gyro_z);
if (flags != notifiedflags)
{
if (((flags ^ notifiedflags) & 1) != 0)
@ -254,7 +431,7 @@ public class FTEDroidActivity extends Activity
inited = false;
if (errormsg == "")
if (errormsg.equals(""))
{
finish();
System.exit(0);
@ -287,7 +464,7 @@ public class FTEDroidActivity extends Activity
if (((flags ^ notifiedflags) & 16) != 0)
{
//16 means orientation cvar change
Runnable r = new Runnable()
Runnable r = new Runnable()
{
public void run()
{
@ -323,13 +500,44 @@ public class FTEDroidActivity extends Activity
}
};
act.runOnUiThread(r);
//fixme: move to proper vid_restart thing.
int wantver = FTEDroidEngine.getpreferedglesversion();
if (wantver != 0 && this.glesversion != 0 && wantver != this.glesversion)
{
inited = false;
wantver = FTEDroidEngine.getpreferedglesversion();
android.util.Log.i("FTEDroid", "Killing old gl state");
FTEDroidEngine.killglcontext();
android.util.Log.i("FTEDroid", "old gl state killed, queueing context kill");
r = new Runnable()
{
public void run()
{
android.util.Log.i("FTEDroid", "Attempting to restart view");
//create a new view and use that, because the desired gl context version might have changed
view = new FTEView(act);
setContentView(view);
}
};
act.runOnUiThread(r);
}
}
if (((flags ^ notifiedflags) & 32) != 0)
{
if ((flags & 32) != 0)
view.audioInit(FTEDroidEngine.audioinfo(0), FTEDroidEngine.audioinfo(1), FTEDroidEngine.audioinfo(2));
else
view.audioStop();
final int fl = flags;
Runnable r = new Runnable()
{
public void run()
{
if ((fl & 32) != 0)
act.audioInit(FTEDroidEngine.audioinfo(0), FTEDroidEngine.audioinfo(1), FTEDroidEngine.audioinfo(2));
else
act.audioStop();
}
};
act.runOnUiThread(r);
}
//clear anything which is an impulse
@ -341,10 +549,12 @@ public class FTEDroidActivity extends Activity
public void onSurfaceChanged(GL10 gl, int width, int height)
{
android.util.Log.i("FTEDroid", "Surface changed, now " + width + " by " + height + ".");
if (glesversion != 0)
if (glesversion != 0 && inited)
{
FTEDroidEngine.init(width, height, glesversion, basedir, userdir);
inited = true;
android.util.DisplayMetrics metrics = new android.util.DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
FTEDroidEngine.init(width, height, metrics.xdpi, metrics.ydpi, glesversion, basedir, userdir);
}
}
@Override
@ -357,101 +567,6 @@ public class FTEDroidActivity extends Activity
private class FTEView extends GLSurfaceView implements SensorEventListener
{
private final FTERenderer rndr;
private audiothreadclass audiothread;
private class audiothreadclass extends Thread
{
boolean timetodie;
int schannels;
int sspeed;
int sbits;
@Override
public void run()
{
byte[] audbuf = new byte[2048];
int avail;
AudioTrack at;
int chans;
try
{
if (schannels >= 8) //the OUT enumeration allows specific speaker control. but also api level 5+
chans = AudioFormat.CHANNEL_OUT_7POINT1;
else if (schannels >= 6)
chans = AudioFormat.CHANNEL_OUT_5POINT1;
else if (schannels >= 4)
chans = AudioFormat.CHANNEL_OUT_QUAD;
else if (schannels >= 2)
chans = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
else
chans = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int enc = (sbits == 8)?AudioFormat.ENCODING_PCM_8BIT:AudioFormat.ENCODING_PCM_16BIT;
int sz = 2*AudioTrack.getMinBufferSize(sspeed, chans, enc);
// if (sz < sspeed * 0.05)
// sz = sspeed * 0.05;
at = new AudioTrack(AudioManager.STREAM_MUSIC, sspeed, chans, enc, sz, AudioTrack.MODE_STREAM);
}
catch(IllegalArgumentException e)
{
//fixme: tell the engine that its bad and that it should configure some different audio attributes, instead of simply muting.
return;
}
at.setStereoVolume(1, 1);
at.play();
while(!timetodie)
{
avail = FTEDroidEngine.paintaudio(audbuf, audbuf.length);
at.write(audbuf, 0, avail);
}
at.stop();
}
public void killoff()
{
timetodie = true;
try
{
join();
}
catch(InterruptedException e)
{
}
timetodie = false;
}
};
private void audioInit(int sspeed, int schannels, int sbits)
{
if (audiothread == null)
{
audiothread = new audiothreadclass();
audiothread.schannels = schannels;
audiothread.sspeed = sspeed;
audiothread.sbits = sbits;
audiothread.start();
}
}
public void audioStop()
{
if (audiothread != null)
{
audiothread.killoff();
audiothread = null;
}
}
public void audioResume()
{
if (audiothread != null)
{
audiothread.killoff();
audiothread.start();
}
}
/* private FTEJoystickInputEvent joystickevent;
class FTEJoystickInputEvent
@ -479,80 +594,6 @@ public class FTEDroidActivity extends Activity
}
*/
private FTELegacyInputEvent inputevent;
class FTEMultiTouchInputEvent extends FTELegacyInputEvent
{
/*Requires API level 5+ (android 2.0+)*/
private void domove(MotionEvent event)
{
final int pointerCount = event.getPointerCount();
int i;
for (i = 0; i < pointerCount; i++)
FTEDroidEngine.motion(0, event.getPointerId(i), event.getX(i), event.getY(i), event.getSize(i));
}
public boolean go(MotionEvent event)
{
int id;
float x, y, size;
final int act = event.getAction();
domove(event);
switch(act & event.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT);
x = event.getX(id);
y = event.getY(id);
size = event.getSize(id);
id = event.getPointerId(id);
FTEDroidEngine.motion(1, id, x, y, size);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
id = ((act&event.ACTION_POINTER_ID_MASK) >> event.ACTION_POINTER_ID_SHIFT);
x = event.getX(id);
y = event.getY(id);
size = event.getSize(id);
id = event.getPointerId(id);
FTEDroidEngine.motion(2, id, x, y, size);
break;
case MotionEvent.ACTION_MOVE:
break;
default:
return false;
}
return true;
}
}
class FTELegacyInputEvent
{
public boolean go(MotionEvent event)
{
final int act = event.getAction();
final float x = event.getX();
final float y = event.getY();
final float size = event.getSize();
FTEDroidEngine.motion(0, 0, x, y, size);
switch(act)
{
case MotionEvent.ACTION_DOWN:
FTEDroidEngine.motion(1, 0, x, y, size);
break;
case MotionEvent.ACTION_UP:
FTEDroidEngine.motion(2, 0, x, y, size);
break;
case MotionEvent.ACTION_MOVE:
break;
default:
return false;
}
return true;
}
}
public FTEView(FTEDroidActivity context)
{
@ -713,9 +754,18 @@ public class FTEDroidActivity extends Activity
public void onSensorChanged(final SensorEvent event)
{
acc_x = event.values[0];
acc_y = event.values[1];
acc_z = event.values[2];
if (event.sensor == sensoracc)
{
acc_x = event.values[0];
acc_y = event.values[1];
acc_z = event.values[2];
}
else if (event.sensor == sensorgyro)
{
gyro_x = event.values[0];
gyro_y = event.values[1];
gyro_z = event.values[2];
}
}
}
@ -776,6 +826,8 @@ public class FTEDroidActivity extends Activity
{
android.util.Log.i("FTEDroid", "init accelerometer");
sensoracc = sensorman.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
android.util.Log.i("FTEDroid", "init gyro");
sensorgyro = sensorman.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
}
android.util.Log.i("FTEDroid", "done");
}
@ -786,8 +838,10 @@ public class FTEDroidActivity extends Activity
super.onResume();
if (sensorman != null && sensoracc != null)
sensorman.registerListener((SensorEventListener)view, sensoracc, SensorManager.SENSOR_DELAY_GAME);
if (sensorman != null && sensorgyro != null)
sensorman.registerListener((SensorEventListener)view, sensorgyro, SensorManager.SENSOR_DELAY_GAME);
view.audioResume();
audioResume();
}
@Override
@ -822,18 +876,18 @@ public class FTEDroidActivity extends Activity
@Override
protected void onStop()
{
if (sensorman != null && sensoracc != null)
if (sensorman != null && (sensoracc != null || sensorgyro != null))
sensorman.unregisterListener(view);
view.audioStop();
audioStop();
super.onStop();
}
@Override
protected void onPause()
{
if (sensorman != null && sensoracc != null)
if (sensorman != null && (sensoracc != null || sensorgyro != null))
sensorman.unregisterListener(view);
view.audioStop();
audioStop();
super.onPause();
}
}

View file

@ -2,8 +2,8 @@ package com.fteqw;
public class FTEDroidEngine
{
public static native void init(int w, int h, int gles2, String apkpath, String usrpath); /* init/reinit */
public static native int frame(float ax, float ay, float az);
public static native void init(int w, int h, float dpix, float dpiy, int gles2, String apkpath, String usrpath); /* init/reinit */
public static native int frame(float ax, float ay, float az, float gx, float gy, float gz);
public static native int openfile(String filename);
public static native int getvibrateduration(); //in ms
public static native int keypress(int down, int qkey, int unicode);
@ -13,6 +13,7 @@ public class FTEDroidEngine
public static native String geterrormessage();
public static native String getpreferedorientation();
public static native int getpreferedglesversion();
public static native void killglcontext();
public static native void newglcontext();
static

View file

@ -402,10 +402,33 @@ void R_SetupGL (float stereooffset)
if (!r_refdef.recurse)
{
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
newa[0] = r_refdef.viewangles[0];
newa[1] = r_refdef.viewangles[1];
newa[2] = r_refdef.viewangles[2] + gl_screenangle.value;
if (1)
{
vec3_t paxis[3];
AngleVectors (newa, paxis[0], paxis[1], paxis[2]);
VectorMA(r_origin, stereooffset, vright, r_origin);
//R_ConcatRotations(r_refdef.headaxis, paxis, vpn);
VectorMA(vec3_origin, r_refdef.headaxis[0][0], paxis[0], vpn);
VectorMA(vpn, r_refdef.headaxis[0][1], paxis[1], vpn);
VectorMA(vpn, r_refdef.headaxis[0][2], paxis[2], vpn);
VectorMA(vec3_origin, r_refdef.headaxis[1][0], paxis[0], vright);
VectorMA(vright, r_refdef.headaxis[1][1], paxis[1], vright);
VectorMA(vright, r_refdef.headaxis[1][2], paxis[2], vright);
VectorMA(vec3_origin, r_refdef.headaxis[2][0], paxis[0], vup);
VectorMA(vup, r_refdef.headaxis[2][1], paxis[1], vup);
VectorMA(vup, r_refdef.headaxis[2][2], paxis[2], vup);
}
else
AngleVectors (newa, vpn, vright, vup);
VectorMA(r_refdef.vieworg, stereooffset, vright, r_origin);
VectorAdd(r_origin, r_refdef.eyeoffset, r_origin);
//
// set up viewpoint
@ -457,10 +480,10 @@ void R_SetupGL (float stereooffset)
w = x2 - x;
h = y2 - y;
if (stereooffset && r_stereo_method.ival == 5)
if (stereooffset && r_refdef.stereomethod == STEREO_CROSSEYED)
{
w /= 2;
if (stereooffset > 0)
if (stereooffset < 0)
x += vid.fbpwidth/2;
}
@ -511,10 +534,7 @@ void R_SetupGL (float stereooffset)
Matrix4x4_CM_Orthographic(r_refdef.m_projection, -fov_x/2, fov_x/2, -fov_y/2, fov_y/2, gl_mindist.value, gl_maxdist.value>=1?gl_maxdist.value:9999);
}
newa[0] = r_refdef.viewangles[0];
newa[1] = r_refdef.viewangles[1];
newa[2] = r_refdef.viewangles[2] + gl_screenangle.value;
Matrix4x4_CM_ModelViewMatrix(r_refdef.m_view, newa, r_origin);
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_origin);
}
if (qglLoadMatrixf)
@ -584,15 +604,15 @@ void R_RenderScene (void)
int tmpvisents = cl_numvisedicts; /*world rendering is allowed to add additional ents, but we don't want to keep them for recursive views*/
int cull = r_refdef.flipcull;
stereomode = r_stereo_method.ival;
if (stereomode == 1)
stereomode = r_refdef.stereomethod;
if (stereomode == STEREO_QUAD)
{
#ifdef GL_STEREO
GLint glb;
qglGetIntegerv(GL_STEREO, &glb);
if (!glb || !qglDrawBuffer)
#endif
stereomode = 0; //we are not a stereo context, so no stereoscopic rendering (this encourages it to otherwise be left enabled, which means the user is more likely to spot that they asked it to give a slower context.
stereomode = STEREO_OFF; //we are not a stereo context, so no stereoscopic rendering (this encourages it to otherwise be left enabled, which means the user is more likely to spot that they asked it to give a slower context.
}
@ -600,12 +620,12 @@ void R_RenderScene (void)
{
stereooffset[0] = 0;
stereoframes = 1;
stereomode = 0;
stereomode = STEREO_OFF;
}
else
{
stereooffset[0] = -r_stereo_separation.value;
stereooffset[1] = r_stereo_separation.value;
stereooffset[0] = -0.5*r_stereo_separation.value;
stereooffset[1] = +0.5*r_stereo_separation.value;
stereoframes = 2;
}
@ -614,37 +634,46 @@ void R_RenderScene (void)
switch (stereomode)
{
default:
case 0: //off
case STEREO_OFF: //off
if (i)
return;
break;
#ifdef GL_STEREO
case 1: //proper gl stereo rendering
case STEREO_QUAD: //proper gl stereo rendering
if (stereooffset[i] < 0)
qglDrawBuffer(GL_BACK_LEFT);
else
qglDrawBuffer(GL_BACK_RIGHT);
break;
#endif
case 2: //red/cyan(green+blue)
case STEREO_RED_CYAN: //red/cyan(green+blue)
if (stereooffset[i] < 0)
qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
else
qglColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
break;
case 3: //red/blue
case STEREO_RED_BLUE: //red/blue
if (stereooffset[i] < 0)
qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
else
qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE);
break;
case 4: //red/green
case STEREO_RED_GREEN: //red/green
if (stereooffset[i] < 0)
qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
else
qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
break;
case 5: //eyestrain
case STEREO_CROSSEYED: //eyestrain
break;
case STEREO_LEFTONLY:
if (i != 0)
continue;
break;
case STEREO_RIGHTONLY:
if (i != 1)
continue;
//fixme: depth buffer doesn't need clearing
break;
}
if (i)
@ -683,21 +712,16 @@ void R_RenderScene (void)
switch (stereomode)
{
default:
case 0:
case STEREO_OFF:
case STEREO_LEFTONLY:
case STEREO_RIGHTONLY:
break;
case 1:
case STEREO_QUAD:
qglDrawBuffer(GL_BACK);
break;
case 3:
qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
qglClear(GL_COLOR_BUFFER_BIT);
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
break;
case 4:
qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
qglClear(GL_COLOR_BUFFER_BIT);
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
case 2:
case STEREO_RED_BLUE: //green should have already been cleared.
case STEREO_RED_GREEN: //blue should have already been cleared.
case STEREO_RED_CYAN:
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
break;
case 5:
@ -1397,6 +1421,7 @@ qboolean R_RenderScene_Cubemap(void)
{90, 0, 0}, {-90, 0, 0},
{0, 0, 0}, {0, -180, 0} };
vec3_t saveang;
vec3_t saveorg;
vrect_t vrect;
pxrect_t prect;
@ -1408,6 +1433,7 @@ qboolean R_RenderScene_Cubemap(void)
qboolean usefbo = true; //this appears to be a 20% speedup in my tests.
static fbostate_t fbostate; //FIXME
qboolean fboreset = false;
int osm = r_refdef.stereomethod;
/*needs glsl*/
if (!gl_config.arb_shader_objects)
@ -1423,7 +1449,7 @@ qboolean R_RenderScene_Cubemap(void)
{
default: //invalid.
return false;
case 1:
case PROJ_STEREOGRAPHIC:
shader = R_RegisterShader("postproc_stereographic", SUF_NONE,
"{\n"
"program postproc_stereographic\n"
@ -1443,7 +1469,7 @@ qboolean R_RenderScene_Cubemap(void)
facemask |= 1<<5; /*back view*/
}
break;
case 2:
case PROJ_FISHEYE:
shader = R_RegisterShader("postproc_fisheye", SUF_NONE,
"{\n"
"program postproc_fisheye\n"
@ -1460,7 +1486,7 @@ qboolean R_RenderScene_Cubemap(void)
if (ffov.value > 270)
facemask |= 1<<5; /*back view*/
break;
case 3:
case PROJ_PANORAMA:
shader = R_RegisterShader("postproc_panorama", SUF_NONE,
"{\n"
"program postproc_panorama\n"
@ -1480,7 +1506,7 @@ qboolean R_RenderScene_Cubemap(void)
}
facemask = 0x3f;
break;
case 4:
case PROJ_LAEA:
shader = R_RegisterShader("postproc_laea", SUF_NONE,
"{\n"
"program postproc_laea\n"
@ -1498,6 +1524,28 @@ qboolean R_RenderScene_Cubemap(void)
facemask |= 1<<5; /*back view*/
}
break;
case PROJ_EQUIRECTANGULAR:
shader = R_RegisterShader("postproc_equirectangular", SUF_NONE,
"{\n"
"program postproc_equirectangular\n"
"{\n"
"map $sourcecube\n"
"}\n"
"}\n"
);
facemask = 0x3f;
#if 0
facemask |= 1<<4; /*front view*/
if (ffov.value > 90)
{
facemask |= (1<<0) | (1<<1) | (1<<2) | (1<<3); /*side/top/bottom views*/
if (ffov.value > 270)
facemask |= 1<<5; /*back view*/
}
#endif
break;
}
//FIXME: we should be able to rotate the view
@ -1536,9 +1584,12 @@ qboolean R_RenderScene_Cubemap(void)
//FIXME: gl_max_size
VectorCopy(r_refdef.vieworg, saveorg);
VectorCopy(r_refdef.viewangles, saveang);
saveang[2] = 0;
r_refdef.stereomethod = STEREO_OFF;
if (!TEXVALID(scenepp_postproc_cube) || cmapsize != scenepp_postproc_cube_size)
{
if (!TEXVALID(scenepp_postproc_cube))
@ -1626,6 +1677,8 @@ qboolean R_RenderScene_Cubemap(void)
r_refdef.vrect = vrect;
r_refdef.pxrect = prect;
VectorCopy(saveorg, r_refdef.vieworg);
r_refdef.stereomethod = osm;
//GL_ViewportUpdate();
GL_Set2D(false);
@ -1639,7 +1692,12 @@ qboolean R_RenderScene_Cubemap(void)
qglLoadIdentity ();
*/
// draw it through the shader
if (r_projection.ival == 3)
if (r_projection.ival == PROJ_EQUIRECTANGULAR)
{
//note vr screenshots have requirements here
R2D_Image(vrect.x, vrect.y, vrect.width, vrect.height, 0, 1, 1, 0, shader);
}
else if (r_projection.ival == PROJ_PANORAMA)
{
float saspect = .5;
float taspect = vrect.height / vrect.width * ffov.value / 90;//(0.5 * vrect.width) / vrect.height;

View file

@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "glquake.h"
extern int sys_glesversion;
extern float sys_dpi_x;
extern float sys_dpi_y;
static dllhandle_t *sys_gl_module = NULL;
@ -77,6 +79,11 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
return false;
}
vid.dpi_x = sys_dpi_x;
vid.dpi_y = sys_dpi_y;
vid.activeapp = true;
GL_Init(GLES_GetSymbol);
return true;
}

View file

@ -513,7 +513,6 @@ static qboolean XI2_Init(void)
//qboolean is8bit = false;
//qboolean isPermedia = false;
qboolean ActiveApp = false;
extern qboolean sys_gracefulexit;
#define SYS_CLIPBOARD_SIZE 512
@ -1099,7 +1098,7 @@ static void GetEvent(void)
/*
if (fullscreenflags & FULLSCREEN_LEGACY)
if (fullscreenflags & FULLSCREEN_VMODE)
if (!ActiveApp)
if (!vid.activeapp)
{ //KDE doesn't seem to like us, in that you can't alt-tab back or click to activate.
//This allows us to steal input focus back from the window manager
x11.pXSetInputFocus(vid_dpy, vid_window, RevertToParent, CurrentTime);
@ -1144,7 +1143,7 @@ static void GetEvent(void)
case FocusIn:
//activeapp is if the game window is focused
ActiveApp = true;
vid.activeapp = true;
//but change modes to track the desktop window
// if (!(fullscreenflags & FULLSCREEN_ACTIVE) || event.xfocus.window != vid_decoywindow)
@ -1173,7 +1172,7 @@ static void GetEvent(void)
if (event.xfocus.window == mw || event.xfocus.window == vid_window)
{
ActiveApp = false;
vid.activeapp = false;
if (old_windowed_mouse)
{
Con_DPrintf("uninstall grabs\n");
@ -1336,9 +1335,9 @@ qboolean GLVID_ApplyGammaRamps(unsigned short *ramps)
if (ramps)
{
//hardwaregamma==1 skips hardware gamma when we're not fullscreen, in favour of software glsl based gamma.
// if (vid_hardwaregamma.value == 1 && !ActiveApp && !(fullscreenflags & FULLSCREEN_ACTIVE))
// if (vid_hardwaregamma.value == 1 && !vid.activeapp && !(fullscreenflags & FULLSCREEN_ACTIVE))
// return false;
// if (!ActiveApp)
// if (!vid.activeapp)
// return false;
// if (!vid_hardwaregamma.value)
// return false;
@ -1751,7 +1750,7 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl)
break; //erm
}
ActiveApp = false;
vid.activeapp = false;
if (fullscreenflags & FULLSCREEN_LEGACY)
{
vid_decoywindow = X_CreateWindow(false, visinfo, 640, 480, false);
@ -1977,7 +1976,7 @@ void Sys_SendKeyEvents(void)
return;
wantwindowed = !!_windowed_mouse.value;
if (!ActiveApp)
if (!vid.activeapp)
wantwindowed = false;
if (Key_MouseShouldBeFree() && !fullscreenflags)
wantwindowed = false;

View file

@ -1168,7 +1168,7 @@ static qboolean CreateMainWindow(rendererstate_t *info)
Win_Touch_Init(mainwindow);
INS_UpdateGrabs(info->fullscreen, ActiveApp);
INS_UpdateGrabs(info->fullscreen, vid.activeapp);
return stat;
}
@ -1816,7 +1816,7 @@ void GLVID_SwapBuffers (void)
// handle the mouse state when windowed if that's changed
INS_UpdateGrabs(modestate != MS_WINDOWED, ActiveApp);
INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp);
}
void OblitterateOldGamma(void)
@ -1843,7 +1843,7 @@ qboolean GLVID_ApplyGammaRamps (unsigned short *ramps)
if (vid_hardwaregamma.value == 1 && modestate == MS_WINDOWED)
return false; //don't do hardware gamma in windowed mode
if (ActiveApp && vid_hardwaregamma.value) //this is needed because ATI drivers don't work properly (or when task-switched out).
if (vid.activeapp && vid_hardwaregamma.value) //this is needed because ATI drivers don't work properly (or when task-switched out).
{
if (gammaworks)
{ //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck)
@ -2174,25 +2174,25 @@ qboolean GLAppActivate(BOOL fActive, BOOL minimize)
{
static BOOL sound_active;
if (ActiveApp == fActive && Minimized == minimize)
if (vid.activeapp == fActive && Minimized == minimize)
return false; //so windows doesn't crash us over and over again.
ActiveApp = fActive;// && (foregroundwindow==mainwindow);
vid.activeapp = fActive;// && (foregroundwindow==mainwindow);
Minimized = minimize;
// enable/disable sound on focus gain/loss
if (!ActiveApp && sound_active)
if (!vid.activeapp && sound_active)
{
S_BlockSound ();
sound_active = false;
}
else if (ActiveApp && !sound_active)
else if (vid.activeapp && !sound_active)
{
S_UnblockSound ();
sound_active = true;
}
INS_UpdateGrabs(modestate != MS_WINDOWED, ActiveApp);
INS_UpdateGrabs(modestate != MS_WINDOWED, vid.activeapp);
if (fActive)
{
@ -2657,7 +2657,7 @@ void VID_Init8bitPalette(void)
void GLVID_DeInit (void)
{
GLVID_Shutdown();
ActiveApp = false;
vid.activeapp = false;
Cvar_Unhook(&vid_vsync);
Cvar_Unhook(&vid_wndalpha);
@ -2710,7 +2710,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
if (isPlugin >= 2)
{
fprintf(stdout, "refocuswindow "fPRIp"\n", mainwindow);
fprintf(stdout, "refocuswindow %"PRIxPTR"\n", mainwindow);
fflush(stdout);
}

View file

@ -31,7 +31,6 @@ extern qboolean vid_isfullscreen;
unsigned short intitialgammaramps[3][256];
#endif
qboolean ActiveApp;
qboolean mouseactive;
extern qboolean mouseusedforgui;
@ -229,7 +228,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
return false;
}
#endif
ActiveApp = true;
vid.activeapp = true;
GL_Init(GLVID_getsdlglfunction);
@ -275,7 +274,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
void GLVID_DeInit (void)
{
ActiveApp = false;
vid.activeapp = false;
IN_DeactivateMouse();
@ -321,7 +320,7 @@ void GLVID_SwapBuffers (void)
}
else
{
if (!Key_MouseShouldBeFree() && ActiveApp)
if (!Key_MouseShouldBeFree() && vid.activeapp)
IN_ActivateMouse ();
else
IN_DeactivateMouse ();

View file

@ -417,7 +417,7 @@ void R_SaveRTLights_f(void);
void GLR_DoomWorld();
#endif
#ifdef MAP_PROC
qboolean D3_LoadMap_CollisionMap(model_t *mod, char *buf);
qboolean QDECL D3_LoadMap_CollisionMap(model_t *mod, char *buf, size_t bufsize);
unsigned char *D3_CalcVis(model_t *mod, vec3_t org);
void D3_GenerateAreas(model_t *mod);
#endif

View file

@ -1831,6 +1831,41 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"tc.y = -2.0*d.y/div;\n"
"tc.z = -(-1.0 + d.x*d.x + d.y*d.y)/div;\n"
"gl_FragColor = textureCube(s_t0, tc);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "postproc_equirectangular",
"!!cvarf ffov\n"
//equirectangular view rendering, commonly used for sphere->2d map projections.
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"varying vec2 texcoord;\n"
"void main()\n"
"{\n"
"texcoord = v_texcoord.xy;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform samplerCube s_t0;\n"
"varying vec2 texcoord;\n"
"uniform float cvar_ffov;\n"
"#define PI 3.1415926535897932384626433832795\n"
"void main()\n"
"{\n"
"vec3 tc;\n"
"float lng = (texcoord.x - 0.5) * PI * 2.0;\n"
"float lat = (texcoord.y) * PI * 1.0;\n"
"tc.z = cos(lng) * sin(lat); \n"
"tc.x = sin(lng) * sin(lat);\n"
"tc.y = cos(lat);\n"
"gl_FragColor = textureCube(s_t0, tc);\n"
"}\n"
"#endif\n"

View file

@ -279,6 +279,7 @@ It doesn't use persistant connections.
*/
#define COOKIECOOKIECOOKIE
#ifdef COOKIECOOKIECOOKIE
typedef struct cookie_s
{
struct cookie_s *next;
@ -293,6 +294,7 @@ cookie_t *cookies;
void Cookie_Feed(char *domain, int secure, char *name, char *value)
{
cookie_t **link, *c;
Sys_LockMutex(com_resourcemutex);
for(link = &cookies; c = *link; link = &(*link)->next)
{
if (!strcmp(c->domain, domain) && c->secure == secure && !strcmp(c->name, name))
@ -304,23 +306,25 @@ void Cookie_Feed(char *domain, int secure, char *name, char *value)
*link = c->next;
Z_Free(c);
}
if (!value || !*value)
if (value && *value)
{
// Con_Printf("Deleting cookie http%s://%s/ %s\n", secure?"s":"", domain, name);
//no new value, hurrah.
return;
// Con_Printf("Setting cookie http%s://%s/ %s=%s\n", secure?"s":"", domain, name, value);
c = Z_Malloc(sizeof(*c) + strlen(domain) + strlen(name) + strlen(value) + 3);
c->domain = (char*)(c+1);
strcpy(c->domain, domain);
c->secure = secure;
c->name = c->domain+strlen(c->domain)+1;
strcpy(c->name, name);
c->value = c->name+strlen(c->name)+1;
strcpy(c->value, value);
c->next = cookies;
cookies = c;
}
// Con_Printf("Setting cookie http%s://%s/ %s=%s\n", secure?"s":"", domain, name, value);
c = Z_Malloc(sizeof(*c) + strlen(domain) + strlen(name) + strlen(value) + 3);
c->domain = (char*)(c+1);
strcpy(c->domain, domain);
c->secure = secure;
c->name = c->domain+strlen(c->domain)+1;
strcpy(c->name, name);
c->value = c->name+strlen(c->name)+1;
strcpy(c->value, value);
c->next = cookies;
cookies = c;
else
{
// Con_Printf("Deleted cookie http%s://%s/ %s\n", secure?"s":"", domain, name);
}
Sys_UnlockMutex(com_resourcemutex);
}
//just removes all the cookies it can.
@ -359,7 +363,7 @@ void Cookie_Parse(char *domain, int secure, char *line, char *end)
*end = 0;
Cookie_Feed(domain, secure, line, e+1);
}
//outputs a complete http line: Cookie a=v1; b=v2\r\n
//outputs a complete http line: Cookie: a=v1; b=v2\r\n
void Cookie_Regurgitate(char *domain, int secure, char *buffer, size_t buffersize)
{
qboolean hascookies = false;
@ -367,6 +371,7 @@ void Cookie_Regurgitate(char *domain, int secure, char *buffer, size_t buffersiz
char *l = buffer;
buffersize -= 3; //\r\n\0
*buffer = 0;
Sys_LockMutex(com_resourcemutex);
for (c = cookies; c; c = c->next)
{
if (!strcmp(c->domain, domain) && c->secure == secure)
@ -401,6 +406,7 @@ void Cookie_Regurgitate(char *domain, int secure, char *buffer, size_t buffersiz
buffer += vlen;
}
}
Sys_UnlockMutex(com_resourcemutex);
if (hascookies)
strcpy(buffer, "\r\n");
@ -410,6 +416,7 @@ void Cookie_Regurgitate(char *domain, int secure, char *buffer, size_t buffersiz
// if (*l)
// Con_Printf("Sending cookie(s) to http%s://%s/ %s\n", secure?"s":"", domain, l);
}
#endif
struct http_dl_ctx_s {
// struct dl_download *dlctx;

View file

@ -1398,7 +1398,7 @@ static pbool PR_ExecRunWarning (pubprogfuncs_t *ppf, int xstatement, char *error
if (progfuncs->funcs.debug_trace == 0)
{
pr_xstatement = ShowStep(progfuncs, xstatement, error, false);
pr_xstatement = ShowStep(progfuncs, xstatement, string, false);
return true;
}
return false;

View file

@ -6465,10 +6465,11 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
QCC_FreeTemp(idx);
return QCC_PR_BuildRef(retbuf, REF_GLOBAL, QCC_MakeIntConst(arraysize), nullsref, type_integer, true);
}
else if (((t->type == ev_pointer && !arraysize) || t->type == ev_struct || t->type == ev_union) && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
else if (((t->type == ev_pointer && !arraysize) || (t->type == ev_field && (t->aux_type->type == ev_struct || t->aux_type->type == ev_union)) || t->type == ev_struct || t->type == ev_union) && (QCC_PR_CheckToken(".") || QCC_PR_CheckToken("->")))
{
char *tname;
unsigned int i;
pbool fld = t->type == ev_field;
if (!idx.cast && t->type == ev_pointer && !arraysize)
{
t = t->aux_type;
@ -6481,6 +6482,12 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
if (!t->size)
QCC_PR_ParseError(0, "%s was not defined yet", tname);
}
else if (fld)
{
t = t->aux_type;
if (!t->size)
QCC_PR_ParseError(0, "%s was not defined yet", tname);
}
else
QCC_PR_ParseError(0, "indirection in something that is not a struct or union", tname);
@ -6511,6 +6518,9 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
}
arraysize = t->params[i].arraysize;
t = t->params[i].type;
if (fld)
t = QCC_PR_FieldType(t);
}
else
break;
@ -7841,6 +7851,7 @@ QCC_sref_t QCC_RefToDef(QCC_ref_t *ref, pbool freetemps)
case REF_ARRAY:
if (ref->index.cast)
{
//FIXME: array reads of array[immediate+offset] should generate (array+immediate)[offset] instead.
//FIXME: this needs to be deprecated
const QCC_eval_t *idxeval = QCC_SRef_EvalConst(ref->index);
if (idxeval && (ref->index.cast->type == ev_float || ref->index.cast->type == ev_integer))

View file

@ -18,6 +18,9 @@ int QCC_PR_CheckCompConst(void);
pbool QCC_Include(char *filename);
void QCC_FreeDef(QCC_def_t *def);
#define MAXINCLUDEDIRS 8
char qccincludedir[MAXINCLUDEDIRS][256]; //the -src path, for #includes
char *compilingfile;
int pr_source_line;
@ -104,8 +107,33 @@ void QCC_PR_LexWhitespace (pbool inhibitpreprocessor);
qcc_includechunk_t *currentchunk;
void QCC_PR_CloseProcessor(void)
{
int i;
for (i = 0; i < MAXINCLUDEDIRS; i++)
*qccincludedir[i] = 0;
currentchunk = NULL;
}
void QCC_PR_AddIncludePath(char *newinc)
{
int i;
for (i = 0; i < MAXINCLUDEDIRS; i++)
{
if (!*qccincludedir[i])
{
QC_strlcpy(qccincludedir[i], newinc, sizeof(qccincludedir));
break;
}
if (!strcmp(qccincludedir[i], newinc))
break;
}
if (i == MAXINCLUDEDIRS)
{
if (!s_file)
QCC_PR_Warning(WARN_STRINGTOOLONG, "cmdline", 0, "Too many include dirs. Ignoring and hoping the stars align.");
else
QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Too many include dirs. Ignoring and hoping the stars align.");
}
}
void QCC_PR_IncludeChunkEx (char *data, pbool duplicate, char *filename, CompilerConstant_t *cnst)
{
qcc_includechunk_t *chunk = qccHunkAlloc(sizeof(qcc_includechunk_t));
@ -165,18 +193,11 @@ void QCC_PR_PrintNextLine (void)
printf ("\n");
}
extern char qccmsourcedir[];
//also meant to include it.
void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath, pbool verbose)
void QCC_Canonicalize(char *fullname, size_t fullnamesize, char *newfile, char *base)
{
char fullname[1024];
int doubledots;
char *end = fullname;
if (!*newfile)
return;
doubledots = 0;
/*count how far up we need to go*/
while(!strncmp(newfile, "../", 3) || !strncmp(newfile, "..\\", 3))
@ -185,25 +206,11 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath, pbool
doubledots++;
}
#if 0
currentfile += strlen(rootpath); //could this be bad?
strcpy(fullname, rootpath);
end = fullname+strlen(end);
if (*fullname && end[-1] != '/')
{
strcpy(end, "/");
end = end+strlen(end);
}
strcpy(end, currentfile);
end = end+strlen(end);
#else
if (currentfile)
strcpy(fullname, currentfile);
if (base)
strcpy(fullname, base);
else
*fullname = 0;
end = fullname+strlen(fullname);
#endif
while (end > fullname)
{
@ -227,6 +234,40 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath, pbool
}
strcpy(end, newfile);
}
extern char qccmsourcedir[];
//also meant to include it.
void QCC_FindBestInclude(char *newfile, char *currentfile, pbool verbose)
{
int includepath = 0;
char fullname[1024];
if (!*newfile)
return;
while(1)
{
if (includepath)
{
if (includepath > MAXINCLUDEDIRS || !*qccincludedir[includepath-1])
QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", newfile);
currentfile = qccincludedir[includepath-1];
}
QCC_Canonicalize(fullname, sizeof(fullname), newfile, currentfile);
{
extern progfuncs_t *qccprogfuncs;
if (qccprogfuncs->funcs.parms->FileSize(fullname) == -1)
{
includepath++;
continue;
}
}
break;
}
if (verbose)
{
@ -794,7 +835,7 @@ pbool QCC_PR_Precompiler(void)
break;
}
QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir, true);
QCC_FindBestInclude(pr_token, compilingfile, true);
if (*pr_file_p == '\r')
pr_file_p++;
@ -835,7 +876,7 @@ pbool QCC_PR_Precompiler(void)
}
msg[a] = 0;
QCC_FindBestInclude(msg, compilingfile, qccmsourcedir, false);
QCC_FindBestInclude(msg, compilingfile, false);
pr_file_p++;
@ -955,6 +996,22 @@ pbool QCC_PR_Precompiler(void)
{
ForcedCRC = atoi(msg);
}
else if (!QC_strcasecmp(qcc_token, "includedir"))
{
char newinc[1024];
int i;
QCC_COM_Parse(msg);
if (*qcc_token)
{
i = qcc_token[strlen(qcc_token)-1];
if (i != '/' && i != '\\')
QC_strlcat(qcc_token, "/", sizeof(qcc_token));
}
QCC_Canonicalize(newinc, sizeof(newinc), qcc_token, compilingfile);
QCC_PR_AddIncludePath(newinc);
}
else if (!QC_strcasecmp(qcc_token, "noref"))
defaultnoref = !!atoi(msg);
else if (!QC_strcasecmp(qcc_token, "nosave"))
@ -1110,50 +1167,11 @@ pbool QCC_PR_Precompiler(void)
{ //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
extern char destfile[1024];
char olddest[1024];
#ifndef QCCONLY
extern char qccmfilename[1024];
int p;
char *s, *s2;
#endif
Q_strlcpy(olddest, destfile, sizeof(olddest));
QCC_COM_Parse(msg);
#ifndef QCCONLY
p=0;
s2 = qcc_token;
if (!strncmp(s2, "./", 2))
s2+=2;
else
{
while(!strncmp(s2, "../", 3))
{
s2+=3;
p++;
}
}
strcpy(qccmfilename, qccmsourcedir);
for (s=qccmfilename+strlen(qccmfilename);p && s>=qccmfilename; s--)
{
if (*s == '/' || *s == '\\')
{
*(s+1) = '\0';
p--;
}
}
QC_snprintfz(destfile, sizeof(destfile), "%s", s2);
QCC_Canonicalize(destfile, sizeof(destfile), qcc_token, compilingfile);
while (p>0)
{
memmove(destfile+3, destfile, strlen(destfile)+1);
destfile[0] = '.';
destfile[1] = '.';
destfile[2] = '/';
p--;
}
#else
strcpy(destfile, qcc_token);
#endif
if (strcmp(destfile, olddest))
printf("Outputfile: %s\n", destfile);
}

View file

@ -3401,13 +3401,23 @@ static LRESULT CALLBACK OptionsWndProc(HWND hWnd,UINT message,
}
return 0;
}
static void AddTip(HWND tipwnd, HWND tool, char *message)
{
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = tool;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)tool;
toolInfo.lpszText = message;
SendMessage(tipwnd, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
}
void OptionsDialog(void)
{
char nicername[256], *us;
HWND subsection;
RECT r;
WNDCLASS wndclass;
HWND wnd;
HWND wnd, tipwnd;
int i;
int flagcolums=1;
@ -3486,6 +3496,10 @@ void OptionsDialog(void)
optionsmenu=CreateWindowEx(WS_EX_CONTEXTHELP, OPTIONS_WINDOW_CLASS_NAME, "Options - FTE QuakeC compiler", WS_CAPTION|WS_SYSMENU,
r.left, r.top, r.right-r.left, r.bottom-r.top, NULL, NULL, ghInstance, NULL);
tipwnd = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, optionsmenu, NULL, ghInstance, NULL);
SetWindowPos(tipwnd, HWND_TOPMOST,0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
subsection = CreateWindow("BUTTON", "Optimisations", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
0, 0, 400, height-40*4+24, optionsmenu, NULL, ghInstance, NULL);
@ -3518,51 +3532,59 @@ void OptionsDialog(void)
if (!fl_nondfltopts)
EnableWindow(wnd, FALSE);
AddTip(tipwnd, wnd, optimisations[i].description);
num++;
}
CreateWindow("BUTTON","O0",
wnd = CreateWindow("BUTTON","O0",
WS_CHILD | WS_VISIBLE,
8,height-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL0,
ghInstance,
NULL);
CreateWindow("BUTTON","O1",
AddTip(tipwnd, wnd, "Disable optimisations completely, giving code more similar to vanilla.");
wnd = CreateWindow("BUTTON","O1",
WS_CHILD | WS_VISIBLE,
8+64,height-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL1,
ghInstance,
NULL);
CreateWindow("BUTTON","O2",
AddTip(tipwnd, wnd, "Enable simple optimisations (primarily size). Probably still breaks decompilers.");
wnd = CreateWindow("BUTTON","O2",
WS_CHILD | WS_VISIBLE,
8+64*2,height-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL2,
ghInstance,
NULL);
CreateWindow("BUTTON","O3",
AddTip(tipwnd, wnd, "Enable most optimisations. Does not optimise anything that is likely to break any engines.");
wnd = CreateWindow("BUTTON","O3",
WS_CHILD | WS_VISIBLE,
8+64*3,height-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL3,
ghInstance,
NULL);
CreateWindow("BUTTON","Debug",
AddTip(tipwnd, wnd, "Enable unsafe optimisations. The extra optimisations may cause the progs to fail in certain cases, especially if used to compile addon modules.");
wnd = CreateWindow("BUTTON","Debug",
WS_CHILD | WS_VISIBLE,
8+64*4,height-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_DEBUG,
ghInstance,
NULL);
CreateWindow("BUTTON","Default",
AddTip(tipwnd, wnd, "Disable any optimisations that might interfere with debugging somehow.");
wnd = CreateWindow("BUTTON","Default",
WS_CHILD | WS_VISIBLE,
8+64*5,height-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_DEFAULT,
ghInstance,
NULL);
AddTip(tipwnd, wnd, "Default optimsations are aimed at increasing capacity without breaking debuggers or common decompilers (although gotos, switches, arrays, etc, will still result in issues).");
#ifdef EMBEDDEBUG
w_enginebinary = CreateWindowEx(WS_EX_CLIENTEDGE,
@ -3592,29 +3614,36 @@ void OptionsDialog(void)
(HMENU)IDI_O_ENGINECOMMANDLINE,
ghInstance,
NULL);
AddTip(tipwnd, w_enginebinary, "This is the engine that you wish to debug with.\nCurrently only FTEQW supports actual debugging, while specifying other engines here merely provides you with a quick way to start them up");
AddTip(tipwnd, w_enginebasedir, "This is your base directory (typically the directory your engine executable is in)");
AddTip(tipwnd, w_enginecommandline, "This is the commandline to use to invoke your mod.\nYou'll likely want -game here.\n-window is also handy.\n-nohome can be used to inhibit the use of home directories.\nYou may also want to add '+map start' or some such.");
#endif
CreateWindow("BUTTON","Apply",
wnd = CreateWindow("BUTTON","Apply",
WS_CHILD | WS_VISIBLE,
8,height-40,64,32,
optionsmenu,
(HMENU)IDI_O_APPLY,
ghInstance,
NULL);
CreateWindow("BUTTON","Save",
AddTip(tipwnd, wnd, "Use selected settings without saving them to disk.");
wnd = CreateWindow("BUTTON","Save",
WS_CHILD | WS_VISIBLE,
8+64,height-40,64,32,
optionsmenu,
(HMENU)IDI_O_APPLYSAVE,
ghInstance,
NULL);
CreateWindow("BUTTON","progs.src",
AddTip(tipwnd, wnd, "Use selected settings and save them to disk so that they're also used the next time you start fteqccgui.");
wnd = CreateWindow("BUTTON","progs.src",
WS_CHILD | WS_VISIBLE,
8+64*2,height-40,64,32,
optionsmenu,
(HMENU)IDI_O_CHANGE_PROGS_SRC,
ghInstance,
NULL);
AddTip(tipwnd, wnd, "Change the initial src file.");
@ -3631,6 +3660,7 @@ void OptionsDialog(void)
Button_SetCheck(wnd, 1);
else
Button_SetCheck(wnd, 0);
AddTip(tipwnd, wnd, "Compile for hexen2.\nThis changes the opcodes slightly, the progs crc, and enables some additional keywords.");
targitem_fte = wnd = CreateWindow("BUTTON","Extended Instructions",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
@ -3644,6 +3674,7 @@ void OptionsDialog(void)
Button_SetCheck(wnd, 1);
else
Button_SetCheck(wnd, 0);
AddTip(tipwnd, wnd, "Enables the use of additional opcodes, which only FTE supports at this time.\nThis gives both smaller and faster code, as well as allowing pointers, ints, and other extensions not possible with the vanilla QCVM.");
/* autohighlight_item = wnd = CreateWindow("BUTTON","Syntax Highlighting",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
@ -3690,6 +3721,7 @@ void OptionsDialog(void)
Button_SetCheck(wnd, 1);
else
Button_SetCheck(wnd, 0);
AddTip(tipwnd, wnd, compiler_flag[i].description);
}
CreateWindow("STATIC","Extra Parameters:",
@ -3708,6 +3740,7 @@ void OptionsDialog(void)
(HMENU)IDI_O_ADDITIONALPARAMETERS,
ghInstance,
NULL);
AddTip(tipwnd, extraparmsitem, "You can specify any additional commandline arguments here.\nAdd -DFOO=bar to define the FOO preprocessor constant as bar.");
ShowWindow(optionsmenu, SW_SHOWDEFAULT);
}
@ -4882,6 +4915,7 @@ void AddSourceFile(const char *parentpath, const char *filename)
{ //add a directory.
item.hParent = pi;
item.item.lParam = !slash; //lparam = false if we're only adding this node to get at a child.
item.item.state = ((*item.item.pszText!='.')?TVIS_EXPANDED:0); //directories with a leading . should not be expanded by default
pi = (HANDLE)SendMessage(projecttree,TVM_INSERTITEM,0,(LPARAM)&item);
item.hParent = pi;
}
@ -5142,11 +5176,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
}
else
{
if (mdibox)
{
buttons[ID_EDIT].washit = true;
}
else
if (!mdibox)
{
GUIprintf("Welcome to FTE QCC\n");
GUIprintf("Source file: ");

View file

@ -934,7 +934,52 @@ void QCC_UnmarshalLocals(void)
if (verbose)
printf("%i shared locals, %i private, %i total\n", biggest - onum, onum - eog, numpr_globals-eog);
}
static void QCC_GenerateFieldDefs(QCC_def_t *def, char *fieldname, int ofs, QCC_type_t *type)
{
string_t sname;
QCC_ddef32_t *dd;
if (type->type == ev_struct || type->type == ev_union)
{ //the qcvm cannot cope with struct fields. so we need to generate lots of fake ones.
char sub[256];
unsigned int p, a;
int parms = type->num_parms;
if (type->type == ev_union)
parms = 1; //unions only generate the first element. it simplifies things (should really just be the biggest).
for (p = 0; p < parms; p++)
{
if (type->params[p].arraysize)
{
for (a = 0; a < type->params[p].arraysize; a++)
{
QC_snprintfz(sub, sizeof(sub), "%s.%s[%u]", fieldname, type->params[p].paramname, a);
QCC_GenerateFieldDefs(def, sub, ofs + type->params[p].ofs + a * type->params[p].type->size, type->params[p].type);
}
}
else
{
QC_snprintfz(sub, sizeof(sub), "%s.%s", fieldname, type->params[p].paramname);
QCC_GenerateFieldDefs(def, sub, ofs + type->params[p].ofs, type->params[p].type);
}
}
return;
}
if (numfielddefs >= MAX_FIELDS)
QCC_PR_ParseError(0, "Too many fields. Limit is %u\n", MAX_FIELDS);
dd = &fields[numfielddefs];
numfielddefs++;
dd->type = type->type;
dd->s_name = sname = QCC_CopyString (fieldname);
dd->ofs = def->symboldata[ofs]._int;
if (numglobaldefs >= MAX_GLOBALS)
QCC_PR_ParseError(0, "Too many globals. Limit is %u\n", MAX_GLOBALS);
//and make sure that there's a global defined too, so field remapping isn't screwed.
dd = &qcc_globals[numglobaldefs];
numglobaldefs++;
dd->type = ev_field;
dd->ofs = ofs;
dd->s_name = sname;
}
CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def);
@ -1300,13 +1345,8 @@ pbool QCC_WriteData (int crc)
}
else if (def->type->type == ev_field && def->constant && (!def->scope || def->isstatic || def->initialized))
{
if (numfielddefs >= MAX_FIELDS)
QCC_PR_ParseError(0, "Too many fields. Limit is %u\n", MAX_FIELDS);
dd = &fields[numfielddefs];
numfielddefs++;
dd->type = def->type->aux_type->type;
dd->s_name = QCC_CopyString (def->name);
dd->ofs = def->symboldata[def->ofs]._int;
QCC_GenerateFieldDefs(def, def->name, def->ofs, def->type->aux_type);
continue;
}
else if ((def->scope||def->constant) && (def->type->type != ev_string || (strncmp(def->name, "dotranslate_", 12) && opt_constant_names_strings)))
{
@ -3167,6 +3207,14 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
memcpy(cnst->value, val, strlen(val)+1);
}
}
else if ( !strncmp(myargv[i], "-I", 2) )
{
name = myargv[i] + 2;
if (!*name && i+1<myargc)
name = myargv[++i];
QCC_PR_AddIncludePath(name);
}
//optimisations.
else if ( !strnicmp(myargv[i], "-O", 2) || !strnicmp(myargv[i], "/O", 2) )

View file

@ -1512,7 +1512,10 @@ void Q_InitProgs(void)
if (a)
{
as = strstr(a, "extraqwprogs=");
if (progstype == PROG_QW)
as = strstr(a, "extraqwprogs=");
else
as = strstr(a, "extraprogs=");
if (as)
{
for (a = as+13; *a; a++)
@ -1630,7 +1633,10 @@ void Q_InitProgs(void)
a = as = COM_LoadStackFile(va("maps/%s.inf", svs.name), addons, sizeof(addons), NULL);
if (a)
{
as = strstr(a, "qwprogs=");
if (progstype == PROG_QW)
as = strstr(a, "qwprogs=");
else
as = strstr(a, "progs=");
if (as)
{
for (a = as+11; *a; a++)
@ -10038,7 +10044,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"serverkey", PF_Fixme, 0, 0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string")},//
{"getentitytoken", PF_Fixme, 0, 0, 0, 355, D("string(optional string resetstring)", "Grab the next token in the map's entity lump.\nIf resetstring is not specified, the next token will be returned with no other sideeffects.\nIf empty, will reset from the map before returning the first token, probably {.\nIf not empty, will tokenize from that string instead.\nAlways returns tempstrings.")},//;
{"findfont", PF_Fixme, 0, 0, 0, 356, D("float(string s)", "Looks up a named font slot. Matches the actual font name as a last resort.")},//;
{"loadfont", PF_Fixme, 0, 0, 0, 357, D("float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset)", "too convoluted for me to even try to explain correct usage. Try drawfont = loadfont(\"foo\", \"cour\", \"16\", 0, 0, 0); to switch to the courier font, if you have the freetype2 library in windows..")},
{"loadfont", PF_Fixme, 0, 0, 0, 357, D("float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset)", "too convoluted for me to even try to explain correct usage. Try drawfont = loadfont(\"\", \"cour\", \"16\", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows..")},
{"sendevent", PF_Fixme, 0, 0, 0, 359, D("void(string evname, string evargs, ...)", "Invoke Cmd_evname_evargs in ssqc. evargs must be a string of initials refering to the types of the arguments to pass. v=vector, e=entity(.entnum field is sent), f=float, i=int. 6 arguments max - you can get more if you pack your floats into vectors.")},// (EXT_CSQC_1)
{"readbyte", PF_Fixme, 0, 0, 0, 360, "float()"},// (EXT_CSQC)
@ -11328,27 +11334,28 @@ void PR_DumpPlatform_f(void)
{"EF_DIMLIGHT", "const float", QW|NQ|CS, NULL, EF_DIMLIGHT},
{"EF_FLAG1", "const float", QW , NULL, QWEF_FLAG1},
{"EF_FLAG2", "const float", QW , NULL, QWEF_FLAG2},
{"EF_ADDITIVE", "const float", NQ|CS, NULL, NQEF_ADDITIVE},
{"EF_BLUE", "const float", QW|NQ|CS, NULL, EF_BLUE},
{"EF_RED", "const float", QW|NQ|CS, NULL, EF_RED},
{"EF_GREEN", "const float", QW|NQ|CS, NULL, EF_GREEN},
{"EF_FULLBRIGHT", "const float", QW|NQ|CS, NULL, EF_FULLBRIGHT},
{"EF_NOSHADOW", "const float", QW|NQ|CS, NULL, EF_NOSHADOW},
{"EF_NODEPTHTEST", "const float", QW|NQ|CS, NULL, EF_NODEPTHTEST},
{"EF_NODRAW", "const float", NQ|CS, NULL, NQEF_NODRAW},
{"EF_ADDITIVE", "const float", NQ|CS, "The entity will be drawn with an additive blend.", NQEF_ADDITIVE},
{"EF_BLUE", "const float", QW|NQ|CS, "A blue glow", EF_BLUE},
{"EF_RED", "const float", QW|NQ|CS, "A red glow", EF_RED},
{"EF_GREEN", "const float", QW|NQ|CS, "A green glow", EF_GREEN},
{"EF_FULLBRIGHT", "const float", QW|NQ|CS, "This entity will ignore lighting", EF_FULLBRIGHT},
{"EF_NOSHADOW", "const float", QW|NQ|CS, "This entity will not cast shadows", EF_NOSHADOW},
{"EF_NODEPTHTEST", "const float", QW|NQ|CS, "This entity will be drawn over the top of other things that are closer.", EF_NODEPTHTEST},
{"EF_NOMODELFLAGS", "const float", QW|NQ, "Surpresses the normal flags specified in the model.", EF_NOMODELFLAGS},
{"MF_ROCKET", "const float", QW|NQ|CS, NULL, EF_MF_ROCKET>>24},
{"MF_GRENADE", "const float", QW|NQ|CS, NULL, EF_MF_GRENADE>>24},
{"MF_GIB", "const float", QW|NQ|CS, NULL, EF_MF_GIB>>24},
{"MF_GIB", "const float", QW|NQ|CS, "Regular blood trail", EF_MF_GIB>>24},
{"MF_ROTATE", "const float", QW|NQ|CS, NULL, EF_MF_ROTATE>>24},
{"MF_TRACER", "const float", QW|NQ|CS, NULL, EF_MF_TRACER>>24},
{"MF_ZOMGIB", "const float", QW|NQ|CS, NULL, EF_MF_ZOMGIB>>24},
{"MF_TRACER2", "const float", QW|NQ|CS, NULL, EF_MF_TRACER2>>24},
{"MF_TRACER3", "const float", QW|NQ|CS, NULL, EF_MF_TRACER3>>24},
{"MF_TRACER", "const float", QW|NQ|CS, "AKA: green scrag trail", EF_MF_TRACER>>24},
{"MF_ZOMGIB", "const float", QW|NQ|CS, "Dark blood trail", EF_MF_ZOMGIB>>24},
{"MF_TRACER2", "const float", QW|NQ|CS, "AKA: hellknight projectile trail", EF_MF_TRACER2>>24},
{"MF_TRACER3", "const float", QW|NQ|CS, "AKA: purple vore trail", EF_MF_TRACER3>>24},
{"SL_ORG_TL", "const float", QW|NQ, NULL, SL_ORG_TL},
{"SL_ORG_TL", "const float", QW|NQ, "Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen", SL_ORG_TL},
{"SL_ORG_TR", "const float", QW|NQ, NULL, SL_ORG_TR},
{"SL_ORG_BL", "const float", QW|NQ, NULL, SL_ORG_BL},
{"SL_ORG_BR", "const float", QW|NQ, NULL, SL_ORG_BR},
@ -11464,6 +11471,7 @@ void PR_DumpPlatform_f(void)
{"IE_ACCELEROMETER", "const float", CS, NULL, CSIE_ACCELEROMETER},
{"IE_FOCUS", "const float", CS, "Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged.", CSIE_FOCUS},
{"IE_JOYAXIS", "const float", CS, "Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller.", CSIE_JOYAXIS},
{"IE_GYROSCOPE", "const float", CS, NULL, CSIE_GYROSCOPE},
{"CLIENTTYPE_DISCONNECTED","const float", QW|NQ, "Return value from clienttype() builtin. This entity is a player slot that is currently empty.", CLIENTTYPE_DISCONNECTED},
{"CLIENTTYPE_REAL", "const float", QW|NQ, "This is a real player, and not a bot.", CLIENTTYPE_REAL},

View file

@ -1527,19 +1527,19 @@ static qintptr_t QVM_uri_query (void *offset, quintptr_t mask, const qintptr_t *
if (!pr_enable_uriget.ival)
{
Con_Printf("QVM_uri_query(\"%s\","fPRIp"): %s disabled\n", url, cb_context, pr_enable_uriget.name);
Con_Printf("QVM_uri_query(\"%s\",%"PRIxPTR"): %s disabled\n", url, (qintptr_t)cb_context, pr_enable_uriget.name);
return 0;
}
if (mimetype && *mimetype)
{
VALIDATEPOINTER(arg[4],datasize);
Con_DPrintf("QVM_uri_query(%s,"fPRIp")\n", url, cb_context);
Con_DPrintf("QVM_uri_query(%s,%"PRIxPTR")\n", url, (qintptr_t)cb_context);
dl = HTTP_CL_Put(url, mimetype, data, datasize, QVM_uri_query_callback);
}
else
{
Con_DPrintf("QVM_uri_query(%s,"fPRIp")\n", url, cb_context);
Con_DPrintf("QVM_uri_query(%s,%"PRIxPTR")\n", url, (qintptr_t)cb_context);
dl = HTTP_CL_Get(url, NULL, QVM_uri_query_callback);
}
if (dl)
@ -1751,26 +1751,25 @@ static qintptr_t QVM_Map_Extension (void *offset, quintptr_t mask, const qintptr
}
//============== general Quake services ==================
#if FTE_WORDSIZE == 32 && !defined(NACL)
static int syscallqvm (void *offset, quintptr_t mask, int fn, const int *arg)
{
if (fn >= countof(traps))
return QVM_NotYetImplemented(offset, mask, arg);
return traps[fn](offset, mask, arg);
if (sizeof(int) == sizeof(qintptr_t))
{ //should allow the slow copy below to be optimised out
if (fn >= countof(traps))
return QVM_NotYetImplemented(offset, mask, (qintptr_t*)arg);
return traps[fn](offset, mask, (qintptr_t*)arg);
}
else
{
qintptr_t args[13];
int i;
for (i = 0; i < 13; i++)
args[i] = arg[i];
if (fn >= countof(traps))
return QVM_NotYetImplemented(offset, mask, args);
return traps[fn](offset, mask, args);
}
}
#else
static int syscallqvm (void *offset, quintptr_t mask, int fn, const int *arg)
{
qintptr_t args[13];
int i;
for (i = 0; i < 13; i++)
args[i] = arg[i];
if (fn >= countof(traps))
return QVM_NotYetImplemented(offset, mask, args);
return traps[fn](offset, mask, args);
}
#endif
static qintptr_t EXPORT_FN syscallnative (qintptr_t arg, ...)
{

View file

@ -1257,7 +1257,7 @@ void SV_Savegame (const char *savename, qboolean mapchange)
rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
if (rgbbuffer)
{
SCR_ScreenShot(savefilename, FS_GAMEONLY, rgbbuffer, width, height, fmt);
SCR_ScreenShot(savefilename, FS_GAMEONLY, &rgbbuffer, 1, width, height, fmt);
BZ_Free(rgbbuffer);
@ -1307,6 +1307,7 @@ void SV_Savegame_f (void)
cvar_t sv_autosave = CVARD("sv_autosave", "1", "Interval for autosaves, in minutes.");
void SV_AutoSave(void)
{
#ifndef NOBUILTINMENUS
#ifndef SERVERONLY
const char *autosavename;
int i;
@ -1342,11 +1343,12 @@ void SV_AutoSave(void)
}
autosavename = M_ChooseAutoSave();
Con_Printf("Autosaving to %s\n", autosavename);
Con_DPrintf("Autosaving to %s\n", autosavename);
SV_Savegame(autosavename, false);
sv.autosave_time = sv.time + sv_autosave.value * 60;
#endif
#endif
}
void SV_Loadgame_f (void)

View file

@ -291,12 +291,18 @@ SV_Give_f
*/
static void SV_Give_f (void)
{
char *t;
char *t = Cmd_Argv(2);
int v;
if (!svprogfuncs)
return;
if (!strcmp(t, "damn"))
{
Con_TPrintf ("%s not given.\n", t);
return;
}
if (!SV_MayCheat())
{
Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n");
@ -319,7 +325,6 @@ static void SV_Give_f (void)
SV_LogPlayer(host_client, "give cheat");
t = Cmd_Argv(2);
v = atoi (Cmd_Argv(3));
switch ((t[1]==0)?t[0]:0)
@ -1259,7 +1264,7 @@ static void SV_BanList_f (void)
{
*middlebit = 0;
if (nb->expiretime)
Q_strncatz(middlebit, va(",\t+"fPRIllu, (unsigned long long)nb->expiretime - bantime), sizeof(middlebit));
Q_strncatz(middlebit, va(",\t+%"PRIu64, (unsigned long long)nb->expiretime - bantime), sizeof(middlebit));
if (nb->reason[0])
Q_strncatz(middlebit, ",\t", sizeof(middlebit));
Con_Printf("%s%s%s\n", NET_AdrToStringMasked(adr, sizeof(adr), &nb->adr, &nb->adrmask), middlebit, nb->reason);
@ -1297,7 +1302,7 @@ static void SV_FilterList_f (void)
if (nb->expiretime)
{
time_t secs = nb->expiretime - curtime;
Con_Printf("%s %s +"fPRIllu":%02u\n", NET_AdrToStringMasked(adr, sizeof(adr), &nb->adr, &nb->adrmask), banflagtext, (unsigned long long)(secs/60), (unsigned int)(secs%60));
Con_Printf("%s %s +%"PRIu64":%02u\n", NET_AdrToStringMasked(adr, sizeof(adr), &nb->adr, &nb->adrmask), banflagtext, (unsigned long long)(secs/60), (unsigned int)(secs%60));
}
else
Con_Printf("%s %s\n", NET_AdrToStringMasked(adr, sizeof(adr), &nb->adr, &nb->adrmask), banflagtext);
@ -1482,9 +1487,9 @@ static void SV_WriteIP_f (void)
}
}
if (bi->reason[0])
s = va("addip %s %s "fPRIllu" \"%s\"\n", NET_AdrToStringMasked(adr, sizeof(adr), &bi->adr, &bi->adrmask), banflagtext, (unsigned long long) bi->expiretime, bi->reason);
s = va("addip %s %s %"PRIu64" \"%s\"\n", NET_AdrToStringMasked(adr, sizeof(adr), &bi->adr, &bi->adrmask), banflagtext, (unsigned long long) bi->expiretime, bi->reason);
else if (bi->expiretime)
s = va("addip %s %s "fPRIllu"\n", NET_AdrToStringMasked(adr, sizeof(adr), &bi->adr, &bi->adrmask), banflagtext, (unsigned long long) bi->expiretime);
s = va("addip %s %s %"PRIu64"\n", NET_AdrToStringMasked(adr, sizeof(adr), &bi->adr, &bi->adrmask), banflagtext, (unsigned long long) bi->expiretime);
else
s = va("addip %s %s\n", NET_AdrToStringMasked(adr, sizeof(adr), &bi->adr, &bi->adrmask), banflagtext);
VFS_WRITE(f, s, strlen(s));
@ -2713,7 +2718,7 @@ void SV_MemInfo_f(void)
csfr = sizeof(*cl->csqcentversions) * cl->max_net_ents;
Con_Printf(fPRIzu" minping=%i frame=%i, csqc=%i\n", sizeof(svs.clients[i]), sz, fr, csfr);
Con_Printf("%"PRIuSIZE" minping=%i frame=%i, csqc=%i\n", sizeof(svs.clients[i]), sz, fr, csfr);
}
}

View file

@ -226,9 +226,11 @@ void MSV_MapCluster_f(void)
Q_strncpyz(sv.modelname, "start", sizeof(sv.modelname));
if (atoi(Cmd_Argv(2)))
{
#ifdef SQL
Con_Printf("Opening database \"%s\"\n", sqlparams[3]);
sv.logindatabase = SQL_NewServer("sqlite", sqlparams);
if (sv.logindatabase == -1)
#endif
{
SV_UnspawnServer();
Con_Printf("Unable to open account database\n");
@ -934,13 +936,14 @@ struct logininfo_s
char guid[64];
char name[64];
};
#endif
qboolean SV_IgnoreSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof)
{
return false;
}
#endif
void MSV_UpdatePlayerStats(unsigned int playerid, unsigned int serverid, int numstats, float *stats)
{
#ifdef SQL
queryrequest_t *req;
sqlserver_t *srv;
static char hex[16] = "0123456789abcdef";
@ -961,6 +964,7 @@ void MSV_UpdatePlayerStats(unsigned int playerid, unsigned int serverid, int num
if (srv)
SQL_NewQuery(srv, SV_IgnoreSQLResult, sql, &req);
}
#endif
}
qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serverid, unsigned int playerid, char *playername, char *clientguid, netadr_t *clientaddr, void *statsblob, size_t statsblobsize)
@ -1023,6 +1027,7 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv
return false;
}
#ifdef SQL
qboolean MSV_ClusterLoginSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof)
{
sqlserver_t *sql = SQL_GetServer(req->srvid, true);
@ -1061,16 +1066,12 @@ qboolean MSV_ClusterLoginSQLResult(queryrequest_t *req, int firstrow, int numrow
pendinglookups--;
return false;
}
#endif
//returns true to block entry to this server.
extern int nextuserid;
qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize)
{
char escname[64], escpasswd[64];
sqlserver_t *sql;
queryrequest_t *req;
struct logininfo_s *info;
if (sv.state != ss_clustermode)
return false;
@ -1080,8 +1081,13 @@ qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize)
return false;
}*/
#ifdef SQL
if (sv.logindatabase != -1)
{
char escname[64], escpasswd[64];
struct logininfo_s *info;
sqlserver_t *sql;
queryrequest_t *req;
if (pendinglookups > 10)
return true;
sql = SQL_GetServer(sv.logindatabase, false);
@ -1097,7 +1103,9 @@ qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize)
info->clientaddr = net_from;
}
}
/* else if (0)
else
#endif
/* if (0)
{
char tmpbuf[256];
netadr_t redir;
@ -1107,8 +1115,8 @@ qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize)
return false;
}
return true;
}*/
else
}
else*/
MSV_ClusterLoginReply(NULL, 0, ++nextuserid, Info_ValueForKey(userinfo, "name"), guid, &net_from, NULL, 0);
return true;
}

View file

@ -88,6 +88,7 @@ cvar_t allow_download_packages = CVARD("allow_download_packages", "1", "if 1, p
cvar_t allow_download_refpackages = CVARD("allow_download_refpackages", "1", "If set to 1, packages that contain files needed during spawn functions will be become 'referenced' and automatically downloaded to clients.\nThis cvar should probably not be set if you have large packages that provide replacement pickup models on public servers.\nThe path command will show a '(ref)' tag next to packages which clients will automatically attempt to download.");
cvar_t allow_download_wads = CVARD("allow_download_wads", "1", "0 blocks downloading of any file in the wads/ directory, or is in the root directory with the extension .wad");
cvar_t allow_download_configs = CVARD("allow_download_configs", "0", "1 allows downloading of config files, either with the extension .cfg or in the subdir configs/.\n"CON_ERROR"THIS IS DANGEROUS AS IT CAN ALLOW PEOPLE TO READ YOUR RCON PASSWORD.");
cvar_t allow_download_locs = CVARD("allow_download_locs", "1", "0 blocks downloading of any file in the locs/ directory");
cvar_t allow_download_copyrighted = CVARD("allow_download_copyrighted", "0", "0 blocks download of packages that are considered copyrighted. Specifically, this means packages with a leading 'pak' prefix on the filename.\nIf you take your copyrights seriously, you should also set allow_download_pakmaps 0 and allow_download_pakcontents 0.");
cvar_t allow_download_other = CVARD("allow_download_other", "0", "0 blocks downloading of any file that was not covered by any of the directory download blocks.");
@ -4777,6 +4778,7 @@ void SV_InitLocal (void)
Cvar_Register (&allow_download_pakcontents, cvargroup_serverpermissions);
Cvar_Register (&allow_download_textures,cvargroup_serverpermissions);
Cvar_Register (&allow_download_configs, cvargroup_serverpermissions);
Cvar_Register (&allow_download_locs, cvargroup_serverpermissions);
Cvar_Register (&allow_download_packages,cvargroup_serverpermissions);
Cvar_Register (&allow_download_refpackages,cvargroup_serverpermissions);
Cvar_Register (&allow_download_wads, cvargroup_serverpermissions);
@ -4819,8 +4821,10 @@ void SV_InitLocal (void)
Cmd_AddCommand ("openroute", SV_OpenRoute_f);
#ifndef NOBUILTINMENUS
#ifndef SERVERONLY
Cvar_Register(&sv_autosave, cvargroup_servercontrol);
#endif
#endif
Cmd_AddCommand ("savegame_legacy", SV_LegacySavegame_f);
Cmd_AddCommand ("savegame", SV_Savegame_f);

View file

@ -868,164 +868,6 @@ void Sys_ServerActivity(void)
{
}
#ifdef MULTITHREAD
/* Thread creation calls */
typedef void *(*pfunction_t)(void *);
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
pthread_t *thread;
pthread_attr_t attr;
thread = (pthread_t *)malloc(sizeof(pthread_t));
if (!thread)
return NULL;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (stacksize < PTHREAD_STACK_MIN)
stacksize = PTHREAD_STACK_MIN;
pthread_attr_setstacksize(&attr, stacksize);
if (pthread_create(thread, &attr, (pfunction_t)func, args))
{
free(thread);
thread = NULL;
}
pthread_attr_destroy(&attr);
return (void *)thread;
}
void Sys_WaitOnThread(void *thread)
{
pthread_join((pthread_t *)thread, NULL);
free(thread);
}
/* Mutex calls */
void *Sys_CreateMutex(void)
{
pthread_mutex_t *mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
if (mutex && !pthread_mutex_init(mutex, NULL))
return mutex;
return NULL;
}
qboolean Sys_TryLockMutex(void *mutex)
{
return !pthread_mutex_trylock(mutex);
}
qboolean Sys_LockMutex(void *mutex)
{
return !pthread_mutex_lock(mutex);
}
qboolean Sys_UnlockMutex(void *mutex)
{
return !pthread_mutex_unlock(mutex);
}
void Sys_DestroyMutex(void *mutex)
{
pthread_mutex_destroy(mutex);
free(mutex);
}
/* Conditional wait calls */
typedef struct condvar_s
{
//FIXME: these should not be pointers.
pthread_mutex_t *mutex;
pthread_cond_t *cond;
} condvar_t;
void *Sys_CreateConditional(void)
{
condvar_t *condv;
pthread_mutex_t *mutex;
pthread_cond_t *cond;
condv = (condvar_t *)malloc(sizeof(condvar_t));
if (!condv)
return NULL;
mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
if (!mutex)
return NULL;
cond = (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
if (!cond)
return NULL;
if (!pthread_mutex_init(mutex, NULL))
{
if (!pthread_cond_init(cond, NULL))
{
condv->cond = cond;
condv->mutex = mutex;
return (void *)condv;
}
else
pthread_mutex_destroy(mutex);
}
free(cond);
free(mutex);
free(condv);
return NULL;
}
qboolean Sys_LockConditional(void *condv)
{
return !pthread_mutex_lock(((condvar_t *)condv)->mutex);
}
qboolean Sys_UnlockConditional(void *condv)
{
return !pthread_mutex_unlock(((condvar_t *)condv)->mutex);
}
qboolean Sys_ConditionWait(void *condv)
{
return !pthread_cond_wait(((condvar_t *)condv)->cond, ((condvar_t *)condv)->mutex);
}
qboolean Sys_ConditionSignal(void *condv)
{
return !pthread_cond_signal(((condvar_t *)condv)->cond);
}
qboolean Sys_ConditionBroadcast(void *condv)
{
return !pthread_cond_broadcast(((condvar_t *)condv)->cond);
}
void Sys_DestroyConditional(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
pthread_cond_destroy(cv->cond);
pthread_mutex_destroy(cv->mutex);
free(cv->cond);
free(cv->mutex);
free(cv);
}
#endif
void Sys_Sleep (double seconds)
{
struct timespec ts;
ts.tv_sec = (time_t)seconds;
seconds -= ts.tv_sec;
ts.tv_nsec = seconds * 1000000000.0;
nanosleep(&ts, NULL);
}
qboolean Sys_RandomBytes(qbyte *string, int len)
{
qboolean res;

View file

@ -2629,6 +2629,7 @@ qboolean SV_AllowDownload (const char *name)
extern cvar_t allow_download_root;
extern cvar_t allow_download_logs;
extern cvar_t allow_download_configs;
extern cvar_t allow_download_locs;
extern cvar_t allow_download_copyrighted;
extern cvar_t allow_download_other;
char cleanname[MAX_QPATH];
@ -2700,9 +2701,12 @@ qboolean SV_AllowDownload (const char *name)
if (strncmp(name, "textures/", 9) == 0)
return !!allow_download_textures.value;
if (strncmp(name, "config/", 9) == 0)
if (strncmp(name, "config/", 7) == 0)
return !!allow_download_configs.value;
if (strncmp(name, "locs/", 5) == 0)
return !!allow_download_locs.value;
//wads
if (strncmp(name, "wads/", 5) == 0)
return !!allow_download_wads.value;
@ -2739,6 +2743,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
extern cvar_t sv_demoDir;
qboolean protectedpak;
qboolean found;
static char tmpname[MAX_QPATH];
if (replacementname)
*replacementname = NULL;
@ -2765,19 +2770,22 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
return -1; //not found
}
name = *replacementname = va("demos/%s", mvdname);
return -4;
return DLERR_REDIRECTFILE;
}
}
if (!SV_AllowDownload(name))
{
Sys_Printf ("%s denied download of %s due to path/name rules\n", host_client->name, name);
return -2; //not permitted (even if it exists).
return DLERR_PERMISSIONS; //not permitted (even if it exists).
}
//mvdsv demo downloading support. demos/ -> demodir (sets up the server paths)
if (!strncmp(name, "demos/", 6))
name = va("%s/%s", sv_demoDir.string, name+6);
{
Q_snprintfz(tmpname, sizeof(tmpname), "%s/%s", sv_demoDir.string, name+6);
name = tmpname;
}
if (!strncmp(name, "package/", 8))
{
@ -2786,10 +2794,10 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
{
loc->len = VFS_GETLEN(f);
VFS_CLOSE(f);
return -5; //found package
return DLERR_PACKAGE; //found package
}
else
return -1; //not found/unable to open
return DLERR_FILENOTFOUND; //not found/unable to open
}
#ifdef TERRAIN
else if (Terrain_LocateSection(name, loc))
@ -2800,37 +2808,44 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
else
found = FS_FLocateFile(name, FSLF_IFFOUND, loc);
//nexuiz names certain files as .wav but they're really .ogg on disk.
if (!found && replacementname)
{
char ext[8];
if (!strcmp(COM_FileExtension(name, ext, sizeof(ext)), "wav"))
{
char tryogg[MAX_QPATH];
COM_StripExtension(name, tryogg, sizeof(tryogg));
COM_DefaultExtension(tryogg, ".ogg", sizeof(tryogg));
size_t alt;
static const char *alternatives[][4] = {
//orig-path, orig-ext, new-path, new-ext
//nexuiz qc names [sound/]sound/foo.wav but expects sound/foo.ogg and variations of that (the [sound/] is implied, but ignored)
{"", "", ".wav", ".ogg"},//nexuiz qc names .wav, but the paks use .ogg
{"sound/", "", ".wav", ".wav"}, //nexuiz qc names sound/ but that's normally implied, resulting in doubles that don't exist in the filesystem
{"sound/", "", ".wav", ".ogg"} //both of nexuiz's issues
};
found = FS_FLocateFile(tryogg, FSLF_IFFOUND, loc);
if (found)
{
name = *replacementname = va("%s", tryogg);
}
}
}
//nexuiz also names files with absolute paths (yet sounds are meant to have an extra prefix)
//this results in clients asking for sound/sound/blah.wav (or sound/sound/blah.ogg for nexuiz)
if (!found && replacementname)
{
if (!strncmp(name, "sound/", 6))
for (alt = 0; alt < countof(alternatives); alt++)
{
int result;
result = SV_LocateDownload(name+6, loc, replacementname, redirectpaks);
if (!result)
{ //if that was successful... redirect to it.
result = -4;
*replacementname = name+6;
char tryalt[MAX_QPATH];
char ext[8];
if (strncmp(name, alternatives[alt][0], strlen(alternatives[alt][0])))
{
if (*alternatives[alt][2])
{
if (strcmp(COM_FileExtension(name, ext, sizeof(ext)), alternatives[alt][2]+1))
continue;
memcpy(tryalt, alternatives[alt][1], strlen(alternatives[alt][1]));
COM_StripExtension(name+strlen(alternatives[alt][0]), tryalt+strlen(alternatives[alt][1]), sizeof(tryalt)-strlen(alternatives[alt][1]));
COM_DefaultExtension(tryalt, alternatives[alt][3], sizeof(tryalt));
}
else
{
memcpy(tryalt, alternatives[alt][1], strlen(alternatives[alt][1]));
Q_strncpyz(tryalt+strlen(alternatives[alt][1]), name+strlen(alternatives[alt][0]), sizeof(tryalt)-strlen(alternatives[alt][1]));
}
found = FS_FLocateFile(tryalt, FSLF_IFFOUND, loc);
if (found)
{
Q_snprintfz(tmpname, sizeof(tmpname), "%s", tryalt);
name = *replacementname = tmpname;
break;
}
}
return result;
}
}
@ -2844,7 +2859,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
if (!allow_download_anymap.value && !strncmp(name, "maps/", 5))
{
Sys_Printf ("%s denied download of %s - it is in a pak\n", host_client->name, name+8);
return -2;
return DLERR_PERMISSIONS;
}
}
@ -2858,7 +2873,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
{
//its inside a pak file, return the name of this file instead
*replacementname = pakname;
return -4; //redirect
return DLERR_REDIRECTPACK; //redirect
}
else
Con_Printf("Failed to read %s\n", pakname);
@ -2870,12 +2885,12 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
if (!allow_download_pakcontents.value)
{
Sys_Printf ("%s denied download of %s - it is in a pak\n", host_client->name, name+8);
return -2;
return DLERR_PERMISSIONS;
}
}
if (replacementname && *replacementname)
return -4;
return DLERR_REDIRECTPACK;
return 0;
}
return -1; //not found
@ -2980,7 +2995,7 @@ void SV_BeginDownload_f(void)
result = SV_LocateDownload(name, &loc, &redirection, false);
if (result == -5)
if (result == DLERR_PACKAGE)
{
//package download
result = 0;
@ -2989,11 +3004,11 @@ void SV_BeginDownload_f(void)
else
{
//redirection protocol-specific code goes here.
if (result == -4)
if (result == DLERR_REDIRECTPACK || result == DLERR_REDIRECTFILE)
{
#ifdef PEXT_CHUNKEDDOWNLOADS
qboolean isezquake = !strncmp(Info_ValueForKey(host_client->userinfo, "*client"), "ezQuake", 7);
if ((host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) && !isezquake)
//ezquake etc cannot cope with proper redirects
if ((host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) && (host_client->fteprotocolextensions & PEXT_CSQC))
{
//redirect the client (before the message saying download failed)
// char *s = va("dlsize \"%s\" r \"%s\"\n", name, redirection);
@ -3002,13 +3017,14 @@ void SV_BeginDownload_f(void)
ClientReliableWrite_Begin (host_client, svc_download, 10+strlen(name));
ClientReliableWrite_Long (host_client, -1);
ClientReliableWrite_Long (host_client, result);
ClientReliableWrite_Long (host_client, DLERR_REDIRECTFILE);
ClientReliableWrite_String (host_client, redirection);
return;
}
else
else if (result == DLERR_REDIRECTFILE && host_client->protocol == SCP_QUAKEWORLD)
{ //crappy hack for crappy clients. tell them to download the new file instead without telling them about any failure.
//this will seriously mess with any download queues or anything like that
//this doesn't apply to packages, because these shitty clients won't know to actually load said packages before attempting to request more files, meaning the same package gets downloaded 80 times and then only actually used AFTER they restart the client.
char *s = va("download \"%s\"\n", redirection);
ClientReliableWrite_Begin (host_client, svc_stufftext, 2+strlen(s));
ClientReliableWrite_String (host_client, s);
@ -3032,14 +3048,23 @@ void SV_BeginDownload_f(void)
char *error;
switch(result)
{
case DLERR_FILENOTFOUND:
default:
result = DLERR_FILENOTFOUND;
error = "Download could not be found\n";
break;
case -2:
case DLERR_UNKNOWN:
error = "Filesystem error\n";
break;
case DLERR_PERMISSIONS:
error = "Download permission denied\n";
break;
case -4:
result = -1;
case DLERR_REDIRECTFILE:
result = DLERR_PERMISSIONS;
error = "Client doesn't support file redirection\n";
break;
case DLERR_REDIRECTPACK:
result = DLERR_PERMISSIONS;
error = "Package contents not available individually\n";
break;
}
@ -3849,6 +3874,7 @@ qboolean SV_UserInfoIsBasic(char *infoname)
"skin",
"topcolor",
"bottomcolor",
"chat", //ezquake's afk indicators
NULL};
@ -3914,12 +3940,14 @@ void SV_SetInfo_f (void)
if (!strcmp(Info_ValueForKey(host_client->userinfo, key), oldval))
return; // key hasn't changed
#ifdef Q2SERVER
if (svs.gametype == GT_QUAKE2)
{
ge->ClientUserinfoChanged (host_client->q2edict, host_client->userinfo); //tell the gamecode
SV_ExtractFromUserinfo(host_client, true); //let the server routines know
return;
}
#endif
// process any changed values
SV_ExtractFromUserinfo (host_client, true);
@ -6864,7 +6892,7 @@ void SV_ReadQCRequest(void)
{
int e;
char args[8];
char *rname;
char *rname, *fname;
func_t f;
int i;
globalvars_t *pr_globals;
@ -6924,10 +6952,10 @@ done:
args[i] = 0;
rname = MSG_ReadString();
if (i)
rname = va("CSEv_%s_%s", rname, args);
fname = va("CSEv_%s_%s", rname, args);
else
rname = va("CSEv_%s", rname);
f = PR_FindFunction(svprogfuncs, rname, PR_ANY);
fname = va("CSEv_%s", rname);
f = PR_FindFunction(svprogfuncs, fname, PR_ANY);
if (!f)
{
if (i)
@ -6942,7 +6970,7 @@ done:
PR_ExecuteProgram(svprogfuncs, f);
}
else
SV_ClientPrintf(host_client, PRINT_HIGH, "qcrequest \"%s\" not supported\n", rname);
SV_ClientPrintf(host_client, PRINT_HIGH, "qcrequest \"%s\" not supported\n", fname);
}
void SV_AckEntityFrame(client_t *cl, int framenum)

View file

@ -29,6 +29,7 @@ char shaders[][64] =
"postproc_panorama",
"postproc_laea",
"postproc_stereographic",
"postproc_equirectangular",
"fxaa",
"rtlight",
"underwaterwarp",

View file

@ -996,13 +996,13 @@ void SW_SCR_UpdateScreen(void)
V_UpdatePalette (false);
}
void SW_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize)
void SW_VBO_Begin(vbobctx_t *ctx, size_t maxsize)
{
}
void SW_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray)
void SW_VBO_Data(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray)
{
}
void SW_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray)
void SW_VBO_Finish(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray)
{
}
void SW_VBO_Destroy(vboarray_t *vearray)

View file

@ -258,25 +258,25 @@ qboolean SWAppActivate(BOOL fActive, BOOL minimize)
{
static BOOL sound_active;
if (ActiveApp == fActive && Minimized == minimize)
if (vid.activeapp == fActive && Minimized == minimize)
return false; //so windows doesn't crash us over and over again.
ActiveApp = fActive;
vid.activeapp = fActive;
Minimized = minimize;
// enable/disable sound on focus gain/loss
if (!ActiveApp && sound_active)
if (!vid.activeapp && sound_active)
{
S_BlockSound ();
sound_active = false;
}
else if (ActiveApp && !sound_active)
else if (vid.activeapp && !sound_active)
{
S_UnblockSound ();
sound_active = true;
}
INS_UpdateGrabs(false, ActiveApp);
INS_UpdateGrabs(false, vid.activeapp);
/*
if (fActive)
@ -704,7 +704,7 @@ void SW_VID_SwapBuffers(void)
DIB_SwapBuffers();
framenumber++;
INS_UpdateGrabs(false, ActiveApp);
INS_UpdateGrabs(false, vid.activeapp);
// memset( pDIBBase, 0, vid.pixelwidth * vid.pixelheight * 4);

View file

@ -8,7 +8,6 @@ extern int gammaworks;
extern qboolean vid_isfullscreen;
qboolean ActiveApp;
qboolean mouseactive;
extern qboolean mouseusedforgui;
@ -221,7 +220,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
return false;
}
ActiveApp = true;
vid.activeapp = true;
GL_Init(GLVID_getsdlglfunction);
@ -236,7 +235,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
void GLVID_DeInit (void)
{
ActiveApp = false;
vid.activeapp = false;
emscriptenfte_setupcanvas(-1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
@ -261,9 +260,9 @@ void GLVID_SwapBuffers (void)
}
else
{
if ((key_dest == key_game||mouseusedforgui) && ActiveApp)
if ((key_dest == key_game||mouseusedforgui) && vid.activeapp)
IN_ActivateMouse ();
else if (!(key_dest == key_game || mouseusedforgui) || !ActiveApp)
else if (!(key_dest == key_game || mouseusedforgui) || !vid.activeapp)
IN_DeactivateMouse ();
}
}

View file

@ -47,7 +47,7 @@ nonstatic void(mitem_desktop desktop) M_Main =
local mitem_exmenu m;
//no dupes please.
m = (mitem_exmenu)desktop.findchild(_("Main Menu"));
m = (mitem_exmenu)desktop.findchildtext(_("Main Menu"));
if (m)
{
m.totop();

View file

@ -23,7 +23,7 @@ nonstatic void(mitem_desktop desktop) M_NewGame =
if (gametype == "sp")
{
//single player has no options. the start map itself gives skill+episode options.
localcmd("\ndeathmatch 0; coop 0; maxplayers 0; timelimit 0; fraglimit 0; teamplay 0; map start\n");
localcmd("\ndeathmatch 0; coop 0; maxplayers 0; timelimit 0; fraglimit 0; teamplay 0; samelevel 0; map start\n");
return;
}
if (gametype == "begin")

View file

@ -35,7 +35,7 @@ nonstatic void(mitem_desktop desktop) M_Options =
//and show the options.
fr.add(spawn(mitem_text, item_text:"Graphical Presets", item_command:"m_pop;m_preset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
fr.add(spawn(mitem_text, item_text:"Game Presets", item_command:"m_pop;m_configs", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
fr.add(spawn(mitem_text, item_text:"Game Configs", item_command:"m_pop;m_configs", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
fr.add(spawn(mitem_text, item_text:"Basic Setup", item_command:"m_pop;m_basicopts", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
fr.add(spawn(mitem_text, item_text:"Audio", item_command:"m_pop;m_audio", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
fr.add(spawn(mitem_text, item_text:"Video", item_command:"m_pop;m_video", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;

View file

@ -3,24 +3,8 @@ Uses the engine command to apply the preset, and tries an exec instead if a conf
Doesn't track the current one or anything.
Really simple and stupid menu.
no background tint, so the game is still visible so you can preview it.
you should probably remove the fps_preset part. I left it in so that I don't have to bother with providing cfg files. note that this isn't a valid solution for dp, but whatever.
the great thing about providing source is that you can change it.
you can instead just shove your preset settings directly into the quotes instead of exec.
*/
struct
{
string name;
string preset;
string config;
} configs[] =
{
// {"Simple Deathmatch", "simple", "configs/game_simple.cfg"},
{"Deathmatch", "deathmatch", "configs/game_deathmatch.cfg"},
{"Mod Compatibility", "compat", "configs/game_compat.cfg"},
{"Standard", "normal", "configs/game_normal.cfg"}
};
nonstatic void(mitem_desktop desktop) M_Configs =
{
@ -41,13 +25,24 @@ nonstatic void(mitem_desktop desktop) M_Configs =
mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE);
m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]);
float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN;
//add the options
for (i = 0; i < configs.length; i++)
float fs, y=0;
fs = search_begin("configs/game_*.cfg", TRUE, TRUE);
float c = search_getsize(fs);
for (i = 0; i < c; i++)
{
fr.add(spawn(mitem_text, item_text:configs[i].name, item_command:sprintf("exec \"%s\"", configs[i].config), item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, i*16], [100, 16]);
string fname = search_getfilename(fs, i);
string iname = substring(fname, 10, -5);
string dname = GetFirstLineComment(fname, iname);
iname = sprintf("exec \"%s\"", iname);
if (dname && !fr.findchildcmd(iname))
fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=16], '100 16');
}
search_end(fs);
if (c <= 0)
fr.add(spawn(mitem_text, item_text:"No configs found", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y], '100 16');
//random art for style
#if 1//def CSQC

View file

@ -19,9 +19,9 @@ nonstatic void(mitem_desktop desktop) M_Options_Hud =
mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE);
m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]);
float fs = search_begin("configs/hud_*.cfg", TRUE, TRUE);
float fs = search_begin("hud/*.cfg", TRUE, TRUE);
float fc = search_getsize(fs);
//add the options
for (i = 0, float y = 0; i < fc; i++)
{

View file

@ -48,16 +48,6 @@ class particlesmenu : mitem_frame
thelist = strtrim(strcat(thelist, " ", cmd));
UpdateSelections();
};
//to avoid dupes
nonvirtual float(string n) HasChild =
{
for (mitem ch = item_children; ch; ch = ch.item_next)
{
if (!strcasecmp(n, ch.item_command))
return TRUE;
}
return FALSE;
};
};
string(string fname, string dflt) GetFirstLineComment =
@ -124,7 +114,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Particles =
string fname = search_getfilename(fs, i);
string iname = substring(fname, 10, -5);
string dname = GetFirstLineComment(fname, iname);
if (dname && !fr.HasChild(iname))
if (dname && !fr.findchildcmd(iname))
fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8');
}
search_end(fs);
@ -134,7 +124,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Particles =
string fname = search_getfilename(fs, i);
string iname = substring(fname, 10, -5);
string dname = GetFirstLineComment(fname, iname);
if (dname && !fr.HasChild(iname))
if (dname && !fr.findchildcmd(iname))
fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:8, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, y+=8], '0 8');
}
search_end(fs);

View file

@ -63,14 +63,30 @@ nonstatic void(mitem_desktop desktop) M_Preset =
m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]);
float fl = RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN;
//add the options
for (i = 0, float pos = 0; i < presets.length; i++)
float fs, y=0;
fs = search_begin("configs/preset_*.cfg", TRUE, TRUE);
float c = search_getsize(fs);
for (i = 0; i < c; i++)
{
if (checkfileexists(presets[i].config)) //file exists, try to exec it
fr.add(spawn(mitem_text, item_text:presets[i].name, item_command:sprintf("exec \"%s\";vid_reload", presets[i].config), item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [100, 16]);
else //okay, no file exists, depend upon the engine for it.
string fname = search_getfilename(fs, i);
string iname = substring(fname, 10, -5);
string dname = GetFirstLineComment(fname, iname);
iname = sprintf("exec \"%s\";vid_reload", iname);
if (dname && !fr.findchildcmd(iname))
{
fr.add(spawn(mitem_text, item_text:dname, item_command:iname, item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, y], '100 16');
y+=16;
}
}
search_end(fs);
if (c <= 0)
{
//add the default options
for (i = 0, float pos = 0; i < presets.length; i++)
{
fr.add(spawn(mitem_text, item_text:presets[i].name, item_command:sprintf("fps_preset %s", presets[i].preset), item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [100, 16]);
pos += 16;
pos += 16;
}
}
//random art for style

View file

@ -372,7 +372,7 @@ nonstatic void(mitem_desktop desktop) M_Servers =
}
#endif
o = (mitem_menu)desktop.findchild(_("Servers List"));
o = (mitem_menu)desktop.findchildtext(_("Servers List"));
if (o)
o.totop();
else

View file

@ -25,15 +25,18 @@ float sb_showscores;
void() mitem_desktop::mitem_desktop =
{
#define menu_font_win autocvar(menu_font_win, "cour")
#define menu_font_win autocvar(menu_font_win, "")
#define menu_font autocvar(menu_font, "")
queryscreensize();
//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
if (menu_font_win != "" && !strncmp(cvar_string("sys_platform"), "Win", 3))
drawfont = loadfont("", menu_font_win, "8 12 16", 0);
drawfont = loadfont("", menu_font_win, "8 12 16", -1);
else if (menu_font != "")
drawfont = loadfont("", menu_font, "8 12 16", -1);
else
drawfont = loadfont("", menu_font, "8 12 16", 0);
drawfont = 0;
item_text = "desktop";
if (!item_flags)

View file

@ -35,7 +35,8 @@ class mitem_frame : mitem
vector item_framesize; //x=sides, y=top, z=bottom
float frame_hasscroll;
static mitem(string title) findchild;
static mitem(string title) findchildtext;
static mitem(string title) findchildcmd;
static void(mitem newitem, float originflags, vector originmin, vector originmax) add;
static void(mitem newitem, vector pos) adda;
static void(mitem newitem, vector originmin, vector originmax) addm;
@ -56,7 +57,7 @@ void(mitem fromitem, string cmd) mitem_frame::item_execcommand =
localcmd(strcat(cmd, "\n"));
};
mitem(string title) mitem_frame::findchild =
mitem(string title) mitem_frame::findchildtext =
{
mitem ch;
for (ch = item_children; ch; ch = ch.item_next)
@ -66,6 +67,17 @@ mitem(string title) mitem_frame::findchild =
}
return __NULL__;
};
mitem(string title) mitem_frame::findchildcmd =
{
mitem ch;
for (ch = item_children; ch; ch = ch.item_next)
{
if (ch.item_command == title)
return ch;
}
return __NULL__;
};
//adds an item with the desired origin settings
void(mitem newitem, float originflags, vector originmin, vector originmax) mitem_frame::add =