From fceb09fe375398121cb21186679ddce1ab24d701 Mon Sep 17 00:00:00 2001 From: Spoike Date: Fri, 26 Jul 2013 17:19:06 +0000 Subject: [PATCH] reworked demo playback and interpolation. added support for recording nq demos, but only if not already on the server. added capturedriver as a sane way to select between screenshots, avi, or various plugins. output sound device can now be selected via the menu. not all drivers provide device enumeration (openal and dsound do). enabled openal, but not using it unless an openal device is explicitly requested as its still a little buggy. added \"\"" markup in the console. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4427 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 27 +- engine/botlib/be_interface.c | 2 +- engine/botlib/botlib.h | 2 +- engine/client/cl_demo.c | 694 +++++++++++++++++---------------- engine/client/cl_ents.c | 54 ++- engine/client/cl_input.c | 10 +- engine/client/cl_main.c | 40 +- engine/client/cl_parse.c | 344 ++++++++++------ engine/client/cl_pred.c | 83 ++-- engine/client/client.h | 20 +- engine/client/m_items.c | 19 +- engine/client/m_mp3.c | 85 ++-- engine/client/m_options.c | 66 +++- engine/client/menu.h | 1 + engine/client/pr_csqc.c | 3 + engine/client/sbar.c | 5 +- engine/client/snd_al.c | 557 +++++++++++++++++++------- engine/client/snd_directx.c | 214 +++++----- engine/client/snd_dma.c | 624 ++++++++++++++++++----------- engine/client/sound.h | 16 +- engine/client/sys_win.c | 3 + engine/client/view.c | 34 +- engine/common/bothdefs.h | 2 +- engine/common/cmd.c | 2 +- engine/common/com_mesh.c | 14 +- engine/common/common.c | 102 ++++- engine/common/common.h | 3 +- engine/common/cvar.c | 30 +- engine/common/net_chan.c | 11 +- engine/common/pmovetst.c | 2 +- engine/common/protocol.h | 12 +- engine/common/translate.c | 2 +- engine/d3d/d3d11_backend.c | 2 +- engine/d3d/d3d_image.c | 33 +- engine/d3d/vid_d3d11.c | 1 - engine/dotnet2005/ftequake.sln | 260 ++++++------ engine/gl/gl_backend.c | 6 +- engine/gl/gl_draw.c | 18 +- engine/gl/gl_font.c | 2 + engine/gl/gl_ngraph.c | 2 +- engine/qclib/Makefile | 2 +- engine/qclib/qcc_pr_comp.c | 8 +- engine/server/sv_mvd.c | 13 +- engine/server/sv_send.c | 22 +- plugins/avplug/avdecode.c | 4 + plugins/avplug/avencode.c | 35 +- plugins/mpq/fs_mpq.vcproj | 221 +++++++++++ 47 files changed, 2379 insertions(+), 1333 deletions(-) create mode 100644 plugins/mpq/fs_mpq.vcproj diff --git a/engine/Makefile b/engine/Makefile index 36c6e42b0..4b9a65af1 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -518,9 +518,16 @@ MP3_OBJS = \ huffman.o \ mymad.o -PROGS_OBJS = \ +QCC_OBJS= \ comprout.o \ hash.o \ + qcc_cmdlib.o \ + qccmain.o \ + qcc_pr_comp.o \ + qcc_pr_lex.o \ + qcd_main.o +PROGS_OBJS = \ + $(QCC_OBJS) \ initlib.o \ pr_bgcmd.o \ pr_skelobj.o \ @@ -528,12 +535,7 @@ PROGS_OBJS = \ pr_exec.o \ pr_multi.o \ pr_x86.o \ - qcc_cmdlib.o \ - qccmain.o \ - qcc_pr_comp.o \ - qcc_pr_lex.o \ - qcdecomp.o \ - qcd_main.o + qcdecomp.o SERVER_OBJS = \ pr_cmds.o \ @@ -1372,6 +1374,17 @@ m-profile: .PHONY: m-tmp mcl-tmp mingl-tmp glcl-tmp gl-tmp sv-tmp _clsv-dbg _clsv-rel _cl-dbg _cl-rel _out-rel _out-dbg +_qcc-tmp: $(REQDIR) + @$(MAKE) $(TYPE) EXE_NAME="$(EXE_NAME)" PRECOMPHEADERS="" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" OBJS="QCC_OBJS SOBJS" +qcc-rel: + @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqcc" OUT_DIR="$(RELEASE_DIR)/qcc" SOBJS="qcctui.o" +qccgui-rel: + @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui" OUT_DIR="$(RELEASE_DIR)/qcc" SOBJS="qccgui.o qccguistuff.o" LDFLAGS="$(LDFLAGS) -lcomdlg32 -lcomctl32" +qcc-dbg: + @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqcc" OUT_DIR="$(RELEASE_DIR)/qcc" SOBJS="qcctui.o" +qccgui-dbg: + @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqccgui" OUT_DIR="$(RELEASE_DIR)/qcc" SOBJS="qccgui.o qccguistuff.o" LDFLAGS="$(LDFLAGS) -lcomdlg32 -lcomctl32" + ifdef windir debugdir: @-mkdir -p $(subst /,\, $(OUT_DIR)) diff --git a/engine/botlib/be_interface.c b/engine/botlib/be_interface.c index d279cef39..2444124cc 100644 --- a/engine/botlib/be_interface.c +++ b/engine/botlib/be_interface.c @@ -868,7 +868,7 @@ static void Init_AI_Export( ai_export_t *ai ) { GetBotLibAPI ============ */ -botlib_export_t *GetBotLibAPI(int apiVersion, botlib_import_t *import) { +botlib_export_t *QDECL GetBotLibAPI(int apiVersion, botlib_import_t *import) { assert(import); botimport = *import; assert(botimport.Print); diff --git a/engine/botlib/botlib.h b/engine/botlib/botlib.h index d36a038da..3da1c39a8 100644 --- a/engine/botlib/botlib.h +++ b/engine/botlib/botlib.h @@ -431,7 +431,7 @@ typedef struct botlib_export_s } botlib_export_t; //linking of bot library -botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import ); +botlib_export_t *QDECL GetBotLibAPI( int apiVersion, botlib_import_t *import ); /* Library variables: diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 03bac1fce..6bc77ab36 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -92,6 +92,10 @@ void CL_WriteDemoCmd (usercmd_t *pcmd) qbyte c; q1usercmd_t cmd; + //nq doesn't have this info + if (cls.demorecording != 1) + return; + //Con_Printf("write: %ld bytes, %4.4f\n", msg->cursize, demtime); fl = LittleFloat((float)demtime); @@ -131,7 +135,7 @@ CL_WriteDemoMessage Dumps the current net message, prefixed by the length and view angles ==================== */ -void CL_WriteDemoMessage (sizebuf_t *msg) +void CL_WriteDemoMessage (sizebuf_t *msg, int payloadoffset) { int len; int i; @@ -140,37 +144,50 @@ void CL_WriteDemoMessage (sizebuf_t *msg) //Con_Printf("write: %ld bytes, %4.4f\n", msg->cursize, demtime); - if (!cls.demorecording) + switch (cls.demorecording) + { + case 0: return; + case 1: //QW + fl = LittleFloat((float)demtime); + VFS_WRITE (cls.demooutfile, &fl, sizeof(fl)); - fl = LittleFloat((float)demtime); - VFS_WRITE (cls.demooutfile, &fl, sizeof(fl)); + c = dem_read; + VFS_WRITE (cls.demooutfile, &c, sizeof(c)); - c = dem_read; - VFS_WRITE (cls.demooutfile, &c, sizeof(c)); - - if (*(int*)msg->data == -1) - { - //connectionless packet. - len = LittleLong (msg->cursize); - VFS_WRITE (cls.demooutfile, &len, 4); - VFS_WRITE (cls.demooutfile, msg->data + msg_readcount, msg->cursize - msg_readcount); + if (*(int*)msg->data == -1) + { + //connectionless packet. + len = LittleLong (msg->cursize); + VFS_WRITE (cls.demooutfile, &len, 4); + VFS_WRITE (cls.demooutfile, msg->data + msg_readcount, msg->cursize - msg_readcount); + } + else + { + //regenerate a legacy netchan. no fragmentation support, but whatever. this ain't udp. + //the length + len = LittleLong (msg->cursize - msg_readcount + 8); + VFS_WRITE (cls.demooutfile, &len, 4); + //hack the netchan here. + i = cls.netchan.incoming_sequence; + VFS_WRITE (cls.demooutfile, &i, 4); + i = cls.netchan.incoming_acknowledged; + VFS_WRITE (cls.demooutfile, &i, 4); + //and the data + VFS_WRITE (cls.demooutfile, msg->data + msg_readcount, msg->cursize - msg_readcount); + } + break; + case 2: //NQ + len = LittleLong (net_message.cursize - payloadoffset); + VFS_WRITE(cls.demooutfile, &len, sizeof(len)); + for (i=0 ; i<3 ; i++) + { + float f = LittleFloat (cl.playerview[0].viewangles[i]); + VFS_WRITE(cls.demooutfile, &f, sizeof(f)); + } + VFS_WRITE(cls.demooutfile, net_message.data + payloadoffset, net_message.cursize - payloadoffset); + break; } - else - { - //regenerate a legacy netchan. no fragmentation support, but whatever. this ain't udp. - //the length - len = LittleLong (msg->cursize - msg_readcount + 8); - VFS_WRITE (cls.demooutfile, &len, 4); - //hack the netchan here. - i = cls.netchan.incoming_sequence; - VFS_WRITE (cls.demooutfile, &i, 4); - i = cls.netchan.incoming_acknowledged; - VFS_WRITE (cls.demooutfile, &i, 4); - //and the data - VFS_WRITE (cls.demooutfile, msg->data + msg_readcount, msg->cursize - msg_readcount); - } - VFS_FLUSH (cls.demooutfile); } @@ -244,6 +261,8 @@ int readdemobytes(int *readpos, void *data, int len) { int i; int trybytes; + if (len < 0) + Host_EndGame("Corrupt demo"); if (demopreparsedbytes < 0) //won't happen in normal running, but can still happen on corrupt data... if we don't disconnect first. { @@ -391,6 +410,7 @@ CL_GetDemoMessage ==================== */ +vec3_t demoangles; float olddemotime = 0; float nextdemotime = 0; qboolean CL_GetDemoMessage (void) @@ -456,27 +476,7 @@ qboolean CL_GetDemoMessage (void) if ((cls.timedemo && host_framecount == demoframe) || (!cls.timedemo && demtime<= cl.gametime && cl.gametime))// > dem_lasttime+demtime) { if (demtime <= cl.gametime-1) - { demtime = cl.gametime; - } - - { - float f = (cl.gametime-demtime)/(cl.gametime-olddemotime); - float a1; - float a2; - - for (i=0 ; i<3 ; i++) - { - a1 = cl.playerview[2].viewangles[i]; - a2 = cl.playerview[1].viewangles[i]; - if (a1 - a2 > 180) - a1 -= 360; - if (a1 - a2 < -180) - a1 += 360; - cl.playerview[0].simangles[i] = a2 + f * (a1 - a2); - } - VectorCopy(cl.playerview[0].simangles, cl.playerview[0].viewangles); - } return 0; } demoframe = host_framecount; @@ -487,13 +487,11 @@ qboolean CL_GetDemoMessage (void) } if (cls.demoplayback == DPB_NETQUAKE) { - VectorCopy (cl.playerview[1].viewangles, cl.playerview[2].viewangles); for (i=0 ; i<3 ; i++) { readdemobytes(&demopos, &f, 4); - cl.playerview[0].simangles[i] = cl.playerview[1].viewangles[i] = LittleFloat (f); + demoangles[i] = LittleFloat (f); } - VectorCopy (cl.playerview[1].viewangles, cl.playerview[0].viewangles); } olddemotime = demtime; @@ -645,42 +643,6 @@ readnext: Con_Printf("mvd demos/qtv streams should not contain dem_cmd\n"); olddemotime = demtime+1; CL_StopPlayback (); - /* - unsigned short samps; - unsigned char bits; - unsigned char rateid; - unsigned char audio[8192]; - - if (readdemobytes (&demopos, &samps, 2) == 2) - { - if (readdemobytes (&demopos, &bits, 1) == 1) - { - if (samps > sizeof(audio)) - { - Con_Printf("Corrupted/too large audio chunk\n"); - CL_StopPlayback(); - return 0; - } - if (readdemobytes (&demopos, &rateid, 1) == 1) - { - if (readdemobytes (&demopos, audio, samps) == samps) - { - FILE *f; - samps = samps/(bits/8); - f = fopen("c:/test.raw", "r+b"); - if (f) - { - fseek(f, 0, SEEK_END); - fwrite(audio, samps, bits/8, f); - fclose(f); - } - S_RawAudio(0, audio, 11025, samps, 1, bits/8); - break; - } - } - } - } -*/ return 0; } else @@ -715,6 +677,7 @@ readnext: for (i=0 ; i<3 ; i++) { readdemobytes (&demopos, &f, 4); + demoangles[i] = LittleFloat (f); cl.playerview[0].viewangles[i] = LittleFloat (f); } goto readnext; @@ -880,8 +843,9 @@ void CL_Stop_f (void) { #ifndef CLIENTONLY SV_MVDStop_f(); -#endif +#else Con_Printf ("Not recording a demo.\n"); +#endif return; } @@ -890,7 +854,7 @@ void CL_Stop_f (void) MSG_WriteLong (&net_message, -1); // -1 sequence means out of band MSG_WriteByte (&net_message, svc_disconnect); MSG_WriteString (&net_message, "EndOfDemo"); - CL_WriteDemoMessage (&net_message); + CL_WriteDemoMessage (&net_message, sizeof(int)); // finish up VFS_CLOSE (cls.demooutfile); @@ -946,7 +910,7 @@ void CL_WriteSetDemoMessage (void) //Con_Printf("write: %ld bytes, %4.4f\n", msg->cursize, demtime); - if (!cls.demorecording) + if (cls.demorecording != 1) return; fl = LittleFloat((float)demtime); @@ -964,7 +928,52 @@ void CL_WriteSetDemoMessage (void) } +/* +record a single player game. +*/ +#ifndef CLIENTONLY +mvddest_t *SV_InitRecordFile (char *name); +qboolean SV_MVD_Record (mvddest_t *dest); +void CL_RecordMap_f (void) +{ + char demoname[MAX_QPATH]; + char mapname[MAX_QPATH]; + char *demoext; + Q_strncpyz(demoname, Cmd_Argv(1), sizeof(demoname)); + Q_strncpyz(mapname, Cmd_Argv(2), sizeof(mapname)); + CL_Disconnect_f(); + SV_SpawnServer (mapname, NULL, false, false); + + COM_DefaultExtension(demoname, ".mvd", sizeof(demoname)); + demoext = COM_FileExtension(demoname); + + if (!strcmp(demoext, "mvd")) + { + if (!SV_MVD_Record (SV_InitRecordFile(demoname))) + CL_Disconnect_f(); +// char buf[512]; +// Cbuf_AddText(va("mvdrecord %s\n", COM_QuotedString(demoname, buf, sizeof(buf))), RESTRICT_LOCAL); + } + else + { + cls.demooutfile = FS_OpenVFS (demoname, "wb", FS_GAME); + if (!cls.demooutfile) + { + CL_Disconnect_f(); + return; + } + if (!strcmp(demoext, "dem")) + { + cls.demorecording = 2; + VFS_PUTS(cls.demooutfile, "-1\n"); + } + else + cls.demorecording = 1; + CL_WriteSetDemoMessage(); + } +} +#endif /* ==================== @@ -990,6 +999,9 @@ void CL_Record_f (void) c = Cmd_Argc(); if (c > 2) { +#ifndef CLIENTONLY + CL_RecordMap_f(); +#endif Con_Printf ("record \n"); return; } @@ -1110,199 +1122,172 @@ void CL_Record_f (void) /*-------------------------------------------------*/ -// serverdata - // send the info about the new client to all connected clients - memset(&buf, 0, sizeof(buf)); - buf.data = buf_data; - buf.maxsize = sizeof(buf_data); - buf.prim = cls.netchan.netprim; + switch(cls.protocol) + { + case CP_QUAKEWORLD: -// send the serverdata - MSG_WriteByte (&buf, svc_serverdata); + // serverdata + // send the info about the new client to all connected clients + memset(&buf, 0, sizeof(buf)); + buf.data = buf_data; + buf.maxsize = sizeof(buf_data); + buf.prim = cls.netchan.netprim; + + // send the serverdata + MSG_WriteByte (&buf, svc_serverdata); #ifdef PROTOCOL_VERSION_FTE - if (cls.fteprotocolextensions) //maintain demo compatability - { - MSG_WriteLong (&buf, PROTOCOL_VERSION_FTE); - MSG_WriteLong (&buf, cls.fteprotocolextensions); - } - if (cls.fteprotocolextensions2) //maintain demo compatability - { - MSG_WriteLong (&buf, PROTOCOL_VERSION_FTE2); - MSG_WriteLong (&buf, cls.fteprotocolextensions2); - } + if (cls.fteprotocolextensions) //maintain demo compatability + { + MSG_WriteLong (&buf, PROTOCOL_VERSION_FTE); + MSG_WriteLong (&buf, cls.fteprotocolextensions); + } + if (cls.fteprotocolextensions2) //maintain demo compatability + { + MSG_WriteLong (&buf, PROTOCOL_VERSION_FTE2); + MSG_WriteLong (&buf, cls.fteprotocolextensions2); + } #endif - MSG_WriteLong (&buf, PROTOCOL_VERSION_QW); - MSG_WriteLong (&buf, cl.servercount); - MSG_WriteString (&buf, gamedirfile); + MSG_WriteLong (&buf, PROTOCOL_VERSION_QW); + MSG_WriteLong (&buf, cl.servercount); + MSG_WriteString (&buf, gamedirfile); - if (cls.fteprotocolextensions2 & PEXT2_MAXPLAYERS) - { - MSG_WriteByte (&buf, cl.allocated_client_slots); - MSG_WriteByte (&buf, cl.splitclients | (cl.spectator?128:0)); - for (i = 0; i < cl.splitclients; i++) + if (cls.fteprotocolextensions2 & PEXT2_MAXPLAYERS) { - MSG_WriteByte (&buf, cl.playerview[i].playernum); - } - } - else - { - for (i = 0; i < cl.splitclients; i++) - { - if (cl.spectator) - MSG_WriteByte (&buf, cl.playerview[i].playernum | 128); - else + MSG_WriteByte (&buf, cl.allocated_client_slots); + MSG_WriteByte (&buf, cl.splitclients | (cl.spectator?128:0)); + for (i = 0; i < cl.splitclients; i++) + { MSG_WriteByte (&buf, cl.playerview[i].playernum); + } + } + else + { + for (i = 0; i < cl.splitclients; i++) + { + if (cl.spectator) + MSG_WriteByte (&buf, cl.playerview[i].playernum | 128); + else + MSG_WriteByte (&buf, cl.playerview[i].playernum); + } + if (cls.fteprotocolextensions & PEXT_SPLITSCREEN) + MSG_WriteByte (&buf, 128); } - if (cls.fteprotocolextensions & PEXT_SPLITSCREEN) - MSG_WriteByte (&buf, 128); - } - // send full levelname - MSG_WriteString (&buf, cl.levelname); + // send full levelname + MSG_WriteString (&buf, cl.levelname); - // send the movevars - MSG_WriteFloat(&buf, movevars.gravity); - MSG_WriteFloat(&buf, movevars.stopspeed); - MSG_WriteFloat(&buf, movevars.maxspeed); - MSG_WriteFloat(&buf, movevars.spectatormaxspeed); - MSG_WriteFloat(&buf, movevars.accelerate); - MSG_WriteFloat(&buf, movevars.airaccelerate); - MSG_WriteFloat(&buf, movevars.wateraccelerate); - MSG_WriteFloat(&buf, movevars.friction); - MSG_WriteFloat(&buf, movevars.waterfriction); - MSG_WriteFloat(&buf, movevars.entgravity); + // send the movevars + MSG_WriteFloat(&buf, movevars.gravity); + MSG_WriteFloat(&buf, movevars.stopspeed); + MSG_WriteFloat(&buf, movevars.maxspeed); + MSG_WriteFloat(&buf, movevars.spectatormaxspeed); + MSG_WriteFloat(&buf, movevars.accelerate); + MSG_WriteFloat(&buf, movevars.airaccelerate); + MSG_WriteFloat(&buf, movevars.wateraccelerate); + MSG_WriteFloat(&buf, movevars.friction); + MSG_WriteFloat(&buf, movevars.waterfriction); + MSG_WriteFloat(&buf, movevars.entgravity); - // send server info string - MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) ); + // send server info string + MSG_WriteByte (&buf, svc_stufftext); + MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) ); - // send music (delayed) - MSG_WriteByte (&buf, svc_cdtrack); - MSG_WriteByte (&buf, 0); // none in demos + // send music (delayed) + MSG_WriteByte (&buf, svc_cdtrack); + MSG_WriteByte (&buf, 0); // none in demos #ifdef PEXT_SETVIEW - if (cl.playerview[0].viewentity != cl.playerview[0].playernum+1) //tell the player if we have a different view entity - { - MSG_WriteByte (&buf, svc_setview); - MSG_WriteEntity (&buf, cl.playerview[0].viewentity); - } + if (cl.playerview[0].viewentity != cl.playerview[0].playernum+1) //tell the player if we have a different view entity + { + MSG_WriteByte (&buf, svc_setview); + MSG_WriteEntity (&buf, cl.playerview[0].viewentity); + } #endif - // flush packet - CL_WriteRecordDemoMessage (&buf, seq++); - SZ_Clear (&buf); + // flush packet + CL_WriteRecordDemoMessage (&buf, seq++); + SZ_Clear (&buf); -// soundlist - MSG_WriteByte (&buf, svc_soundlist); - MSG_WriteByte (&buf, 0); + // soundlist + MSG_WriteByte (&buf, svc_soundlist); + MSG_WriteByte (&buf, 0); - n = 0; - s = cl.sound_name[n+1]; - while (*s) - { - MSG_WriteString (&buf, s); - if (buf.cursize > MAX_QWMSGLEN/2) - { - MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, n); - CL_WriteRecordDemoMessage (&buf, seq++); - SZ_Clear (&buf); - MSG_WriteByte (&buf, svc_soundlist); - MSG_WriteByte (&buf, n + 1); - } - n++; + n = 0; s = cl.sound_name[n+1]; - } - if (buf.cursize) - { - MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, 0); - CL_WriteRecordDemoMessage (&buf, seq++); - SZ_Clear (&buf); - } - -// modellist - MSG_WriteByte (&buf, svc_modellist); - MSG_WriteByte (&buf, 0); - - n = 0; - s = cl.model_name[n+1]; - while (*s) - { - MSG_WriteString (&buf, s); - if (buf.cursize > MAX_QWMSGLEN/2) + while (*s) + { + MSG_WriteString (&buf, s); + if (buf.cursize > MAX_QWMSGLEN/2) + { + MSG_WriteByte (&buf, 0); + MSG_WriteByte (&buf, n); + CL_WriteRecordDemoMessage (&buf, seq++); + SZ_Clear (&buf); + MSG_WriteByte (&buf, svc_soundlist); + MSG_WriteByte (&buf, n + 1); + } + n++; + s = cl.sound_name[n+1]; + } + if (buf.cursize) { MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, n); + MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); - MSG_WriteByte (&buf, svc_modellist); - MSG_WriteByte (&buf, n + 1); } - n++; + + // modellist + MSG_WriteByte (&buf, svc_modellist); + MSG_WriteByte (&buf, 0); + + n = 0; s = cl.model_name[n+1]; - } - if (buf.cursize) - { - MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, 0); - CL_WriteRecordDemoMessage (&buf, seq++); - SZ_Clear (&buf); - } - -// spawnstatic - - for (i = 0; i < cl.num_statics; i++) - { - ent = &cl_static_entities[i].ent; - - MSG_WriteByte (&buf, svc_spawnstatic); - - for (j = 1; j < MAX_MODELS; j++) - if (ent->model == cl.model_precache[j]) - break; - if (j == MAX_MODELS) - MSG_WriteByte (&buf, 0); - else - MSG_WriteByte (&buf, j); - - MSG_WriteByte (&buf, ent->framestate.g[FS_REG].frame[0]); - MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, ent->skinnum); - for (j=0 ; j<3 ; j++) + while (*s) { - MSG_WriteCoord (&buf, ent->origin[j]); - MSG_WriteAngle (&buf, ent->angles[j]); + MSG_WriteString (&buf, s); + if (buf.cursize > MAX_QWMSGLEN/2) + { + MSG_WriteByte (&buf, 0); + MSG_WriteByte (&buf, n); + CL_WriteRecordDemoMessage (&buf, seq++); + SZ_Clear (&buf); + MSG_WriteByte (&buf, svc_modellist); + MSG_WriteByte (&buf, n + 1); + } + n++; + s = cl.model_name[n+1]; } - - if (buf.cursize > MAX_QWMSGLEN/2) + if (buf.cursize) { + MSG_WriteByte (&buf, 0); + MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } - } -// spawnstaticsound - // static sounds are skipped in demos, life is hard + // spawnstatic -// baselines - - for (i = 0; i < cl_baselines_count; i++) - { - es = cl_baselines + i; - - if (memcmp(es, &nullentitystate, sizeof(nullentitystate))) + for (i = 0; i < cl.num_statics; i++) { - MSG_WriteByte (&buf,svc_spawnbaseline); - MSG_WriteEntity (&buf, i); + ent = &cl_static_entities[i].ent; - MSG_WriteByte (&buf, es->modelindex); - MSG_WriteByte (&buf, es->frame); - MSG_WriteByte (&buf, es->colormap); - MSG_WriteByte (&buf, es->skinnum); + MSG_WriteByte (&buf, svc_spawnstatic); + + for (j = 1; j < MAX_MODELS; j++) + if (ent->model == cl.model_precache[j]) + break; + if (j == MAX_MODELS) + MSG_WriteByte (&buf, 0); + else + MSG_WriteByte (&buf, j); + + MSG_WriteByte (&buf, ent->framestate.g[FS_REG].frame[0]); + MSG_WriteByte (&buf, 0); + MSG_WriteByte (&buf, ent->skinnum); for (j=0 ; j<3 ; j++) { - MSG_WriteCoord(&buf, es->origin[j]); - MSG_WriteAngle(&buf, es->angles[j]); + MSG_WriteCoord (&buf, ent->origin[j]); + MSG_WriteAngle (&buf, ent->angles[j]); } if (buf.cursize > MAX_QWMSGLEN/2) @@ -1311,114 +1296,151 @@ void CL_Record_f (void) SZ_Clear (&buf); } } - } - MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va("cmd spawn %i\n", cl.servercount) ); + // spawnstaticsound + // static sounds are skipped in demos, life is hard - if (buf.cursize) - { - CL_WriteRecordDemoMessage (&buf, seq++); - SZ_Clear (&buf); - } + // baselines -// send current status of all other players - - for (i = 0; i < cl.allocated_client_slots; i++) - { - player = cl.players + i; - - if (player->frags != 0) + for (i = 0; i < cl_baselines_count; i++) { - MSG_WriteByte (&buf, svc_updatefrags); - MSG_WriteByte (&buf, i); - MSG_WriteShort (&buf, player->frags); + es = cl_baselines + i; + + if (memcmp(es, &nullentitystate, sizeof(nullentitystate))) + { + MSG_WriteByte (&buf,svc_spawnbaseline); + MSG_WriteEntity (&buf, i); + + MSG_WriteByte (&buf, es->modelindex); + MSG_WriteByte (&buf, es->frame); + MSG_WriteByte (&buf, es->colormap); + MSG_WriteByte (&buf, es->skinnum); + for (j=0 ; j<3 ; j++) + { + MSG_WriteCoord(&buf, es->origin[j]); + MSG_WriteAngle(&buf, es->angles[j]); + } + + if (buf.cursize > MAX_QWMSGLEN/2) + { + CL_WriteRecordDemoMessage (&buf, seq++); + SZ_Clear (&buf); + } + } } - if (player->ping != 0) - { - MSG_WriteByte (&buf, svc_updateping); - MSG_WriteByte (&buf, i); - MSG_WriteShort (&buf, player->ping); - } + MSG_WriteByte (&buf, svc_stufftext); + MSG_WriteString (&buf, va("cmd spawn %i\n", cl.servercount) ); - if (player->pl != 0) - { - MSG_WriteByte (&buf, svc_updatepl); - MSG_WriteByte (&buf, i); - MSG_WriteByte (&buf, player->pl); - } - - if (*player->userinfo) - { - MSG_WriteByte (&buf, svc_updateentertime); - MSG_WriteByte (&buf, i); - MSG_WriteFloat (&buf, player->entertime); - } - - if (*player->userinfo) - { - MSG_WriteByte (&buf, svc_updateuserinfo); - MSG_WriteByte (&buf, i); - MSG_WriteLong (&buf, player->userid); - MSG_WriteString (&buf, player->userinfo); - } - - if (buf.cursize > MAX_QWMSGLEN/2) + if (buf.cursize) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } - } -// send all current light styles - for (i=0 ; i= MAX_STANDARDLIGHTSTYLES) - if (!*cl_lightstyle[i].map) - continue; + // send current status of all other players + + for (i = 0; i < cl.allocated_client_slots; i++) + { + player = cl.players + i; + + if (player->frags != 0) + { + MSG_WriteByte (&buf, svc_updatefrags); + MSG_WriteByte (&buf, i); + MSG_WriteShort (&buf, player->frags); + } + + if (player->ping != 0) + { + MSG_WriteByte (&buf, svc_updateping); + MSG_WriteByte (&buf, i); + MSG_WriteShort (&buf, player->ping); + } + + if (player->pl != 0) + { + MSG_WriteByte (&buf, svc_updatepl); + MSG_WriteByte (&buf, i); + MSG_WriteByte (&buf, player->pl); + } + + if (*player->userinfo) + { + MSG_WriteByte (&buf, svc_updateentertime); + MSG_WriteByte (&buf, i); + MSG_WriteFloat (&buf, player->entertime); + } + + if (*player->userinfo) + { + MSG_WriteByte (&buf, svc_updateuserinfo); + MSG_WriteByte (&buf, i); + MSG_WriteLong (&buf, player->userid); + MSG_WriteString (&buf, player->userinfo); + } + + if (buf.cursize > MAX_QWMSGLEN/2) + { + CL_WriteRecordDemoMessage (&buf, seq++); + SZ_Clear (&buf); + } + } + + // send all current light styles + for (i=0 ; i= MAX_STANDARDLIGHTSTYLES) + if (!*cl_lightstyle[i].map) + continue; #ifdef PEXT_LIGHTSTYLECOL - if ((cls.fteprotocolextensions & PEXT_LIGHTSTYLECOL) && cl_lightstyle[i].colour!=7 && *cl_lightstyle[i].map) - { - MSG_WriteByte (&buf, svcfte_lightstylecol); - MSG_WriteByte (&buf, (unsigned char)i); - MSG_WriteByte (&buf, cl_lightstyle[i].colour); - MSG_WriteString (&buf, cl_lightstyle[i].map); - } - else + if ((cls.fteprotocolextensions & PEXT_LIGHTSTYLECOL) && cl_lightstyle[i].colour!=7 && *cl_lightstyle[i].map) + { + MSG_WriteByte (&buf, svcfte_lightstylecol); + MSG_WriteByte (&buf, (unsigned char)i); + MSG_WriteByte (&buf, cl_lightstyle[i].colour); + MSG_WriteString (&buf, cl_lightstyle[i].map); + } + else #endif - { - MSG_WriteByte (&buf, svc_lightstyle); - MSG_WriteByte (&buf, (unsigned char)i); - MSG_WriteString (&buf, cl_lightstyle[i].map); + { + MSG_WriteByte (&buf, svc_lightstyle); + MSG_WriteByte (&buf, (unsigned char)i); + MSG_WriteString (&buf, cl_lightstyle[i].map); + } } - } - for (i = ((cls.fteprotocolextensions&PEXT_HEXEN2)?MAX_QW_STATS:MAX_CL_STATS); i >= 0; i--) - { - if (!cl.playerview[0].stats[i]) - continue; - MSG_WriteByte (&buf, svcqw_updatestatlong); - MSG_WriteByte (&buf, i); - MSG_WriteLong (&buf, cl.playerview[0].stats[i]); - if (buf.cursize > MAX_QWMSGLEN/2) + for (i = ((cls.fteprotocolextensions&PEXT_HEXEN2)?MAX_QW_STATS:MAX_CL_STATS); i >= 0; i--) { - CL_WriteRecordDemoMessage (&buf, seq++); - SZ_Clear (&buf); + if (!cl.playerview[0].stats[i]) + continue; + MSG_WriteByte (&buf, svcqw_updatestatlong); + MSG_WriteByte (&buf, i); + MSG_WriteLong (&buf, cl.playerview[0].stats[i]); + if (buf.cursize > MAX_QWMSGLEN/2) + { + CL_WriteRecordDemoMessage (&buf, seq++); + SZ_Clear (&buf); + } } + + // get the client to check and download skins + // when that is completed, a begin command will be issued + MSG_WriteByte (&buf, svc_stufftext); + MSG_WriteString (&buf, va("skins\n") ); + + CL_WriteRecordDemoMessage (&buf, seq++); + + CL_WriteSetDemoMessage(); + + // done + break; + default: + Con_Printf("Unable to begin demo recording with this network protocol\n"); + CL_Stop_f(); + break; } - - // get the client to check and download skins - // when that is completed, a begin command will be issued - MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va("skins\n") ); - - CL_WriteRecordDemoMessage (&buf, seq++); - - CL_WriteSetDemoMessage(); - - // done } /* diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index f89602f89..8d9ba75d4 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -59,6 +59,7 @@ static struct predicted_player static void CL_LerpNetFrameState(int fsanim, framestate_t *fs, lerpents_t *le); qboolean CL_PredictPlayer(lerpents_t *le, entity_state_t *state, int sequence); void CL_PlayerFrameUpdated(player_state_t *plstate, entity_state_t *state, int sequence); +void CL_AckedInputFrame(int seq, qboolean worldstateokay); extern int cl_playerindex, cl_h_playerindex, cl_rocketindex, cl_grenadeindex, cl_gib1index, cl_gib2index, cl_gib3index; @@ -737,8 +738,8 @@ void CLFTE_ParseEntities(void) else if (cls.protocol == CP_NETQUAKE) { int i; - for (i = 0; i < MAX_SPLITS; i++) - cl.playerview[i].fixangle = false; + if (cls.demoplayback) + cls.netchan.incoming_unreliable++; //demo playback has no sequence info... cls.netchan.incoming_sequence = cls.netchan.incoming_unreliable; cl.last_servermessage = realtime; if (cls.fteprotocolextensions2 & PEXT2_PREDINFO) @@ -753,6 +754,18 @@ void CLFTE_ParseEntities(void) cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK].receivedtime = realtime; + { + extern vec3_t demoangles; + int fr = cls.netchan.incoming_sequence&UPDATE_MASK; + for (i = 0; i < MAX_SPLITS; i++) + cl.inframes[fr&UPDATE_MASK].packet_entities.fixangles[i] = false; + if (cls.demoplayback) + { + cl.inframes[fr&UPDATE_MASK].packet_entities.fixangles[0] = 2; + VectorCopy(demoangles, cl.inframes[fr&UPDATE_MASK].packet_entities.fixedangles[0]); + } + } + // if (cl.validsequence != cls.netchan.incoming_sequence-1) // Con_Printf("CLIENT: Dropped a frame\n"); } @@ -885,13 +898,15 @@ void CLFTE_ParseEntities(void) { cl.oldvalidsequence = cl.validsequence; cl.validsequence = cls.netchan.incoming_sequence; - cl.ackedmovesequence = inputframe; + CL_AckedInputFrame(inputframe, true); cl.inframes[newpacket].invalid = false; } else { newp->num_entities = 0; cl.validsequence = 0; + + CL_AckedInputFrame(inputframe, false); } } @@ -978,9 +993,10 @@ void CLQW_ParsePacketEntities (qboolean delta) full = true; } + //FIXME cl.oldvalidsequence = cl.validsequence; cl.validsequence = cls.netchan.incoming_sequence; - cl.ackedmovesequence = cl.validsequence; + CL_AckedInputFrame(cls.netchan.incoming_sequence, true); oldindex = 0; newindex = 0; @@ -1293,12 +1309,14 @@ void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o( int oldi, newi, lowesti, lowestv, newremaining; qboolean remove; + //server->client sequence if (cl.numackframes == sizeof(cl.ackframes)/sizeof(cl.ackframes[0])) cl.numackframes--; cl.ackframes[cl.numackframes++] = MSG_ReadLong(); /*server sequence to be acked*/ + //client->server sequence ack if (cls.protocol_nq >= CPNQ_DP7) - cl.ackedmovesequence = MSG_ReadLong(); /*client input sequence which has been acked*/ + CL_AckedInputFrame(MSG_ReadLong(), true); /*client input sequence which has been acked*/ cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].receivedtime = realtime; pack = &cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].packet_entities; @@ -2713,7 +2731,7 @@ void R_FlameTrail(vec3_t start, vec3_t end, float seperation); /* Interpolates the two packets by the given time, writes its results into the lerpentities array. */ -static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newpack, packet_entities_t *oldpack, float servertime) +static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newpack, packet_entities_t *oldpack, float frac, float servertime) { lerpents_t *le; entity_state_t *snew, *sold; @@ -2724,7 +2742,6 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp float a1, a2; - float frac; /* seeing as how dropped packets cannot be filled in due to the reliable networking stuff, We can simply detect changes and lerp towards them @@ -2734,11 +2751,6 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp //we figure out which ones are new, //we don't care about old, as our caller will use the lerpents array we fill, and the entity numbers from the 'new' packet. - if (newpack->servertime == oldpack->servertime) - frac = 1; //lerp totally into the new - else - frac = (servertime-oldpack->servertime)/(newpack->servertime-oldpack->servertime); - cl.lerpentssequence = newsequence; oldpnum=0; @@ -2953,7 +2965,7 @@ void CL_TransitionEntities (void) packet_entities_t *packnew, *packold; int newf, newff, oldf; qboolean nolerp; - float servertime; + float servertime, frac; if (cls.protocol == CP_QUAKEWORLD && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) { @@ -2982,13 +2994,19 @@ void CL_TransitionEntities (void) /*transition the ents and stuff*/ packnew = &cl.inframes[newf].packet_entities; packold = &cl.inframes[oldf].packet_entities; + if (packnew->servertime == packold->servertime) + frac = 1; //lerp totally into the new + else + frac = (servertime-packold->servertime)/(packnew->servertime-packold->servertime); -// Con_Printf("%f %f %f (%i)\n", packold->servertime, servertime, packnew->servertime, newff); +// Con_Printf("%f %f %f (%f) (%i)\n", packold->servertime, servertime, packnew->servertime, frac, newff); // Con_Printf("%f %f %f\n", cl.oldgametime, servertime, cl.gametime); - CL_TransitionPacketEntities(newff, packnew, packold, servertime); + CL_TransitionPacketEntities(newff, packnew, packold, frac, servertime); + cl.packfrac = frac; cl.currentpacktime = servertime; cl.currentpackentities = packnew; + cl.previouspackentities = packold; /*and transition players too*/ @@ -2998,7 +3016,7 @@ void CL_TransitionEntities (void) vec3_t move; lerpents_t *le; player_state_t *pnew, *pold; - if (!cl_lerp_players.ival && !(cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) + if (!cl.do_lerp_players) { newf = newff = oldf = cl.parsecount; newf&=UPDATE_MASK; @@ -3966,7 +3984,7 @@ guess_pm_type: } } - if (cl.worldmodel && cl_lerp_players.ival) + if (cl.worldmodel && cl.do_lerp_players) { player_state_t exact; msec += cls.latency*1000; @@ -4316,7 +4334,7 @@ void CL_LinkPlayers (void) if (pnum < cl.splitclients) { //this is a local player } - else if (cl_lerp_players.ival || (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV)) + else if (cl.do_lerp_players) { lerpents_t *le = &cl.lerpplayers[j]; VectorCopy (le->origin, ent->origin); diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index b1839624b..a23e7e2c0 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -610,6 +610,12 @@ void CL_ClampPitch (int pnum) static float oldtime; float timestep = realtime - oldtime; oldtime = realtime; + + if (cl.intermission) + { + memset(cl.playerview[pnum].viewanglechange, 0, sizeof(cl.playerview[pnum].viewanglechange)); + return; + } #if 0 if (cl.pmovetype[pnum] == PM_WALLWALK) { @@ -650,7 +656,7 @@ void CL_ClampPitch (int pnum) } #endif #if 1 - if ((cl.playerview[pnum].gravitydir[2] != -1 || cl.playerview[pnum].viewangles[2]) && !cl.playerview[pnum].fixangles && !cl.intermission) + if ((cl.playerview[pnum].gravitydir[2] != -1 || cl.playerview[pnum].viewangles[2])) { float surfm[16], invsurfm[16]; float viewm[16]; @@ -769,8 +775,6 @@ void CL_ClampPitch (int pnum) else #endif { - if (cl.playerview[pnum].fixangle) - return; if (cl.playerview[pnum].viewangles[PITCH] > cl.maxpitch) cl.playerview[pnum].viewangles[PITCH] = cl.maxpitch; if (cl.playerview[pnum].viewangles[PITCH] < cl.minpitch) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 97380cfb1..0521f3ae2 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -630,10 +630,13 @@ void CL_CheckForResend (void) char data[2048]; double t1, t2; int contype = 0; + unsigned int pext1, pext2; #ifndef CLIENTONLY if (!cls.state && sv.state) { + pext1 = 0; + pext2 = 0; Q_strncpyz (cls.servername, "internalserver", sizeof(cls.servername)); Cvar_ForceSet(&cl_servername, cls.servername); @@ -642,17 +645,27 @@ void CL_CheckForResend (void) { #ifdef Q3CLIENT case GT_QUAKE3: + pext1 = 0; + pext2 = 0; cls.protocol = CP_QUAKE3; break; #endif #ifdef Q2CLIENT case GT_QUAKE2: + pext1 = 0; + pext2 = 0; cls.protocol = CP_QUAKE2; break; #endif default: cl.movesequence = 0; if (!strcmp(cl_loopbackprotocol.string, "qw")) + { + pext1 = Net_PextMask(1, false); + pext2 = Net_PextMask(2, false); + cls.protocol = CP_QUAKEWORLD; + } + else if (!strcmp(cl_loopbackprotocol.string, "idqw")) cls.protocol = CP_QUAKEWORLD; else if (!strcmp(cl_loopbackprotocol.string, "fitz")) //actually proquake, because we might as well use the extra angles { @@ -682,9 +695,26 @@ void CL_CheckForResend (void) cls.protocol_nq = CPNQ_DP7; } else if (progstype == PROG_QW) + { cls.protocol = CP_QUAKEWORLD; + pext1 = Net_PextMask(1, false); + pext2 = Net_PextMask(2, false); + } else cls.protocol = CP_NETQUAKE; + + //make sure the protocol within demos is actually correct/sane + if (cls.demorecording == 1 && cls.protocol != CP_QUAKEWORLD) + { + cls.protocol = CP_QUAKEWORLD; + pext1 = Net_PextMask(1, false); + pext2 = Net_PextMask(2, false); + } + else if (cls.demorecording == 2 && cls.protocol != CP_NETQUAKE) + { + cls.protocol = CP_NETQUAKE; + cls.protocol_nq = CPNQ_FITZ666; + } break; } @@ -701,7 +731,7 @@ void CL_CheckForResend (void) } NET_AdrToString(data, sizeof(data), &adr); - /*eat up the server's packets, to clear any lingering loopback packets*/ + /*eat up the server's packets, to clear any lingering loopback packets (like disconnect commands... yes this might cause packetloss for other clients)*/ while(NET_GetPacket (NS_SERVER, 0) >= 0) { } @@ -733,7 +763,7 @@ void CL_CheckForResend (void) CL_ConnectToDarkPlaces("", &adr); } else - CL_SendConnectPacket (8192-16, Net_PextMask(1, false), Net_PextMask(2, false), false); + CL_SendConnectPacket (8192-16, pext1, pext2, false); return; } #endif @@ -2686,7 +2716,7 @@ void CLNQ_ConnectionlessPacket(void) #endif void CL_MVDUpdateSpectator (void); -void CL_WriteDemoMessage (sizebuf_t *msg); +void CL_WriteDemoMessage (sizebuf_t *msg, int payloadoffset); /* ================= CL_ReadPackets @@ -2776,6 +2806,7 @@ void CL_ReadPackets (void) // cls.netchan.incoming_sequence = cls.netchan.outgoing_sequence - 3; case NQP_RELIABLE://reliable MSG_ChangePrimitives(cls.netchan.netprim); + CL_WriteDemoMessage (&net_message, msg_readcount); CLNQ_ParseServerMessage (); break; } @@ -2805,7 +2836,7 @@ void CL_ReadPackets (void) else if (!Netchan_Process(&cls.netchan)) continue; // wasn't accepted for some reason - CL_WriteDemoMessage (&net_message); + CL_WriteDemoMessage (&net_message, msg_readcount); if (cls.netchan.incoming_sequence > cls.netchan.outgoing_sequence) { //server should not be responding to packets we have not sent yet @@ -4103,6 +4134,7 @@ double Host_Frame (double time) CL_UseIndepPhysics(!!cl_threadedphysics.ival); + cl.do_lerp_players = cl_lerp_players.ival || (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || (cls.demoplayback && !cl_nolerp.ival); CL_AllowIndependantSendCmd(false); // fetch results from server diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 5f6bd5546..8310eac27 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -210,21 +210,21 @@ char *svc_nqstrings[] = "nqsvc_sellscreen", "nqsvc_cutscene", //34 - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", //40 - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", - "NEW PROTOCOL", + "NEW PROTOCOL", //35 + "NEW PROTOCOL", //36 + "fitzsvc_skybox", //37 + "NEW PROTOCOL", //38 + "NEW PROTOCOL", //39 + "fitzsvc_bf", //40 + "fitzsvc_fog", //41 + "fitzsvc_spawnbaseline2", //42 + "fitzsvc_spawnstatic2", //43 + "fitzsvc_spawnstaticsound2", //44 + "NEW PROTOCOL", //45 + "NEW PROTOCOL", //46 + "NEW PROTOCOL", //47 + "NEW PROTOCOL", //48 + "NEW PROTOCOL", //49 "dpsvc_downloaddata", //50 "dpsvc_updatestatubyte", //51 "dpsvc_effect", //52 @@ -238,33 +238,32 @@ char *svc_nqstrings[] = "dpsvc_trailparticles", //60 "dpsvc_pointparticles", //61 "dpsvc_pointparticles1", //62 - "NEW PROTOCOL(63)", - "NEW PROTOCOL(64)", - "NEW PROTOCOL(65)", - "nqsvcfte_spawnbaseline2(66)", //66 - "NEW PROTOCOL(67)", - "NEW PROTOCOL(68)", - "NEW PROTOCOL(69)", - "NEW PROTOCOL(70)", - "NEW PROTOCOL(71)", - "NEW PROTOCOL(72)", - "NEW PROTOCOL(73)", - "NEW PROTOCOL(74)", - "NEW PROTOCOL(75)", - "NEW PROTOCOL(76)", - "NEW PROTOCOL(77)", - "NEW PROTOCOL(78)", - "NEW PROTOCOL(79)", - "NEW PROTOCOL(80)", - "NEW PROTOCOL(81)", - "NEW PROTOCOL(82)", - "NEW PROTOCOL(83)", - "NEW PROTOCOL(84)", - "NEW PROTOCOL(85)", - "nqsvcfte_updateentities(86)", - "NEW PROTOCOL(87)", - "NEW PROTOCOL(88)", - + "NEW PROTOCOL(63)", //63 + "NEW PROTOCOL(64)", //64 + "NEW PROTOCOL(65)", //65 + "ftenqsvc_spawnbaseline2", //66 + "NEW PROTOCOL(67)", //67 + "NEW PROTOCOL(68)", //68 + "NEW PROTOCOL(69)", //69 + "NEW PROTOCOL(70)", //70 + "NEW PROTOCOL(71)", //71 + "NEW PROTOCOL(72)", //72 + "NEW PROTOCOL(73)", //73 + "NEW PROTOCOL(74)", //74 + "NEW PROTOCOL(75)", //75 + "NEW PROTOCOL(76)", //76 + "NEW PROTOCOL(77)", //77 + "NEW PROTOCOL(78)", //78 + "NEW PROTOCOL(79)", //79 + "NEW PROTOCOL(80)", //80 + "NEW PROTOCOL(81)", //81 + "NEW PROTOCOL(82)", //82 + "NEW PROTOCOL(83)", //83 + "NEW PROTOCOL(84)", //84 + "NEW PROTOCOL(85)", //85 + "nqsvcfte_updateentities", //86 + "NEW PROTOCOL(87)", //87 + "NEW PROTOCOL(88)" //88 }; extern cvar_t requiredownloads, cl_standardchat, msg_filter, cl_countpendingpl, cl_download_mapsrc; @@ -324,12 +323,12 @@ int CL_CalcNet (void) sent = NET_TIMINGS; - for (i=cls.netchan.outgoing_sequence-UPDATE_BACKUP+1 - ; i <= cls.netchan.outgoing_sequence + for (i=cl.movesequence-UPDATE_BACKUP+1 + ; i <= cl.movesequence ; i++) { frame = &cl.inframes[i&UPDATE_MASK]; - if (i > cl.parsecount) + if (i > cl.lastackedmovesequence) { // no response yet if (cl_countpendingpl.ival) @@ -366,6 +365,42 @@ int CL_CalcNet (void) return percent; } +void CL_AckedInputFrame(int seq, qboolean worldstateokay) +{ + unsigned int i; + unsigned int newmod; + inframe_t *frame; + + newmod = seq & UPDATE_MASK; + frame = &cl.inframes[newmod]; +// calculate latency + frame->latency = realtime - cl.outframes[newmod].senttime; + if (frame->latency < 0 || frame->latency > 1.0) + { +// Con_Printf ("Odd latency: %5.2f\n", latency); + } + else + { + // drift the average latency towards the observed latency + if (frame->latency < cls.latency) + cls.latency = frame->latency; + else + cls.latency += 0.001; // drift up, so correction are needed + } + + //and mark any missing ones as dropped + if (seq != cl.lastackedmovesequence) + { + for (i = (cl.lastackedmovesequence+1) & UPDATE_MASK; i != newmod; i=(i+1)&UPDATE_MASK) + { + cl.inframes[i].latency = -1; + } + } + if (worldstateokay) + cl.ackedmovesequence = seq; + cl.lastackedmovesequence = seq; +} + //============================================================================= //note: this will overwrite existing files. @@ -2729,21 +2764,10 @@ void CL_ParseEstablished(void) } #ifdef NQPROT -//FIXME: move to header -void CL_KeepaliveMessage(void){} -void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution. +void CLNQ_ParseProtoVersion(void) { - int nummodels, numsounds; - char *str; - int gametype; int protover; struct netprim_s netprim; - if (developer.ival) - Con_TPrintf (TLC_GOTSVDATAPACKET); - SCR_SetLoadingStage(LS_CLIENT); - CL_ClearState (); - Stats_NewMap(); - Cvar_ForceCallback(Cvar_FindVar("r_particlesdesc")); cls.fteprotocolextensions = 0; cls.fteprotocolextensions2 = 0; @@ -2848,6 +2872,23 @@ void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution. } cls.netchan.message.prim = cls.netchan.netprim = netprim; MSG_ChangePrimitives(netprim); +} + +//FIXME: move to header +void CL_KeepaliveMessage(void){} +void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution. +{ + int nummodels, numsounds; + char *str; + int gametype; + if (developer.ival) + Con_TPrintf (TLC_GOTSVDATAPACKET); + SCR_SetLoadingStage(LS_CLIENT); + CL_ClearState (); + Stats_NewMap(); + Cvar_ForceCallback(Cvar_FindVar("r_particlesdesc")); + + CLNQ_ParseProtoVersion(); if (MSG_ReadByte() > MAX_CLIENTS) { @@ -3575,14 +3616,22 @@ void CL_ParseStatic (int version) entity_state_t es; vec3_t mins,maxs; - if (version == 1) + if (version == 3) { + CLFitz_ParseBaseline2(&es); + i = cl.num_statics; + cl.num_statics++; + } + else if (version == 1) + { + //old nq/qw style CL_ParseBaseline (&es); i = cl.num_statics; cl.num_statics++; } - else + else if (version == 2) { + //new deltaed style ('full' extension support) if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) CLFTE_ParseBaseline(&es, false); else @@ -3605,6 +3654,8 @@ void CL_ParseStatic (int version) cl.num_statics++; } } + else + return; if (i == cl_max_static_entities) { @@ -3926,13 +3977,14 @@ Server information pertaining to this client only, sent every frame void CL_ParseClientdata (void) { int i; - inframe_t *frame; // calculate simulated time of message oldparsecountmod = parsecountmod; i = cls.netchan.incoming_acknowledged; - if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) + if (cls.demoplayback == DPB_NETQUAKE) + i = cls.netchan.incoming_sequence-1; + if (cls.demoplayback == DPB_NETQUAKE || cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) { cl.oldparsecount = i - 1; oldparsecountmod = cl.oldparsecount & UPDATE_MASK; @@ -3940,32 +3992,10 @@ void CL_ParseClientdata (void) cl.parsecount = i; i &= UPDATE_MASK; parsecountmod = i; - - frame = &cl.inframes[i]; -// if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) -// frame->senttime = realtime - host_frametime; parsecounttime = cl.outframes[i].senttime; -// calculate latency - frame->latency = realtime - parsecounttime; - //and mark any missing ones as dropped - for (i = (oldparsecountmod+1)&UPDATE_MASK; i != parsecountmod; i=((i+1)&UPDATE_MASK)) - { - cl.inframes[i].latency = -1; - } - - if (frame->latency < 0 || frame->latency > 1.0) - { -// Con_Printf ("Odd latency: %5.2f\n", latency); - } - else - { - // drift the average latency towards the observed latency - if (frame->latency < cls.latency) - cls.latency = frame->latency; - else - cls.latency += 0.001; // drift up, so correction are needed - } + if (cls.protocol == CP_QUAKEWORLD) + CL_AckedInputFrame(cl.parsecount, false); } /* @@ -4211,11 +4241,49 @@ static void CL_SetStat_Internal (int pnum, int stat, int value) } cl.playerview[pnum].stats[stat] = value; + cl.playerview[pnum].statsf[stat] = value; if (pnum == 0) TP_StatChanged(stat, value); } +void CL_SetStatMovevar(int pnum, int stat, float value) +{ + switch(stat) + { + case STAT_MOVEVARS_GRAVITY: + movevars.gravity = value; + break; + case STAT_MOVEVARS_STOPSPEED: + movevars.stopspeed = value; + break; + case STAT_MOVEVARS_MAXSPEED: + cl.playerview[pnum].maxspeed = value; + break; + case STAT_MOVEVARS_SPECTATORMAXSPEED: + movevars.spectatormaxspeed = value; + break; + case STAT_MOVEVARS_ACCELERATE: + movevars.accelerate = value; + break; + case STAT_MOVEVARS_AIRACCELERATE: + movevars.airaccelerate = value; + break; + case STAT_MOVEVARS_WATERACCELERATE: + movevars.wateraccelerate = value; + break; + case STAT_MOVEVARS_FRICTION: + movevars.friction = value; + break; + case STAT_MOVEVARS_WATERFRICTION: + movevars.waterfriction = value; + break; + case STAT_MOVEVARS_ENTGRAVITY: + cl.playerview[pnum].entgravity = value; + break; + } +} + void CL_SetStatInt (int pnum, int stat, int value) { if (stat < 0 || stat >= MAX_CL_STATS) @@ -4235,6 +4303,7 @@ void CL_SetStatInt (int pnum, int stat, int value) { extern int cls_lastto; cl.players[cls_lastto].stats[stat]=value; + cl.players[cls_lastto].statsf[stat]=value; for (pnum = 0; pnum < cl.splitclients; pnum++) if (cl.playerview[pnum].cam_spec_track == cls_lastto) @@ -4242,6 +4311,9 @@ void CL_SetStatInt (int pnum, int stat, int value) } else CL_SetStat_Internal(pnum, stat, value); + + if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO)) + CL_SetStatMovevar(pnum, stat, *(float*)&value); //DP sucks. } void CL_SetStatFloat (int pnum, int stat, float value) { @@ -4253,16 +4325,26 @@ void CL_SetStatFloat (int pnum, int stat, float value) { extern int cls_lastto; cl.players[cls_lastto].statsf[stat]=value; + cl.players[cls_lastto].stats[stat]=value; for (pnum = 0; pnum < cl.splitclients; pnum++) if (cl.playerview[pnum].cam_spec_track == cls_lastto) + { cl.playerview[pnum].statsf[stat] = value; + cl.playerview[pnum].stats[stat] = value; + } } else + { cl.playerview[pnum].statsf[stat] = value; + cl.playerview[pnum].stats[stat] = value; + } if (stat == STAT_VIEWHEIGHT && cls.z_ext & Z_EXT_VIEWHEIGHT) cl.playerview[pnum].viewheight = value; + + if (cls.fteprotocolextensions2 & PEXT2_PREDINFO) + CL_SetStatMovevar(pnum, stat, value); } void CL_SetStatString (int pnum, int stat, char *value) { @@ -5258,12 +5340,22 @@ void CLQW_ParseServerMessage (void) int destsplit; float f; qboolean csqcpacket = false; + inframe_t *inf; + extern vec3_t demoangles; received_framecount = host_framecount; cl.last_servermessage = realtime; CL_ClearProjectiles (); - for (i = 0; i < MAX_SPLITS; i++) - cl.playerview[i].fixangle = false; + + //clear out fixangles stuff + inf = &cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK]; + for (j = 0; j < MAX_SPLITS; j++) + inf->packet_entities.fixangles[j] = false; + if (cls.demoplayback == DPB_QUAKEWORLD) + { + inf->packet_entities.fixangles[0] = 2; + VectorCopy(demoangles, inf->packet_entities.fixedangles[0]); + } // // if recording demos, copy the message out @@ -5411,11 +5503,12 @@ void CLQW_ParseServerMessage (void) case svcfte_setangledelta: for (i=0 ; i<3 ; i++) cl.playerview[destsplit].viewangles[i] += MSG_ReadAngle16 (); - VectorCopy (cl.playerview[destsplit].viewangles, cl.playerview[destsplit].simangles); +// VectorCopy (cl.playerview[destsplit].viewangles, cl.playerview[destsplit].simangles); break; case svc_setangle: if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) { + //I really don't get the point of fixangles in an mvd. to disable interpolation for that frame? vec3_t ang; i = MSG_ReadByte(); for (i=0 ; i<3 ; i++) @@ -5425,20 +5518,17 @@ void CLQW_ParseServerMessage (void) playerview_t *pv = &cl.playerview[j]; if (Cam_TrackNum(pv) == i) { - pv->fixangle=true; - VectorCopy(ang, pv->simangles); - VectorCopy(ang, pv->viewangles); - VectorCopy(ang, pv->fixangles); + inf->packet_entities.fixangles[j] = true; + VectorCopy(ang, inf->packet_entities.fixedangles[j]); } } break; } - cl.playerview[destsplit].fixangle=true; + inf->packet_entities.fixangles[destsplit] = true; for (i=0 ; i<3 ; i++) - cl.playerview[destsplit].viewangles[i] = cl.playerview[destsplit].fixangles[i] = MSG_ReadAngle (); - - VectorCopy (cl.playerview[destsplit].viewangles, cl.playerview[destsplit].simangles); -// cl.playerview[destsplit].viewangles[PITCH] = cl.viewangles[ROLL] = 0; + { + cl.playerview[destsplit].viewangles[i] = cl.playerview[destsplit].intermissionangles[i] = inf->packet_entities.fixedangles[destsplit][i] = MSG_ReadAngle (); + } break; case svc_lightstyle: @@ -5604,16 +5694,16 @@ void CLQW_ParseServerMessage (void) for (i=0 ; i<3 ; i++) cl.playerview[destsplit].simorg[i] = MSG_ReadCoord (); for (i=0 ; i<3 ; i++) - cl.playerview[destsplit].simangles[i] = MSG_ReadAngle (); - VectorCopy (cl.playerview[destsplit].simangles, cl.playerview[destsplit].fixangles); - VectorClear (cl.playerview[destsplit].simvel); + cl.playerview[destsplit].intermissionangles[i] = MSG_ReadAngle (); break; case svc_finale: if (!cl.intermission) + { for (i = 0; i < MAX_SPLITS; i++) cl.playerview[i].simorg[2] += cl.playerview[i].viewheight; - VectorCopy (cl.playerview[destsplit].fixangles, cl.playerview[destsplit].simangles); + VectorCopy (cl.playerview[destsplit].simangles, cl.playerview[destsplit].intermissionangles); + } cl.intermission = 2; cl.completed_time = cl.gametime; @@ -6174,7 +6264,7 @@ void CLNQ_ParseServerMessage (void) case svc_disconnect: CL_Disconnect(); - break; + return; case svc_centerprint: s = MSG_ReadString (); @@ -6222,6 +6312,9 @@ void CLNQ_ParseServerMessage (void) } break; + case svc_version: + CLNQ_ParseProtoVersion(); + break; case svc_serverdata: Cbuf_Execute (); // make sure any stuffed commands are done CLNQ_ParseServerData (); @@ -6301,9 +6394,15 @@ void CLNQ_ParseServerMessage (void) case svc_time: //fixme: move this stuff to a common place - cl.playerview[destsplit].oldfixangle = cl.playerview[destsplit].fixangle; - VectorCopy(cl.playerview[destsplit].fixangles, cl.playerview[destsplit].oldfixangles); - cl.playerview[destsplit].fixangle = false; +// cl.playerview[destsplit].oldfixangle = cl.playerview[destsplit].fixangle; +// VectorCopy(cl.playerview[destsplit].fixangles, cl.playerview[destsplit].oldfixangles); +// cl.playerview[destsplit].fixangle = false; + if (cls.demoplayback) + { +// extern vec3_t demoangles; +// cl.playerview[destsplit].fixangle = true; +// VectorCopy(demoangles, cl.playerview[destsplit].fixangles); + } cls.netchan.outgoing_sequence++; cls.netchan.incoming_sequence = cls.netchan.outgoing_sequence-1; @@ -6317,7 +6416,18 @@ void CLNQ_ParseServerMessage (void) cl.gametime = MSG_ReadFloat(); cl.gametimemark = realtime; - cl.inframes[cl.validsequence&UPDATE_MASK].receivedtime = realtime; + { + extern vec3_t demoangles; + int fr = cls.netchan.incoming_sequence&UPDATE_MASK; + if (cls.demoplayback) + { + cl.inframes[fr&UPDATE_MASK].packet_entities.fixangles[destsplit] = true; + VectorCopy(demoangles, cl.inframes[fr&UPDATE_MASK].packet_entities.fixedangles[destsplit]); + } + else + cl.inframes[fr&UPDATE_MASK].packet_entities.fixangles[destsplit] = false; + } + cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK].receivedtime = realtime; if (CPNQ_IS_DP) { @@ -6409,13 +6519,15 @@ void CLNQ_ParseServerMessage (void) CL_SetStatFloat (0, i, j); break; case svc_setangle: - cl.playerview[destsplit].fixangle=true; - for (i=0 ; i<3 ; i++) - cl.playerview[destsplit].viewangles[i] = cl.playerview[destsplit].fixangles[i] = MSG_ReadAngle (); -// cl.viewangles[PITCH] = cl.viewangles[ROLL] = 0; + { + inframe_t *inf = &cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK]; + inf->packet_entities.fixangles[destsplit] = true; + for (i=0 ; i<3 ; i++) + cl.playerview[destsplit].viewangles[i] = cl.playerview[destsplit].intermissionangles[i] = inf->packet_entities.fixedangles[destsplit][i] = MSG_ReadAngle (); + } break; - case svc_clientdata: + case svcnq_clientdata: CLNQ_ParseClientdata (); break; @@ -6495,10 +6607,12 @@ void CLNQ_ParseServerMessage (void) Host_EndGame("CLNQ_ParseServerMessage: svcfitz_spawnbaseline2 failed with ent %i", i); CLFitz_ParseBaseline2 (cl_baselines + i); break; -// case svcfitz_spawnstatic2: -// break; -// case svcfitz_spawnstaticsound2: -// break; + case svcfitz_spawnstatic2: + CL_ParseStatic (3); + break; + case svcfitz_spawnstaticsound2: + Host_EndGame("svcfitz_spawnstaticsound2: not implemented"); + break; case svcnq_effect: diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 3353c19ba..0ed6b1dd5 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "winquake.h" cvar_t cl_nopred = SCVAR("cl_nopred","0"); -extern cvar_t cl_lerp_players; cvar_t cl_pushlatency = SCVAR("pushlatency","-999"); extern float pm_airaccelerate; @@ -504,7 +503,7 @@ void CL_CalcCrouch (playerview_t *pv, float stepchange) float LerpAngles360(float to, float from, float frac) { - int delta; + float delta; delta = (from-to); if (delta > 180) @@ -636,6 +635,7 @@ short LerpAngles16(short to, short from, float frac) void CL_CalcClientTime(void) { + extern float demtime; if (cls.protocol != CP_QUAKE3) { float oldst = realtime; @@ -670,7 +670,13 @@ void CL_CalcClientTime(void) max = min; if (max) - cl.servertime += host_frametime; + { + extern cvar_t cl_demospeed; + if (cls.demoplayback && cl_demospeed.value >= 0 && cls.state == ca_active) + cl.servertime += host_frametime*cl_demospeed.value; + else + cl.servertime += host_frametime; + } else cl.servertime = 0; @@ -836,6 +842,7 @@ void CL_PlayerFrameUpdated(player_state_t *plstate, entity_state_t *state, int s { cl.playerview[i].stats[STAT_WEAPONFRAME] = state->u.q1.weaponframe; cl.playerview[i].statsf[STAT_WEAPONFRAME] = state->u.q1.weaponframe; + cl.playerview[i].pmovetype = pmtype; } } @@ -908,6 +915,7 @@ void CL_PredictMovePNum (int seat) float *org; float stepheight = 0; float netfps = cl_netfps.value; + if (!netfps) { //every video frame has its own input frame. @@ -951,39 +959,39 @@ void CL_PredictMovePNum (int seat) if (cl.paused && !(cls.demoplayback!=DPB_MVD && cls.demoplayback!=DPB_EZTV) && (!cl.spectator || !pv->cam_auto)) return; - if (cl.intermission==1 && cls.protocol == CP_QUAKEWORLD) - { - pv->crouch = 0; - return; - } - -#ifdef NQPROT - if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO)) - { - cl.ackedmovesequence = cl.movesequence; - } -#endif - if (!cl.validsequence) { return; } - if (cl.movesequence - cl.ackedmovesequence >= UPDATE_BACKUP-1) - { //lagging like poo. - if (!cl.intermission) //keep the angles working though. - VectorCopy (pv->viewangles, pv->simangles); + + if (cl.intermission==1 && cls.protocol == CP_QUAKEWORLD) + { + VectorCopy (pv->intermissionangles, pv->simangles); return; } + else + { + if (cl.currentpackentities && cl.currentpackentities->fixangles[seat]) + { + if (cl.previouspackentities && cl.previouspackentities->fixangles[seat]==cl.currentpackentities->fixangles[seat]) + { + for (i = 0; i < 3; i++) + pv->simangles[i] = LerpAngles360(cl.currentpackentities->fixedangles[seat][i], cl.previouspackentities->fixedangles[seat][i], 1-(cl.previouspackentities->fixangles[seat]?cl.packfrac:1)); + } + else + VectorCopy(cl.currentpackentities->fixedangles[seat], pv->simangles); + } + else + VectorCopy (pv->viewangles, pv->simangles); + } - // this is the last frame received from the server + //don't wrap + if (cl.movesequence - cl.ackedmovesequence >= UPDATE_BACKUP-1) + return; + // this is the last frame received from the server from = &cl.inframes[cl.validsequence & UPDATE_MASK]; cmdfrom = &cl.outframes[cl.ackedmovesequence & UPDATE_MASK]; - if (!cl.intermission) - { - VectorCopy (pv->viewangles, pv->simangles); - } - vel = from->playerstate[pv->playernum].velocity; org = from->playerstate[pv->playernum].origin; @@ -1018,16 +1026,23 @@ void CL_PredictMovePNum (int seat) } - if (((cl_nopred.value && cls.demoplayback!=DPB_MVD && cls.demoplayback != DPB_EZTV)|| pv->fixangle || cl.paused)) + if (((cl_nopred.value && cls.demoplayback!=DPB_MVD && cls.demoplayback != DPB_EZTV) || cl.paused || pv->pmovetype == PM_NONE)) { - if (cl_lerp_players.ival && !cls.demoplayback) + if (cl.do_lerp_players) { - lerpents_t *le; - if (pv->nolocalplayer) - le = &cl.lerpents[pv->cam_spec_track+1]; + lerpents_t *le = NULL; + if (pv->nolocalplayer) + { + if (pv->viewentity < cl.maxlerpents) + le = &cl.lerpents[pv->viewentity]; + } else - le = &cl.lerpplayers[pv->cam_spec_track]; - org = le->origin; + { + if (pv->viewentity >= 1 && pv->viewentity <= MAX_CLIENTS) + le = &cl.lerpplayers[pv->viewentity-1]; + } + if (le) + org = le->origin; vel = vec3_origin; } @@ -1056,7 +1071,7 @@ fixedorg: if (pv->viewentity && pv->viewentity != pv->playernum+1 && CL_MayLerp()) { float f; - if (cl_lerp_players.ival && (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV)) + if (cl.do_lerp_players) { lerpents_t *le = &cl.lerpplayers[pv->cam_spec_track]; org = le->origin; diff --git a/engine/client/client.h b/engine/client/client.h index bc3604883..a07bc3587 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -396,7 +396,7 @@ typedef struct // demo recording info must be here, because record is started before // entering a map (and clearing client_state_t) - qboolean demorecording; + int demorecording; //1=QW, 2=NQ vfsfile_t *demooutfile; enum{DPB_NONE,DPB_QUAKEWORLD,DPB_MVD,DPB_EZTV, @@ -518,8 +518,9 @@ struct playerview_s // the client maintains its own idea of view angles, which are // sent to the server each frame. And only reset at level change // and teleport times - vec3_t viewangles; - vec3_t viewanglechange; + vec3_t viewangles; //current angles + vec3_t viewanglechange; //angles set by input code this frame + vec3_t intermissionangles; //absolute angles for intermission vec3_t gravitydir; // pitch drifting vars @@ -545,10 +546,6 @@ struct playerview_s int waterlevel; //for smartjump float punchangle; // temporary view kick from weapon firing - qboolean fixangle; //received a fixangle - so disable prediction till the next packet. - qboolean oldfixangle; //received a fixangle - so disable prediction till the next packet. - vec3_t fixangles; //received a fixangle - so disable prediction till the next packet. - vec3_t oldfixangles; //received a fixangle - so disable prediction till the next packet. float v_dmg_time; //various view knockbacks. float v_dmg_roll; @@ -601,10 +598,11 @@ typedef struct int oldparsecount; int oldvalidsequence; int ackedmovesequence; //in quakeworld/q2 this is always equal to validsequence. nq can differ. may only be updated when validsequence is updated. + int lastackedmovesequence; //can be higher than ackedmovesequence when the received frame was unusable. int validsequence; // this is the sequence number of the last good // packetentity_t we got. If this is 0, we can't // render a frame yet - int movesequence; // + int movesequence; // client->server frames int spectator; @@ -723,8 +721,12 @@ typedef struct float predicted_step_time; float predicted_step; + //interpolation+snapshots + float packfrac; packet_entities_t *currentpackentities; + packet_entities_t *previouspackentities; float currentpacktime; + qboolean do_lerp_players; int teamplay; @@ -1393,6 +1395,7 @@ void Stats_NewMap(void); enum uploadfmt; typedef struct { + char *drivername; void *(VARGS *createdecoder)(char *name); void *(VARGS *decodeframe)(void *ctx, qboolean nosound, enum uploadfmt *fmt, int *width, int *height); void (VARGS *doneframe)(void *ctx, void *img); @@ -1407,6 +1410,7 @@ typedef struct void (VARGS *changestream) (void *ctx, char *streamname); } media_decoder_funcs_t; typedef struct { + char *drivername; void *(VARGS *capture_begin) (char *streamname, int videorate, int width, int height, int *sndkhz, int *sndchannels, int *sndbits); void (VARGS *capture_video) (void *ctx, void *data, int frame, int width, int height); void (VARGS *capture_audio) (void *ctx, void *data, int bytes); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index bb728f624..f71db73f7 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -484,6 +484,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu range = 0; if (range > 1) range = 1; + option->slider.vx = x; x -= 8; Font_BeginString(font_conchar, x, y, &x, &y); x = Font_DrawChar(x, y, 0xe080 | CON_WHITEMASK); @@ -1252,6 +1253,9 @@ void MC_Slider_Key(menuslider_t *option, int key) float range = option->current; float delta; + float ix = option->vx; + float ex = ix + 10*8; + if (option->smallchange) delta = option->smallchange; else @@ -1263,8 +1267,6 @@ void MC_Slider_Key(menuslider_t *option, int key) if (range < option->min) range = option->min; option->current = range; - if (option->var) - Cvar_SetValue(option->var, range); } else if (key == K_RIGHTARROW || key == K_MWHEELUP) { @@ -1272,8 +1274,12 @@ void MC_Slider_Key(menuslider_t *option, int key) if (range > option->max) range = option->max; option->current = range; - if (option->var) - Cvar_SetValue(option->var, range); + } + else if (key == K_MOUSE1 && mousecursor_x >= ix-8 && mousecursor_x < ex+8) + { + range = (mousecursor_x - ix) / (ex - ix); + range = option->min + range*(option->max-option->min); + option->current = range; } else if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) { @@ -1284,13 +1290,13 @@ void MC_Slider_Key(menuslider_t *option, int key) if (range > option->max) range = option->max; option->current = range; - if (option->var) - Cvar_SetValue(option->var, range); } else return; S_LocalSound ("misc/menu2.wav"); + if (option->var) + Cvar_SetValue(option->var, option->current); } void MC_CheckBox_Key(menucheck_t *option, menu_t *menu, int key) @@ -1370,6 +1376,7 @@ void MC_Combo_Key(menucombo_t *combo, int key) changed: if (combo->cvar && combo->numoptions) Cvar_Set(combo->cvar, (char *)combo->values[combo->selectedoption]); + S_LocalSound ("misc/menu2.wav"); } else if (key == K_LEFTARROW) { diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 5b6529bca..756a9ac8e 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -2488,18 +2488,19 @@ int captureframe; qboolean captureframeforce; qboolean capturepaused; -cvar_t capturerate = SCVAR("capturerate", "30"); +cvar_t capturerate = CVAR("capturerate", "30"); #if defined(WINAVI) -cvar_t capturecodec = SCVAR("capturecodec", "divx"); +cvar_t capturedriver = CVARD("capturedriver", "avi", "The driver to use to capture the demo. avformat can be supported via a plugin.\navi: capture directly to avi (capturecodec should be a fourcc value).\nraw: capture to a series of screenshots."); +cvar_t capturecodec = CVAR("capturecodec", "divx"); #else -cvar_t capturecodec = SCVAR("capturecodec", "tga"); +cvar_t capturedriver = CVARD("capturedriver", "raw", "The driver to use to capture the demo. avformat can be supported via a plugin.\nraw: capture to a series of screenshots."); +cvar_t capturecodec = CVAR("capturecodec", "tga"); #endif -cvar_t capturesound = SCVAR("capturesound", "1"); -cvar_t capturesoundchannels = SCVAR("capturesoundchannels", "1"); -cvar_t capturesoundbits = SCVAR("capturesoundbits", "8"); -cvar_t capturemessage = SCVAR("capturemessage", ""); +cvar_t capturesound = CVAR("capturesound", "1"); +cvar_t capturesoundchannels = CVAR("capturesoundchannels", "1"); +cvar_t capturesoundbits = CVAR("capturesoundbits", "8"); +cvar_t capturemessage = CVAR("capturemessage", ""); qboolean recordingdemo; -media_encoder_funcs_t *capturedriver[8]; media_encoder_funcs_t *currentcapture_funcs; void *currentcapture_ctx; @@ -2509,7 +2510,9 @@ void *currentcapture_ctx; /*screenshot capture*/ struct capture_raw_ctx { + int frames; char videonameprefix[MAX_QPATH]; + char videonameextension[16]; vfsfile_t *audio; }; @@ -2517,6 +2520,11 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width { struct capture_raw_ctx *ctx = Z_Malloc(sizeof(*ctx)); + if (!strcmp(capturecodec.string, "png") || !strcmp(capturecodec.string, "jpeg") || !strcmp(capturecodec.string, "jpg") || !strcmp(capturecodec.string, "bmp") || !strcmp(capturecodec.string, "pcx") || !strcmp(capturecodec.string, "tga")) + Q_strncpyz(ctx->videonameextension, capturecodec.string, sizeof(ctx->videonameextension)); + else + Q_strncpyz(ctx->videonameextension, "tga", sizeof(ctx->videonameextension)); + Q_strncpyz(ctx->videonameprefix, streamname, sizeof(ctx->videonameprefix)); ctx->audio = NULL; if (*sndkhz) @@ -2545,7 +2553,8 @@ static void QDECL capture_raw_video (void *vctx, void *data, int frame, int widt { struct capture_raw_ctx *ctx = vctx; char filename[MAX_OSPATH]; - Q_snprintfz(filename, sizeof(filename), "%s/%8.8i.%s", ctx->videonameprefix, frame, capturecodec.string); + ctx->frames = frame+1; + Q_snprintfz(filename, sizeof(filename), "%s/%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension); SCR_ScreenShot(filename, data, width, height); } static void QDECL capture_raw_audio (void *vctx, void *data, int bytes) @@ -2558,10 +2567,14 @@ static void QDECL capture_raw_audio (void *vctx, void *data, int bytes) static void QDECL capture_raw_end (void *vctx) { struct capture_raw_ctx *ctx = vctx; + if (ctx->audio) + VFS_CLOSE(ctx->audio); + Con_Printf("%d video frames captured\n", ctx->frames); Z_Free(ctx); } static media_encoder_funcs_t capture_raw = { + "raw", capture_raw_begin, capture_raw_video, capture_raw_audio, @@ -2678,7 +2691,7 @@ static void *QDECL capture_avi_begin (char *streamname, int videorate, int width hr = qAVIMakeCompressedStream(&ctx->compressed_video_stream, ctx->uncompressed_video_stream, &opts, NULL); if (FAILED(hr)) { - Con_Printf("Failed to init compressor\n"); + Con_Printf("AVIMakeCompressedStream failed. check codec.\n"); capture_avi_end(ctx); return NULL; } @@ -2688,7 +2701,7 @@ static void *QDECL capture_avi_begin (char *streamname, int videorate, int width hr = qAVIStreamSetFormat(avi_video_stream(ctx), 0, &bitmap_info_header, sizeof(BITMAPINFOHEADER)); if (FAILED(hr)) { - Con_Printf("Failed to set format\n"); + Con_Printf("AVIStreamSetFormat failed\n"); capture_avi_end(ctx); return NULL; } @@ -2716,6 +2729,8 @@ static void *QDECL capture_avi_begin (char *streamname, int videorate, int width stream_header.dwRate = stream_header.dwScale * (unsigned long)ctx->wave_format.nSamplesPerSec; stream_header.dwSampleSize = ctx->wave_format.nBlockAlign; + //FIXME: be prepared to capture audio to mp3. + hr = qAVIFileCreateStreamA(ctx->file, &ctx->uncompressed_audio_stream, &stream_header); if (FAILED(hr)) { @@ -2748,9 +2763,8 @@ static void QDECL capture_avi_video(void *vctx, void *vdata, int frame, int widt data[i+2] = temp; } //write it - Con_Printf("%i - %f\n", frame, realtime); if (FAILED(qAVIStreamWrite(avi_video_stream(ctx), frame, 1, data, width*height * 3, ((frame%15) == 0)?AVIIF_KEYFRAME:0, NULL, NULL))) - Con_Printf("Recoring error\n"); + Con_DPrintf("Recoring error\n"); } static void QDECL capture_avi_audio(void *vctx, void *data, int bytes) @@ -2762,19 +2776,12 @@ static void QDECL capture_avi_audio(void *vctx, void *data, int bytes) static media_encoder_funcs_t capture_avi = { + "avi", capture_avi_begin, capture_avi_video, capture_avi_audio, capture_avi_end }; -#else -media_encoder_funcs_t capture_avi = -{ - NULL, - NULL, - NULL, - NULL -}; #endif @@ -3106,28 +3113,23 @@ void Media_RecordFilm_f (void) capturelastvideotime = realtime = 0; captureframe = 0; - if (*fourcc) - { - if (!strcmp(fourcc, "tga") || - !strcmp(fourcc, "png") || - !strcmp(fourcc, "jpg") || - !strcmp(fourcc, "pcx")) - { - currentcapture_funcs = &capture_raw; - } - else - { - currentcapture_funcs = &capture_avi; - } - } - else - { - currentcapture_funcs = &capture_avi; - } - for (i = 0; i < 8; i++) + for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++) { if (pluginencodersfunc[i]) - currentcapture_funcs = pluginencodersfunc[i]; + if (!strcmp(pluginencodersfunc[i]->drivername, capturedriver.string)) + currentcapture_funcs = pluginencodersfunc[i]; + } + //just use the first + if (!currentcapture_funcs) + { + for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++) + { + if (pluginencodersfunc[i]) + { + currentcapture_funcs = pluginencodersfunc[i]; + break; + } + } } if (capturesound.ival) @@ -3900,6 +3902,7 @@ void Media_Init(void) Cvar_Register(&capturemessage, "AVI capture controls"); Cvar_Register(&capturesound, "AVI capture controls"); Cvar_Register(&capturerate, "AVI capture controls"); + Cvar_Register(&capturedriver, "AVI capture controls"); Cvar_Register(&capturecodec, "AVI capture controls"); #if defined(WINAVI) diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 348e0edfb..ed25b786a 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -236,12 +236,14 @@ void M_Menu_Audio_Speakers_f (void) menucombo_t *MC_AddCvarCombo(menu_t *menu, int x, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values); void M_Menu_Audio_f (void) { - menu_t *menu; - extern cvar_t nosound, snd_leftisright, snd_khz, snd_speakers, ambient_level, bgmvolume, snd_playersoundvolume, ambient_fade, cl_staticsounds, snd_inactive, _snd_mixahead, snd_usemultipledevices; + int y; + menu_t *menu = M_Options_Title(&y, 0); + extern cvar_t nosound, snd_leftisright, snd_device, snd_khz, snd_speakers, ambient_level, bgmvolume, snd_playersoundvolume, ambient_fade, cl_staticsounds, snd_inactive, _snd_mixahead; // extern cvar_t snd_noextraupdate, snd_eax, precache; #ifdef VOICECHAT - extern cvar_t cl_voip_play, cl_voip_send; + extern cvar_t cl_voip_play, cl_voip_send, cl_voip_test, cl_voip_micamp, cl_voip_vad_threshhold, cl_voip_ducking, cl_voip_noisefilter, cl_voip_codec; #endif + extern char **soundoutdevicecodes, **soundoutdevicenames; static const char *soundqualityoptions[] = { "11025 Hz", @@ -275,11 +277,43 @@ void M_Menu_Audio_f (void) NULL }; - int y; + static const char *voipcodecoptions[] = { + "Speex (ez-compat)", +// "Raw (11025)", + "Opus (external)", + "Speex (Narrow)", + "Speex (Wide)", + NULL + }; + static const char *voipcodecvalue[] = { + "0", +// "1", + "2", + "3", + "4", + NULL + }; + + static const char *voipsendoptions[] = { + "Push To Talk", + "Voice Activation", + "Continuous", + NULL + }; + static const char *voipsendvalue[] = { + "0", + "1", + "2", + NULL + }; + menubulk_t bulk[] = { MB_REDTEXT("Sound Options", false), MB_TEXT("\x80\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x82", false), MB_SPACING(8), + MB_CONSOLECMD("Restart Sound", "snd_restart\n", "Restart audio systems and apply set options."), + MB_SPACING(4), + MB_COMBOCVAR("Output Device", snd_device, soundoutdevicenames, soundoutdevicecodes, NULL), MB_SLIDER("Volume", volume, 0, 1, 0.1, NULL), MB_COMBOCVAR("Speaker Setup", snd_speakers, speakeroptions, speakervalues, NULL), MB_COMBOCVAR("Frequency", snd_khz, soundqualityoptions, soundqualityvalues, NULL), @@ -288,10 +322,7 @@ void M_Menu_Audio_f (void) MB_SLIDER("Mixahead", _snd_mixahead, 0, 1, 0.05, NULL), MB_CHECKBOXCVAR("Disable All Sounds", nosound, 0), MB_SPACING(4), -#ifdef VOICECHAT - MB_CHECKBOXCVAR("Voice Chat", cl_voip_play, 0), - MB_CHECKBOXCVAR("Voice Activation", cl_voip_send, 0), -#endif + MB_SLIDER("Player Sound Volume", snd_playersoundvolume, 0, 1, 0.1, NULL), MB_SLIDER("Ambient Volume", ambient_level, 0, 1, 0.1, NULL), MB_SLIDER("Ambient Fade", ambient_fade, 0, 1000, 1, NULL), @@ -300,17 +331,28 @@ void M_Menu_Audio_f (void) // removed music buffer // removed precache // removed eax2 - MB_CHECKBOXCVAR("Multiple Devices", snd_usemultipledevices, 0), // remove no extra update MB_CHECKBOXCVAR("Sound While Inactive", snd_inactive, 0), MB_SPACING(4), + +#ifdef VOICECHAT + MB_REDTEXT("Voice Options", false), + MB_TEXT("\x80\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x82", false), + MB_SLIDER("Voice Volume", cl_voip_play, 0, 2, 0.1, NULL), +// MB_COMBOCVAR("Microphone Device", snd_micdevice, inputdeviceoptions, inputdevicevalue, NULL), + MB_CHECKBOXCVAR("Microphone Test", cl_voip_test, 0), + MB_SLIDER("Microphone Volume", cl_voip_micamp, 0, 2, 0.1, NULL), + MB_COMBOCVAR("Activation Mode", cl_voip_send, voipsendoptions, voipsendvalue, NULL), + MB_SLIDER("Act. Threshhold", cl_voip_vad_threshhold, 0, 30, 1, NULL), + MB_CHECKBOXCVAR("Audio Ducking", cl_voip_ducking, 0), + MB_CHECKBOXCVAR("Noise Cancelation", cl_voip_noisefilter, 0), + MB_COMBOCVAR("Codec", cl_voip_codec, voipcodecoptions, voipcodecvalue, NULL), +#endif + //MB_CONSOLECMD("Speaker Test", "menu_speakers\n", "Test speaker setup output."), - MB_CONSOLECMD("Restart Sound", "snd_restart\n", "Restart audio systems and apply set options."), MB_END() }; - menu = M_Options_Title(&y, 0); - MC_AddBulk(menu, bulk, 16, 216, y); } diff --git a/engine/client/menu.h b/engine/client/menu.h index 764a3eb86..aeffb469b 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -178,6 +178,7 @@ typedef struct { float current; float smallchange; float largechange; + float vx; cvar_t *var; const char *text; } menuslider_t; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 6030efe95..a7385dd58 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2455,6 +2455,9 @@ static void QCBUILTIN PF_cs_serverkey (pubprogfuncs_t *prinst, struct globalvars default: ret = "NetQuake"; break; + case CPNQ_FITZ666: + ret = "Fitz666"; + break; case CPNQ_DP5: ret = "NetQuake DarkPlaces 5"; break; diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 2e644fa03..b8d53df12 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -2721,7 +2721,7 @@ ping time frags name Font_BeginString(font_conchar, x+24, y, &cx, &cy); \ Font_DrawChar(cx, cy, num[2] | 0xe000 | CON_WHITEMASK); \ \ - if ((cl.spectator && k == pv->cam_spec_track) ||\ + if ((cl.spectator && k == Cam_TrackNum(pv)) ||\ (!cl.spectator && k == pv->playernum)) \ { \ Font_BeginString(font_conchar, x, y, &cx, &cy); \ @@ -2774,6 +2774,9 @@ void Sbar_DeathmatchOverlay (int start) int startx, rank_width; playerview_t *pv = r_refdef.playerview; + if (!pv) + return; + if (largegame) skip = 8; diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index bfc06c1d5..7bb617b90 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -5,13 +5,9 @@ This is based on Jogi's OpenAL support. Much of it is stripped, to try and get it clean/compliant. Missing features: -FIXME: does not kill old sounds on replaced sound channels (quake compliance). -FIXME: no static/ambient sounds (quake compliance). -FIXME: does not support streaming audio from voice/videos (voice/q2/q3 compliance). -If the above ar implemented, it can be the default device. FIXME: listener velocity calculations (currently ugly). -FIXME: does not track entity velocities, so no dopler (awkward, quake move playing sounds at all). -FIXME: no eax (underwater). +FIXME: does not track entity velocities, so no dopler (awkward, quake doesn't move playing sounds at all). +FIXME: no eax / efx (underwater reverb etc). FIXME: a capture device would be useful (voice chat). */ @@ -34,6 +30,8 @@ typedef char ALboolean; typedef int ALsizei; typedef void ALvoid; +static dllhandle_t *openallib; +static qboolean openallib_tried; static AL_API ALenum (AL_APIENTRY *palGetError)( void ); static AL_API void (AL_APIENTRY *palSourcef)( ALuint sid, ALenum param, ALfloat value ); static AL_API void (AL_APIENTRY *palSourcei)( ALuint sid, ALenum param, ALint value ); @@ -60,6 +58,10 @@ static AL_API void (AL_APIENTRY *palDeleteSources)( ALsizei n, const ALuint* sou static AL_API void (AL_APIENTRY *palSpeedOfSound)( ALfloat value ); static AL_API void (AL_APIENTRY *palDistanceModel)( ALenum distanceModel ); +//needed for streaming +static AL_API void (AL_APIENTRY *palGetSourcei)(ALuint source, ALenum pname, ALint *value); +static AL_API void (AL_APIENTRY *palSourceQueueBuffers)(ALuint source, ALsizei n, ALuint* buffers); +static AL_API void (AL_APIENTRY *palSourceUnqueueBuffers)(ALuint source, ALsizei n, ALuint* buffers); #define AL_NONE 0 #define AL_FALSE 0 @@ -72,9 +74,14 @@ static AL_API void (AL_APIENTRY *palDistanceModel)( ALenum distanceModel ); #define AL_BUFFER 0x1009 #define AL_GAIN 0x100A #define AL_ORIENTATION 0x100F +#define AL_SOURCE_STATE 0x1010 +#define AL_PLAYING 0x1012 +#define AL_BUFFERS_PROCESSED 0x1016 #define AL_REFERENCE_DISTANCE 0x1020 #define AL_ROLLOFF_FACTOR 0x1021 #define AL_MAX_DISTANCE 0x1023 +#define AL_SOURCE_TYPE 0x1027 +#define AL_STREAMING 0x1029 #define AL_FORMAT_MONO8 0x1100 #define AL_FORMAT_MONO16 0x1101 #define AL_FORMAT_STEREO8 0x1102 @@ -127,6 +134,7 @@ static ALC_API ALCboolean (ALC_APIENTRY *palcIsExtensionPresent)( ALCdevice #define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 #define ALC_DEVICE_SPECIFIER 0x1005 #define ALC_EXTENSIONS 0x1006 +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 //#include "AL/alut.h" //#include "AL/al.h" @@ -134,6 +142,66 @@ static ALC_API ALCboolean (ALC_APIENTRY *palcIsExtensionPresent)( ALCdevice +//efx +#define AL_AUXILIARY_SEND_FILTER 0x20006 +#define AL_FILTER_NULL 0x0000 +#define AL_EFFECTSLOT_EFFECT 0x0001 +#define AL_EFFECT_TYPE 0x8001 +#define AL_EFFECT_REVERB 0x0001 +#define AL_EFFECT_EAXREVERB 0x8000 + +#define AL_REVERB_DENSITY 0x0001 +#define AL_REVERB_DIFFUSION 0x0002 +#define AL_REVERB_GAIN 0x0003 +#define AL_REVERB_GAINHF 0x0004 +#define AL_REVERB_DECAY_TIME 0x0005 +#define AL_REVERB_DECAY_HFRATIO 0x0006 +#define AL_REVERB_REFLECTIONS_GAIN 0x0007 +#define AL_REVERB_REFLECTIONS_DELAY 0x0008 +#define AL_REVERB_LATE_REVERB_GAIN 0x0009 +#define AL_REVERB_LATE_REVERB_DELAY 0x000A +#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B +#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C +#define AL_REVERB_DECAY_HFLIMIT 0x000D + +/* EAX Reverb effect parameters */ +#define AL_EAXREVERB_DENSITY 0x0001 +#define AL_EAXREVERB_DIFFUSION 0x0002 +#define AL_EAXREVERB_GAIN 0x0003 +#define AL_EAXREVERB_GAINHF 0x0004 +#define AL_EAXREVERB_GAINLF 0x0005 +#define AL_EAXREVERB_DECAY_TIME 0x0006 +#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +#define AL_EAXREVERB_ECHO_TIME 0x000F +#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +#define AL_EAXREVERB_MODULATION_TIME 0x0011 +#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +#define AL_EAXREVERB_HFREFERENCE 0x0014 +#define AL_EAXREVERB_LFREFERENCE 0x0015 +#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 +static AL_API void*(AL_APIENTRY *palGetProcAddress)(const ALchar *fname); +static AL_API void (AL_APIENTRY *palSource3i)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); + +static AL_API void (AL_APIENTRY *palAuxiliaryEffectSloti)(ALuint effectslot, ALenum param, ALint iValue); +static AL_API ALvoid (AL_APIENTRY *palGenAuxiliaryEffectSlots)(ALsizei n, ALuint *effectslots); +static AL_API ALvoid (AL_APIENTRY *palDeleteAuxiliaryEffectSlots)(ALsizei n, const ALuint *effectslots); +static AL_API ALvoid (AL_APIENTRY *palDeleteEffects)(ALsizei n, const ALuint *effects); + +static AL_API ALvoid (AL_APIENTRY *palGenEffects)(ALsizei n, ALuint *effects); +static AL_API ALvoid (AL_APIENTRY *palEffecti)(ALuint effect, ALenum param, ALint iValue); +static AL_API ALvoid (AL_APIENTRY *palEffectiv)(ALuint effect, ALenum param, const ALint *piValues); +static AL_API ALvoid (AL_APIENTRY *palEffectf)(ALuint effect, ALenum param, ALfloat flValue); +static AL_API ALvoid (AL_APIENTRY *palEffectfv)(ALuint effect, ALenum param, const ALfloat *pflValues); + #define SOUNDVARS "OpenAL variables" @@ -155,30 +223,35 @@ static void S_Info(void); static void S_Shutdown_f(void); */ -static cvar_t s_al_enable = CVAR("s_al_enable", "0"); static cvar_t s_al_debug = CVAR("s_al_debug", "0"); static cvar_t s_al_max_distance = CVARFC("s_al_max_distance", "1000",0,OnChangeALMaxDistance); static cvar_t s_al_speedofsound = CVARFC("s_al_speedofsound", "343.3",0,OnChangeALSpeedOfSound); static cvar_t s_al_dopplerfactor = CVARFC("s_al_dopplerfactor", "3.0",0,OnChangeALDopplerFactor); -static cvar_t s_al_distancemodel = CVARFC("s_al_distancemodel", "1",0,OnChangeALDistanceModel); +static cvar_t s_al_distancemodel = CVARFC("s_al_distancemodel", "2",0,OnChangeALDistanceModel); static cvar_t s_al_rolloff_factor = CVAR("s_al_rolloff_factor", "1"); static cvar_t s_al_reference_distance = CVAR("s_al_reference_distance", "120");static cvar_t s_al_velocityscale = CVAR("s_al_velocityscale", "1"); static cvar_t s_al_static_listener = CVAR("s_al_static_listener", "0"); //cheat -#define NUM_SOURCES MAX_CHANNELS -static ALuint source[NUM_SOURCES]; +typedef struct +{ + #define NUM_SOURCES MAX_CHANNELS + ALuint source[NUM_SOURCES]; -static ALCdevice *OpenAL_Device; -static ALCcontext *OpenAL_Context; + ALCdevice *OpenAL_Device; + ALCcontext *OpenAL_Context; -static ALfloat ListenPos[] = { 0.0, 0.0, 0.0 }; + ALfloat ListenPos[3];// = { 0.0, 0.0, 0.0 }; -// Velocity of the listener. -static ALfloat ListenVel[] = { 0.0, 0.0, 0.0 }; + // Velocity of the listener. + ALfloat ListenVel[3];// = { 0.0, 0.0, 0.0 }; -// Orientation of the listener. (first 3 elements are "at", second 3 are "up") -static ALfloat ListenOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 }; + // Orientation of the listener. (first 3 elements are "at", second 3 are "up") + ALfloat ListenOri[6];// = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 }; + int cureffect; + ALuint effectslot; //the global reverb slot + ALuint effecttype[2]; //effect used when underwater +} oalinfo_t; static void PrintALError(char *string) { ALenum err; @@ -212,7 +285,7 @@ static void PrintALError(char *string) Con_Printf("OpenAL - %s: %x: %s\n",string,err,text); } -void OpenAL_LoadCache(sfx_t *s, sfxcache_t *sc) +void OpenAL_LoadCache(unsigned int *bufptr, sfxcache_t *sc) { unsigned int fmt; unsigned int size; @@ -246,7 +319,7 @@ void OpenAL_LoadCache(sfx_t *s, sfxcache_t *sc) return; } PrintALError("pre Buffer Data"); - palGenBuffers(1, &s->openal_buffer); + palGenBuffers(1, bufptr); /*openal is inconsistant and supports only 8bit unsigned or 16bit signed*/ if (sc->width == 1) { @@ -257,11 +330,11 @@ void OpenAL_LoadCache(sfx_t *s, sfxcache_t *sc) { tmp[i] = src[i]+128; } - palBufferData(s->openal_buffer, fmt, tmp, size, sc->speed); + palBufferData(*bufptr, fmt, tmp, size, sc->speed); free(tmp); } else - palBufferData(s->openal_buffer, fmt, sc->data, size, sc->speed); + palBufferData(*bufptr, fmt, sc->data, size, sc->speed); //FIXME: we need to handle oal-oom error codes @@ -270,7 +343,6 @@ void OpenAL_LoadCache(sfx_t *s, sfxcache_t *sc) void OpenAL_CvarInit(void) { - Cvar_Register(&s_al_enable, SOUNDVARS); Cvar_Register(&s_al_debug, SOUNDVARS); Cvar_Register(&s_al_max_distance, SOUNDVARS); Cvar_Register(&s_al_dopplerfactor, SOUNDVARS); @@ -283,111 +355,58 @@ void OpenAL_CvarInit(void) } extern float voicevolumemod; -void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity) +static void OpenAL_ListenerUpdate(soundcardinfo_t *sc, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity) { - VectorScale(velocity, s_al_velocityscale.value, ListenVel); - VectorCopy(origin, ListenPos); + oalinfo_t *oali = sc->handle; - ListenOri[0] = forward[0]; - ListenOri[1] = forward[1]; - ListenOri[2] = forward[2]; - ListenOri[3] = up[0]; - ListenOri[4] = up[1]; - ListenOri[5] = up[2]; + VectorScale(velocity, s_al_velocityscale.value, oali->ListenVel); + VectorCopy(origin, oali->ListenPos); + + oali->ListenOri[0] = forward[0]; + oali->ListenOri[1] = forward[1]; + oali->ListenOri[2] = forward[2]; + oali->ListenOri[3] = up[0]; + oali->ListenOri[4] = up[1]; + oali->ListenOri[5] = up[2]; if (!s_al_static_listener.value) { palListenerf(AL_GAIN, volume.value*voicevolumemod); - palListenerfv(AL_POSITION, ListenPos); - palListenerfv(AL_VELOCITY, ListenVel); - palListenerfv(AL_ORIENTATION, ListenOri); + palListenerfv(AL_POSITION, oali->ListenPos); + palListenerfv(AL_VELOCITY, oali->ListenVel); + palListenerfv(AL_ORIENTATION, oali->ListenOri); } } -/* -static void OpenAL_StopAllSounds(qboolean clear) -{ - Con_Printf("-------------------------- %i ---------------\n",clear); - palSourceStopv(NUM_SOURCES,source); - palSourceStopv(NUM_SOURCES,static_source); - num_sfx=0; - num_static_source=0; - if (clear) - { - } -} -*/ -/* -void OpenAL_StartSound(int entnum, int entchannel, sfx_t * sfx, vec3_t origin, float fvol, float attenuation, float pitch) -{ - vec3_t tmp; - extern cvar_t temp1; - if (!temp1.value) - temp1.value = 1; - - if (!sfx->openal_buffer) - { - sfxcache_t *sc = Cache_Check(&sfx->cache); - if (!sc) - return; - OpenAL_LoadCache(sfx, sc); - } - - if (!origin) - VectorClear(tmp); - else - { - tmp[0] = origin[0]; - tmp[1] = origin[1]; - tmp[2] = origin[2]; - } - - PrintALError("pre start sound"); - - palSourceStop(source[num_sfx]); - palSourcei(source[num_sfx], AL_BUFFER, sfx->openal_buffer); - palSourcef(source[num_sfx], AL_PITCH, pitch*temp1.value); - palSourcef(source[num_sfx], AL_GAIN, fvol); -// palSourcef(source[num_sfx], AL_MAX_DISTANCE, s_al_max_distance.value); -// palSourcef(source[num_sfx], AL_ROLLOFF_FACTOR, s_al_rolloff_factor.value); - palSourcefv(source[num_sfx], AL_POSITION, tmp); - palSourcefv(source[num_sfx], AL_VELOCITY, vec3_origin); - palSourcef(source[num_sfx], AL_REFERENCE_DISTANCE, s_al_reference_distance.value); - - if (entnum == -1 || entnum == cl.playernum[0]+1) - { - palSourcei(source[num_sfx], AL_SOURCE_RELATIVE, AL_TRUE); - palSourcef(source[num_sfx], AL_ROLLOFF_FACTOR, 0.0f); - } - else - { - palSourcei(source[num_sfx], AL_SOURCE_RELATIVE, AL_FALSE); - palSourcef(source[num_sfx], AL_ROLLOFF_FACTOR, s_al_rolloff_factor.value); - } - - palSourcePlay(source[num_sfx]); - num_sfx++; - if (num_sfx >= NUM_SOURCES) - num_sfx =0; - - PrintALError("post start sound"); -}*/ - static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned int schanged) { + oalinfo_t *oali = sc->handle; ALuint src; sfx_t *sfx = chan->sfx; float pitch; + int chnum = chan - sc->channel; + ALuint buf; - src = source[chan - sc->channel]; + if (chnum >= NUM_SOURCES) + return; + + src = oali->source[chnum]; if (!src) { + //not currently playing. be prepared to create one if (!sfx || chan->master_vol == 0) return; palGenSources(1, &src); - source[chan - sc->channel] = src; - schanged = true; + //unable to start a new sound source, give up. + if (!src) + { + //FIXME: find one which has already stopped and steal it. + Con_Printf("Out of OpenAL sources!\n"); + return; + } + oali->source[chnum] = src; + schanged = true; //should normally be true anyway, but hey } PrintALError("pre start sound"); @@ -395,33 +414,75 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned if (schanged && src) palSourceStop(src); + //reclaim any queued buffers + palGetSourcei(src, AL_SOURCE_TYPE, &buf); + if (buf == AL_STREAMING) + { + for(;;) + { + palGetSourcei(src, AL_BUFFERS_PROCESSED, &buf); + if (!buf) + break; + palSourceUnqueueBuffers(src, 1, &buf); + palDeleteBuffers(1, &buf); + } + } + /*just wanted to stop it?*/ if (!sfx || chan->master_vol == 0) { if (src) { - palDeleteBuffers(1, &src); - source[chan - sc->channel] = 0; + palDeleteSources(1, &src); + oali->source[chnum] = 0; } return; } - if (schanged) + if (schanged || sfx->decoder.decodedata) { if (!sfx->openal_buffer) { - sfxcache_t *sc = S_LoadSound(sfx); - if (!sc) /*ack! can't start it if its not loaded!*/ - return; - OpenAL_LoadCache(sfx, sc); - } + if (!S_LoadSound(sfx)) + return; //can't load it + if (sfx->decoder.decodedata) + { + int offset; + sfxcache_t sbuf, *sc = sfx->decoder.decodedata(sfx, &sbuf, chan->pos>>PITCHSHIFT, 65536); + memcpy(&sbuf, sc, sizeof(sbuf)); - palSourcei(src, AL_BUFFER, sfx->openal_buffer); + //hack up the sound to offset it correctly + offset = (chan->pos>>PITCHSHIFT) - sbuf.soundoffset; + sbuf.data += offset * sc->width*sc->numchannels; + sbuf.length -= offset; + sbuf.soundoffset = 0; + + //build a buffer with it and queue it up. + //buffer will be purged later on when its unqueued + OpenAL_LoadCache(&buf, &sbuf); + palSourceQueueBuffers(src, 1, &buf); + + //yay + chan->pos += sbuf.length<openal_buffer, sfx->decoder.buf); + palSourcei(src, AL_BUFFER, sfx->openal_buffer); + } + } + else + palSourcei(src, AL_BUFFER, sfx->openal_buffer); } palSourcef(src, AL_GAIN, chan->master_vol/255.0f); -// palSourcef(src, AL_MAX_DISTANCE, s_al_max_distance.value); -// palSourcef(src, AL_ROLLOFF_FACTOR, s_al_rolloff_factor.value); - palSourcefv(src, AL_POSITION, chan->origin); + if (chan->entnum == -1 || chan->entnum == cl.playerview[0].viewentity) + palSourcefv(src, AL_POSITION, vec3_origin); + else + palSourcefv(src, AL_POSITION, chan->origin); palSourcefv(src, AL_VELOCITY, vec3_origin); if (schanged) @@ -429,17 +490,34 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned pitch = (float)chan->rate/(1<entnum == -2) //don't do the underwater thing on static sounds. it sounds like arse with all those sources. + palSource3i(src, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + else + palSource3i(src, AL_AUXILIARY_SEND_FILTER, oali->effectslot, 0, AL_FILTER_NULL); + palSourcei(src, AL_LOOPING, chan->looping?AL_TRUE:AL_FALSE); - if (chan->entnum == -1 || chan->entnum == cl.playernum[0]+1) + if (chan->entnum == -1 || chan->entnum == cl.playerview[0].viewentity) { palSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); - palSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); +// palSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); } else { palSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); - palSourcef(src, AL_ROLLOFF_FACTOR, s_al_rolloff_factor.value*chan->dist_mult); +// palSourcef(src, AL_ROLLOFF_FACTOR, s_al_rolloff_factor.value*chan->dist_mult); + } + switch(s_al_distancemodel.ival) + { + default: + palSourcef(src, AL_ROLLOFF_FACTOR, s_al_reference_distance.value); + palSourcef(src, AL_REFERENCE_DISTANCE, 1); + palSourcef(src, AL_MAX_DISTANCE, 1/chan->dist_mult); //clamp to the maximum distance you'd normally be allowed to hear... this is probably going to be annoying. + break; + case 2: //linear, mimic quake. + palSourcef(src, AL_ROLLOFF_FACTOR, 1); + palSourcef(src, AL_REFERENCE_DISTANCE, 0); + palSourcef(src, AL_MAX_DISTANCE, 1/chan->dist_mult); + break; } /*and start it up again*/ @@ -468,9 +546,9 @@ static void S_Info (void) } */ -static qboolean OpenAL_Init(void) +static qboolean OpenAL_InitLibrary(void) { - dllfunction_t openalfuncs[] = + static dllfunction_t openalfuncs[] = { {(void*)&palGetError, "alGetError"}, {(void*)&palSourcef, "alSourcef"}, @@ -493,6 +571,11 @@ static qboolean OpenAL_Init(void) {(void*)&palSpeedOfSound, "alSpeedOfSound"}, {(void*)&palDistanceModel, "alDistanceModel"}, + {(void*)&palGetProcAddress, "alGetProcAddress"}, + {(void*)&palGetSourcei, "alGetSourcei"}, + {(void*)&palSourceQueueBuffers, "alSourceQueueBuffers"}, + {(void*)&palSourceUnqueueBuffers, "alSourceUnqueueBuffers"}, + {(void*)&palcOpenDevice, "alcOpenDevice"}, {(void*)&palcCloseDevice, "alcCloseDevice"}, {(void*)&palcCreateContext, "alcCreateContext"}, @@ -503,33 +586,56 @@ static qboolean OpenAL_Init(void) {(void*)&palcIsExtensionPresent, "alcIsExtensionPresent"}, {NULL} }; - if (!Sys_LoadLibrary("OpenAL32", openalfuncs)) + + if (!openallib_tried) + { + openallib_tried = true; + openallib = Sys_LoadLibrary("OpenAL32", openalfuncs); + } + return !!openallib; +} + +static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname) +{ + oalinfo_t *oali = Z_Malloc(sizeof(oalinfo_t)); + sc->handle = oali; + + if (!OpenAL_InitLibrary()) { Con_Printf("OpenAL is not installed\n"); return false; } - OpenAL_Device = palcOpenDevice(NULL); - if (OpenAL_Device == NULL) + if (oali->OpenAL_Context) + { + Con_Printf("OpenAL: only able to load one device at a time\n"); + return false; + } + + oali->OpenAL_Device = palcOpenDevice(devname); + if (oali->OpenAL_Device == NULL) { PrintALError("Could not init a sound device\n"); return false; } - OpenAL_Context = palcCreateContext(OpenAL_Device, NULL); - palcMakeContextCurrent(OpenAL_Context); -// palcProcessContext(OpenAL_Context); + oali->OpenAL_Context = palcCreateContext(oali->OpenAL_Device, NULL); + if (!oali->OpenAL_Context) + return false; + + palcMakeContextCurrent(oali->OpenAL_Context); +// palcProcessContext(oali->OpenAL_Context); //S_Info(); - - palGenSources(NUM_SOURCES, source); + //fixme... + memset(oali->source, 0, sizeof(oali->source)); PrintALError("alGensources for normal sources"); - palListenerfv(AL_POSITION, ListenPos); - palListenerfv(AL_VELOCITY, ListenVel); - palListenerfv(AL_ORIENTATION, ListenOri); + palListenerfv(AL_POSITION, oali->ListenPos); + palListenerfv(AL_VELOCITY, oali->ListenVel); + palListenerfv(AL_ORIENTATION, oali->ListenOri); return true; } @@ -595,6 +701,17 @@ static void OpenAL_UnlockBuffer (soundcardinfo_t *sc, void *buffer) static void OpenAL_SetUnderWater (soundcardinfo_t *sc, qboolean underwater) { + oalinfo_t *oali = sc->handle; + + if (!oali->effectslot) + return; + //don't spam it + if (oali->cureffect == underwater) + return; + oali->cureffect = underwater; + PrintALError("preunderwater"); + palAuxiliaryEffectSloti(oali->effectslot, AL_EFFECTSLOT_EFFECT, oali->effecttype[oali->cureffect]); + PrintALError("postunderwater"); //Con_Printf("OpenAL: SetUnderWater %i\n", underwater); } @@ -613,9 +730,10 @@ static unsigned int OpenAL_GetDMAPos (soundcardinfo_t *sc) static void OpenAL_Shutdown (soundcardinfo_t *sc) { + oalinfo_t *oali = sc->handle; int i; - palDeleteSources(NUM_SOURCES, source); + palDeleteSources(NUM_SOURCES, oali->source); /*make sure the buffers are cleared from the sound effects*/ for (i=0;ieffectslot); + palDeleteEffects(1, &oali->effecttype[1]); + + palcDestroyContext(oali->OpenAL_Context); + palcCloseDevice(oali->OpenAL_Device); + Z_Free(oali); } - -static int OpenAL_InitCard(soundcardinfo_t *sc, int cardnum) +typedef struct { + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; +} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; +#define EFX_REVERB_PRESET_PSYCHOTIC \ + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } +#define EFX_REVERB_PRESET_UNDERWATER \ + { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } +ALuint OpenAL_LoadEffect(const EFXEAXREVERBPROPERTIES *reverb) { - if (cardnum != 0) - return 2; + ALuint effect; + palGenEffects(1, &effect); + if(1)//alGetEnumValue("AL_EFFECT_EAXREVERB") != 0) + { + /* EAX Reverb is available. Set the EAX effect type then load the + * reverb properties. */ + palEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - if (!s_al_enable.ival) - return 2; + palEffectf(effect, AL_EAXREVERB_DENSITY, reverb->flDensity); + palEffectf(effect, AL_EAXREVERB_DIFFUSION, reverb->flDiffusion); + palEffectf(effect, AL_EAXREVERB_GAIN, reverb->flGain); + palEffectf(effect, AL_EAXREVERB_GAINHF, reverb->flGainHF); + palEffectf(effect, AL_EAXREVERB_GAINLF, reverb->flGainLF); + palEffectf(effect, AL_EAXREVERB_DECAY_TIME, reverb->flDecayTime); + palEffectf(effect, AL_EAXREVERB_DECAY_HFRATIO, reverb->flDecayHFRatio); + palEffectf(effect, AL_EAXREVERB_DECAY_LFRATIO, reverb->flDecayLFRatio); + palEffectf(effect, AL_EAXREVERB_REFLECTIONS_GAIN, reverb->flReflectionsGain); + palEffectf(effect, AL_EAXREVERB_REFLECTIONS_DELAY, reverb->flReflectionsDelay); + palEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, reverb->flReflectionsPan); + palEffectf(effect, AL_EAXREVERB_LATE_REVERB_GAIN, reverb->flLateReverbGain); + palEffectf(effect, AL_EAXREVERB_LATE_REVERB_DELAY, reverb->flLateReverbDelay); + palEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, reverb->flLateReverbPan); + palEffectf(effect, AL_EAXREVERB_ECHO_TIME, reverb->flEchoTime); + palEffectf(effect, AL_EAXREVERB_ECHO_DEPTH, reverb->flEchoDepth); + palEffectf(effect, AL_EAXREVERB_MODULATION_TIME, reverb->flModulationTime); + palEffectf(effect, AL_EAXREVERB_MODULATION_DEPTH, reverb->flModulationDepth); + palEffectf(effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, reverb->flAirAbsorptionGainHF); + palEffectf(effect, AL_EAXREVERB_HFREFERENCE, reverb->flHFReference); + palEffectf(effect, AL_EAXREVERB_LFREFERENCE, reverb->flLFReference); + palEffectf(effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, reverb->flRoomRolloffFactor); + palEffecti(effect, AL_EAXREVERB_DECAY_HFLIMIT, reverb->iDecayHFLimit); + } + else + { + /* No EAX Reverb. Set the standard reverb effect type then load the + * available reverb properties. */ + palEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - Con_Printf("Initiating OpenAL sound device.\n"); + palEffectf(effect, AL_REVERB_DENSITY, reverb->flDensity); + palEffectf(effect, AL_REVERB_DIFFUSION, reverb->flDiffusion); + palEffectf(effect, AL_REVERB_GAIN, reverb->flGain); + palEffectf(effect, AL_REVERB_GAINHF, reverb->flGainHF); + palEffectf(effect, AL_REVERB_DECAY_TIME, reverb->flDecayTime); + palEffectf(effect, AL_REVERB_DECAY_HFRATIO, reverb->flDecayHFRatio); + palEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, reverb->flReflectionsGain); + palEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, reverb->flReflectionsDelay); + palEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, reverb->flLateReverbGain); + palEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, reverb->flLateReverbDelay); + palEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, reverb->flAirAbsorptionGainHF); + palEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, reverb->flRoomRolloffFactor); + palEffecti(effect, AL_REVERB_DECAY_HFLIMIT, reverb->iDecayHFLimit); + } + return effect; +} - if (OpenAL_Init() == false) +static qboolean QDECL OpenAL_InitCard(soundcardinfo_t *sc, const char *devname) +{ + oalinfo_t *oali; + //no default support, because we're buggy as fuck + if (!devname) + return false; + + if (!devname || !*devname) + devname = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + + Con_Printf("Initiating OpenAL: %s.\n", devname); + + if (OpenAL_Init(sc, devname) == false) { Con_Printf(CON_ERROR "OpenAL init failed\n"); return false; } + oali = sc->handle; + + Con_DPrintf("OpenAL AL Extension : %s\n",palGetString(AL_EXTENSIONS)); + Con_DPrintf("OpenAL ALC Extension : %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS)); sc->Lock = OpenAL_LockBuffer; sc->Unlock = OpenAL_UnlockBuffer; @@ -657,10 +868,10 @@ static int OpenAL_InitCard(soundcardinfo_t *sc, int cardnum) sc->Shutdown = OpenAL_Shutdown; sc->GetDMAPos = OpenAL_GetDMAPos; sc->ChannelUpdate = OpenAL_ChannelUpdate; + sc->ListenerUpdate = OpenAL_ListenerUpdate; - Q_snprintfz(sc->name, sizeof(sc->name), "OpenAL device"); + Q_snprintfz(sc->name, sizeof(sc->name), "%s", devname); - sc->openal = 1; sc->inactive_sound = true; sc->selfpainting = true; @@ -668,9 +879,53 @@ static int OpenAL_InitCard(soundcardinfo_t *sc, int cardnum) Cvar_ForceCallback(&s_al_speedofsound); Cvar_ForceCallback(&s_al_dopplerfactor); Cvar_ForceCallback(&s_al_max_distance); + + PrintALError("preeffects"); + palSource3i = palGetProcAddress("alSource3i"); + palAuxiliaryEffectSloti = palGetProcAddress("alAuxiliaryEffectSloti"); + palGenAuxiliaryEffectSlots = palGetProcAddress("alGenAuxiliaryEffectSlots"); + palDeleteAuxiliaryEffectSlots = palGetProcAddress("alDeleteAuxiliaryEffectSlots"); + palDeleteEffects = palGetProcAddress("alDeleteEffects"); + palGenEffects = palGetProcAddress("alGenEffects"); + palEffecti = palGetProcAddress("alEffecti"); + palEffectiv = palGetProcAddress("alEffectiv"); + palEffectf = palGetProcAddress("alEffectf"); + palEffectfv = palGetProcAddress("alEffectfv"); + + palGenAuxiliaryEffectSlots(1, &oali->effectslot); + + oali->cureffect = 0; + oali->effecttype[0] = 0; + { + EFXEAXREVERBPROPERTIES uw = EFX_REVERB_PRESET_UNDERWATER; + oali->effecttype[1] = OpenAL_LoadEffect(&uw); + } + PrintALError("posteffects"); return true; } -int (*pOPENAL_InitCard) (soundcardinfo_t *sc, int cardnum) = &OpenAL_InitCard; +static qboolean QDECL OpenAL_Enumerate(void (QDECL *callback)(const char *driver, const char *devicecode, const char *readabledevice)) +{ + const char *devnames; + if (!OpenAL_InitLibrary()) + return true; //enumerate nothing if al is disabled + + devnames = palcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + if (!devnames) + devnames = palcGetString(NULL, ALC_DEVICE_SPECIFIER); + while(*devnames) + { + callback("OpenAL", devnames, va("OAL:%s", devnames)); + devnames += strlen(devnames)+1; + } + return true; +} + +sounddriver_t OPENAL_Output = +{ + "OpenAL", + OpenAL_InitCard, + OpenAL_Enumerate +}; #endif diff --git a/engine/client/snd_directx.c b/engine/client/snd_directx.c index d5b12ffce..5f4b5e4d1 100644 --- a/engine/client/snd_directx.c +++ b/engine/client/snd_directx.c @@ -36,10 +36,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. FORCE_DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); #endif -#define SND_ERROR 0 -#define SND_LOADED 1 -#define SND_NOMORE 2 //like error, but doesn't try the next card. - #ifdef AVAIL_DSOUND #define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c) @@ -86,7 +82,7 @@ static void DSOUND_Restore(soundcardinfo_t *sc) dh->pDSBuf->lpVtbl->Play(dh->pDSBuf, 0, 0, DSBPLAY_LOOPING); } -DWORD dwSize; +static DWORD dsound_locksize; static void *DSOUND_Lock(soundcardinfo_t *sc, unsigned int *sampidx) { void *ret; @@ -96,11 +92,11 @@ static void *DSOUND_Lock(soundcardinfo_t *sc, unsigned int *sampidx) HRESULT hresult; dshandle_t *dh = sc->handle; - dwSize=0; + dsound_locksize=0; reps = 0; - while ((hresult = dh->pDSBuf->lpVtbl->Lock(dh->pDSBuf, 0, dh->gSndBufSize, (void**)&ret, &dwSize, + while ((hresult = dh->pDSBuf->lpVtbl->Lock(dh->pDSBuf, 0, dh->gSndBufSize, (void**)&ret, &dsound_locksize, (void**)&pbuf2, &dwSize2, 0)) != DS_OK) { if (hresult != DSERR_BUFFERLOST) @@ -125,7 +121,7 @@ static void *DSOUND_Lock(soundcardinfo_t *sc, unsigned int *sampidx) static void DSOUND_Unlock(soundcardinfo_t *sc, void *buffer) { dshandle_t *dh = sc->handle; - dh->pDSBuf->lpVtbl->Unlock(dh->pDSBuf, buffer, dwSize, NULL, 0); + dh->pDSBuf->lpVtbl->Unlock(dh->pDSBuf, buffer, dsound_locksize, NULL, 0); } /* @@ -190,24 +186,6 @@ static void DSOUND_Shutdown (soundcardinfo_t *sc) DSOUND_Shutdown_Internal(sc); } -GUID FAR *dsndguid; -int dsnd_guids; -static BOOL (CALLBACK DSEnumCallback)(GUID FAR *guid, LPCSTR str1, LPCSTR str2, LPVOID parm) -{ - soundcardinfo_t *sc = parm; - if (guid == NULL) - return TRUE; - - if (sc->audio_fd == dsnd_guids) - { - Q_strncpyz(sc->name, str1, sizeof(sc->name)); - dsndguid = guid; - } - dsnd_guids++; - return TRUE; -} - - /* Direct Sound. These following defs should be moved to winquake.h somewhere. @@ -530,6 +508,30 @@ static void DSOUND_Submit(soundcardinfo_t *sc, int start, int end) { } +static qboolean DSOUND_InitOutputLibrary(void) +{ + if (!hInstDS) + { + hInstDS = LoadLibrary("dsound.dll"); + + if (hInstDS == NULL) + { + Con_SafePrintf ("Couldn't load dsound.dll\n"); + return false; + } + + pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate"); + + if (!pDirectSoundCreate) + { + Con_SafePrintf ("Couldn't get DS proc addr\n"); + return false; + } + + pDirectSoundEnumerate = (void *)GetProcAddress(hInstDS,"DirectSoundEnumerateA"); + } + return true; +} /* ================== SNDDMA_InitDirect @@ -537,7 +539,7 @@ SNDDMA_InitDirect Direct-Sound support ================== */ -static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) +static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname) { extern cvar_t snd_inactive; #if _MSC_VER > 1200 //fixme err @@ -555,9 +557,24 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) qboolean primary_format_set; dshandle_t *dh; char *buffer; + GUID guid, *dsguid; + memset (&format, 0, sizeof(format)); + if (*sc->name) + { + wchar_t mssuck[128]; + mbstowcs(mssuck, sc->name, sizeof(mssuck)/sizeof(mssuck[0])-1); + CLSIDFromString(mssuck, &guid); + dsguid = &guid; + } + else + { + memset(&guid, 0, sizeof(GUID)); + dsguid = NULL; + } + if (sc->sn.numchannels >= 8) // 7.1 surround { format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; @@ -606,35 +623,8 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec *format.Format.nBlockAlign; - if (!hInstDS) - { - hInstDS = LoadLibrary("dsound.dll"); - - if (hInstDS == NULL) - { - Con_SafePrintf ("Couldn't load dsound.dll\n"); - return SND_ERROR; - } - - pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate"); - - if (!pDirectSoundCreate) - { - Con_SafePrintf ("Couldn't get DS proc addr\n"); - return SND_ERROR; - } - - pDirectSoundEnumerate = (void *)GetProcAddress(hInstDS,"DirectSoundEnumerateA"); - } - - dsnd_guids=0; - dsndguid=NULL; - if (pDirectSoundEnumerate) - pDirectSoundEnumerate(&DSEnumCallback, sc); - if (!snd_usemultipledevices.ival) //if only one device, ALWAYS use the default. - dsndguid=NULL; - else if (!dsndguid) //no more... - return SND_NOMORE; + if (!DSOUND_InitOutputLibrary()) + return false; sc->handle = Z_Malloc(sizeof(dshandle_t)); dh = sc->handle; @@ -648,19 +638,21 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) if (FAILED(CoCreateInstance( &CLSID_EAXDirectSound, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound, (void **)&dh->pDS ))) dh->pDS=NULL; else - IDirectSound_Initialize(dh->pDS, dsndguid); + { + IDirectSound_Initialize(dh->pDS, dsguid); + } } if (!dh->pDS) #endif #endif { - while ((hresult = iDirectSoundCreate(dsndguid, &dh->pDS, NULL)) != DS_OK) + while ((hresult = iDirectSoundCreate(dsguid, &dh->pDS, NULL)) != DS_OK) { if (hresult != DSERR_ALLOCATED) { Con_SafePrintf (": create failed\n"); - return SND_ERROR; + return false; } // if (MessageBox (NULL, @@ -672,11 +664,21 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) Con_SafePrintf (": failure\n" " hardware already in use\n" " Close the other app then use snd_restart\n"); - return SND_ERROR; + return false; // } } } +#ifdef _SDL +#define mainwindow GetDesktopWindow() +#endif + if (DS_OK != dh->pDS->lpVtbl->SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_EXCLUSIVE)) + { + Con_SafePrintf ("Set coop level failed\n"); + DSOUND_Shutdown_Internal (sc); + return false; + } + dscaps.dwSize = sizeof(dscaps); if (DS_OK != dh->pDS->lpVtbl->GetCaps (dh->pDS, &dscaps)) @@ -688,17 +690,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) { Con_SafePrintf ("No DirectSound driver installed\n"); DSOUND_Shutdown_Internal (sc); - return SND_ERROR; - } - -#ifdef _SDL -#define mainwindow GetDesktopWindow() -#endif - if (DS_OK != dh->pDS->lpVtbl->SetCooperativeLevel (dh->pDS, mainwindow, DSSCL_EXCLUSIVE)) - { - Con_SafePrintf ("Set coop level failed\n"); - DSOUND_Shutdown_Internal (sc); - return SND_ERROR; + return false; } @@ -776,7 +768,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) { Con_SafePrintf ("DS:CreateSoundBuffer Failed"); DSOUND_Shutdown_Internal (sc); - return SND_ERROR; + return false; } sc->sn.numchannels = format.Format.nChannels; @@ -787,7 +779,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) { Con_SafePrintf ("DS:GetCaps failed\n"); DSOUND_Shutdown_Internal (sc); - return SND_ERROR; + return false; } // if (snd_firsttime) @@ -799,14 +791,14 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) { Con_SafePrintf ("Set coop level failed\n"); DSOUND_Shutdown_Internal (sc); - return SND_ERROR; + return false; } if (DS_OK != dh->pDSPBuf->lpVtbl->GetCaps (dh->pDSPBuf, &dsbcaps)) { Con_Printf ("DS:GetCaps failed\n"); DSOUND_Shutdown_Internal (sc); - return SND_ERROR; + return false; } dh->pDSBuf = dh->pDSPBuf; @@ -835,14 +827,14 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) { Con_SafePrintf ("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); DSOUND_Shutdown_Internal (sc); - return SND_ERROR; + return false; } if (++reps > 10000) { Con_SafePrintf ("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); DSOUND_Shutdown_Internal (sc); - return SND_ERROR; + return false; } } @@ -889,7 +881,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) IKsPropertySet_Release(dh->EaxKsPropertiesSet); dh->EaxKsPropertiesSet = NULL; Con_SafePrintf ("EAX 2 not supported\n"); - return SND_LOADED;//otherwise successful. It can be used for normal sound anyway. + return true;//otherwise successful. It can be used for normal sound anyway. } //worked. EAX is supported. @@ -903,7 +895,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, int cardnum) #endif #endif - return SND_LOADED; + return true; } @@ -915,23 +907,11 @@ static int DSOUND_Thread(void *arg) { soundcardinfo_t *sc = arg; void *cond = sc->handle; - int cardnum = sc->audio_fd; sc->handle = NULL; //once creating the thread, the main thread will wait for us to signal that we have inited the dsound device. - switch(DSOUND_InitCard_Internal(sc, cardnum)) - { - case SND_LOADED: - break; - case SND_NOMORE: - sc->audio_fd = -1; + if (!DSOUND_InitCard_Internal(sc, sc->name)) sc->selfpainting = false; - break; - default: - case SND_ERROR: - sc->selfpainting = false; - break; - } //wake up the main thread. Sys_ConditionSignal(cond); @@ -952,19 +932,17 @@ static int DSOUND_Thread(void *arg) } #endif -static int DSOUND_InitCard (soundcardinfo_t *sc, int cardnum) +static qboolean QDECL DSOUND_InitCard (soundcardinfo_t *sc, const char *device) { if (COM_CheckParm("-wavonly")) - return SND_NOMORE; + return false; - if (cardnum > 5) - return SND_NOMORE; + Q_strncpyz(sc->name, device?device:"", sizeof(sc->name)); #ifdef MULTITHREAD if (snd_mixerthread.ival) { void *cond; - sc->audio_fd = cardnum; sc->selfpainting = true; sc->handle = cond = Sys_CreateConditional(); Sys_LockConditional(cond); @@ -972,7 +950,7 @@ static int DSOUND_InitCard (soundcardinfo_t *sc, int cardnum) if (!sc->thread) { Con_SafePrintf ("Unable to create sound mixing thread\n"); - return SND_NOMORE; + return false; } //wait for the thread to finish (along with all its error con printfs etc @@ -984,16 +962,48 @@ static int DSOUND_InitCard (soundcardinfo_t *sc, int cardnum) { Sys_WaitOnThread(sc->thread); sc->thread = NULL; - return (sc->audio_fd==-1)?SND_NOMORE:SND_ERROR; + return false; } - return SND_LOADED; + return true; } else #endif - return DSOUND_InitCard_Internal(sc, cardnum); + return DSOUND_InitCard_Internal(sc, sc->name); } -int (*pDSOUND_InitCard) (soundcardinfo_t *sc, int cardnum) = &DSOUND_InitCard; +#define SDRVNAME "DirectSound" +static BOOL (CALLBACK DSound_EnumCallback)(GUID FAR *guid, LPCSTR str1, LPCSTR str2, LPVOID parm) +{ + char guidbuf[128]; + wchar_t mssuck[128]; + void (QDECL *callback) (const char *drivername, const char *devicecode, const char *readablename) = parm; + soundcardinfo_t *sc = parm; + if (guid == NULL) //we don't care about the (dupe) default device + return TRUE; + + StringFromGUID2(guid, mssuck, sizeof(mssuck)/sizeof(mssuck[0])); + wcstombs(guidbuf, mssuck, sizeof(guidbuf)); + callback(SDRVNAME, guidbuf, str1); + return TRUE; +} +static qboolean QDECL DSOUND_Enumerate(void (QDECL *cb) (const char *drivername, const char *devicecode, const char *readablename)) +{ + if (!DSOUND_InitOutputLibrary()) + return false; + if (pDirectSoundEnumerate) + { + pDirectSoundEnumerate(&DSound_EnumCallback, cb); + return true; + } + return false; +} + +sounddriver_t DSOUND_Output = +{ + SDRVNAME, + DSOUND_InitCard, + DSOUND_Enumerate +}; #endif diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index da971b16b..70d98d31f 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -112,10 +112,8 @@ cvar_t snd_linearresample_stream = CVARAF( "s_linearresample_stream", "0", cvar_t snd_mixerthread = CVARAD( "s_mixerthread", "1", "snd_mixerthread", "When enabled sound mixing will be run on a separate thread. Currently supported only by directsound. Other drivers may unconditionally thread audio. Set to 0 only if you have issues."); -cvar_t snd_usemultipledevices = CVARAFD( "s_multipledevices", "0", - "snd_multipledevices", 0, "If enabled, all output sound devices in your computer will be initialised for playback, not just the default device."); -cvar_t snd_driver = CVARAF( "s_driver", "", - "snd_driver", 0); +cvar_t snd_device = CVARAF( "s_device", "", + "snd_device", CVAR_ARCHIVE); #ifdef VOICECHAT static void S_Voip_Play_Callback(cvar_t *var, char *oldval); @@ -130,7 +128,7 @@ cvar_t cl_voip_play = CVARAFDC("cl_voip_play", "1", NULL, CVAR_ARCHIVE, "Enables cvar_t cl_voip_ducking = CVARAFD("cl_voip_ducking", "0.5", NULL, CVAR_ARCHIVE, "Scales game audio by this much when someone is talking to you. Does not affect your speaker volume when you speak (minimum of cl_voip_capturingvol and cl_voip_ducking is used)."); cvar_t cl_voip_micamp = CVARAFDC("cl_voip_micamp", "2", NULL, CVAR_ARCHIVE, "Amplifies your microphone when using voip.", 0); cvar_t cl_voip_codec = CVARAFDC("cl_voip_codec", "0", NULL, CVAR_ARCHIVE, "0: speex. 1: raw. 2: opus.", 0); -cvar_t cl_voip_noisefilter = CVARAFDC("cl_voip_noisefilter", "1", NULL, CVAR_ARCHIVE, "Enable the use of the noise cancelation filter, which also normalises microphone volume levels.", 0); +cvar_t cl_voip_noisefilter = CVARAFDC("cl_voip_noisefilter", "1", NULL, CVAR_ARCHIVE, "Enable the use of the noise cancelation filter.", 0); cvar_t cl_voip_autogain = CVARAFDC("cl_voip_autogain", "0", NULL, CVAR_ARCHIVE, "Attempts to normalize your voice levels to a standard level. Useful for lazy people, but interferes with voice activation levels.", 0); #endif @@ -471,6 +469,8 @@ static qboolean S_Opus_Init(void) } #endif + Con_Printf("OPUS support is experimental and should not be used\n"); //need to remove the packet length prefix. + s_voip.opus.loaded = true; return s_voip.opus.loaded; } @@ -508,6 +508,8 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un case VOIP_SPEEX_WIDE: qspeex_decoder_destroy(s_voip.decoder[sender]); break; + case VOIP_RAW: + break; case VOIP_OPUS: qopus_decoder_destroy(s_voip.decoder[sender]); break; @@ -520,23 +522,34 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un { default: //codec not supported. return; + case VOIP_RAW: + s_voip.decsamplerate[sender] = 11025; + break; case VOIP_SPEEX_OLD: case VOIP_SPEEX_NARROW: case VOIP_SPEEX_WIDE: if (!S_Speex_Init()) return; //speex not usable. if (codec == VOIP_SPEEX_NARROW) + { s_voip.decsamplerate[sender] = 8000; + s_voip.decframesize[sender] = 160; + } else if (codec == VOIP_SPEEX_WIDE) + { s_voip.decsamplerate[sender] = 16000; + s_voip.decframesize[sender] = 320; + } else + { s_voip.decsamplerate[sender] = 11025; - s_voip.decframesize[sender] = 160; + s_voip.decframesize[sender] = 160; + } if (!s_voip.decoder[sender]) { qspeex_bits_init(&s_voip.speex.decbits[sender]); qspeex_bits_reset(&s_voip.speex.decbits[sender]); - s_voip.decoder[sender] = qspeex_decoder_init(codec==VOIP_SPEEX_WIDE?s_voip.speex.modewb:s_voip.speex.modenb); + s_voip.decoder[sender] = qspeex_decoder_init((codec==VOIP_SPEEX_WIDE)?s_voip.speex.modewb:s_voip.speex.modenb); if (!s_voip.decoder[sender]) return; } @@ -550,7 +563,6 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un //the lazy way to reset the codec! if (!s_voip.decoder[sender]) { - s_voip.decframesize[sender] = (sizeof(decodebuf) / sizeof(decodebuf[0])) / 2; //this is the maximum size in a single frame. //opus outputs to 8, 12, 16, 24, or 48khz. pick whichever has least excess samples and resample to fit it. if (snd_speed <= 8000) s_voip.decsamplerate[sender] = 8000; @@ -565,6 +577,8 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un s_voip.decoder[sender] = qopus_decoder_create(s_voip.decsamplerate[sender], 1/*FIXME: support stereo where possible*/, NULL); if (!s_voip.decoder[sender]) return; + + s_voip.decframesize[sender] = (sizeof(decodebuf) / sizeof(decodebuf[0])) / 2; //this is the maximum size in a single frame. } else qopus_decoder_ctl(s_voip.decoder[sender], OPUS_RESET_STATE); @@ -596,7 +610,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un decodesamps += s_voip.decframesize[sender]; break; case VOIP_OPUS: - r = qopus_decode(s_voip.decoder[sender], NULL, 0, decodebuf + decodesamps, sizeof(decodebuf)/sizeof(decodebuf[0]) - decodesamps, false); + r = qopus_decode(s_voip.decoder[sender], NULL, 0, decodebuf + decodesamps, min(s_voip.decframesize[sender], sizeof(decodebuf)/sizeof(decodebuf[0]) - decodesamps), false); if (r > 0) decodesamps += r; break; @@ -606,7 +620,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un while (bytes > 0) { - if (decodesamps + s_voip.decframesize[sender] > sizeof(decodebuf)/sizeof(decodebuf[0])) + if (decodesamps + s_voip.decframesize[sender] >= sizeof(decodebuf)/sizeof(decodebuf[0])) { S_RawAudio(sender, (qbyte*)decodebuf, s_voip.decsamplerate[sender], decodesamps, 1, 2, cl_voip_play.value); decodesamps = 0; @@ -636,14 +650,43 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un decodesamps += s_voip.decframesize[sender]; s_voip.decseq[sender]++; seq++; - if (decodesamps + s_voip.decframesize[sender] > sizeof(decodebuf)/sizeof(decodebuf[0])) + if (decodesamps + s_voip.decframesize[sender] >= sizeof(decodebuf)/sizeof(decodebuf[0])) { S_RawAudio(sender, (qbyte*)decodebuf, s_voip.decsamplerate[sender], decodesamps, 1, 2, cl_voip_play.value); decodesamps = 0; } } break; + case VOIP_RAW: + len = min(bytes, sizeof(decodebuf)-(sizeof(decodebuf[0])*decodesamps)); + memcpy(decodebuf+decodesamps, start, len); + decodesamps += len / sizeof(decodebuf[0]); + s_voip.decseq[sender]++; + bytes -= len; + start += len; + break; case VOIP_OPUS: +#if 1 + len = bytes; + if (decodesamps > 0) + { + S_RawAudio(sender, (qbyte*)decodebuf, s_voip.decsamplerate[sender], decodesamps, 1, 2, cl_voip_play.value); + decodesamps = 0; + } + r = qopus_decode(s_voip.decoder[sender], start, len, decodebuf + decodesamps, sizeof(decodebuf)/sizeof(decodebuf[0]) - decodesamps, false); + Con_Printf("Decoded %i frames from %i bytes\n", r, len); + if (r > 0) + { + decodesamps += r; + s_voip.decseq[sender] += 1;//r / s_voip.decframesize[sender]; + seq += 1;//r / s_voip.decframesize[sender]; + } + else if (r < 0) + Con_Printf("Opus decoding error %i\n", r); + + bytes -= len; + start += len; +#else //FIXME: we shouldn't need this crap bytes--; len = *start++; @@ -661,6 +704,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un bytes -= len; start += len; +#endif break; } } @@ -718,6 +762,28 @@ void S_Voip_Parse(void) S_Voip_Decode(sender, codec, gen, seq, bytes, data); } +static float S_Voip_Preprocess(short *start, unsigned int samples, float micamp) +{ + int i; + float level = 0, f; + int framesize = s_voip.encframesize; + while(samples >= framesize) + { + if (s_voip.speexdsp.preproc) + qspeex_preprocess_run(s_voip.speexdsp.preproc, start); + for (i = 0; i < framesize; i++) + { + f = start[i] * micamp; + start[i] = f; + f = fabs(start[i]); + level += f*f; + } + + start += framesize; + samples -= framesize; + } + return level; +} void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) { unsigned char outbuf[8192]; @@ -726,9 +792,8 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) short *start; unsigned int initseq;//in frames unsigned int inittimestamp;//in samples - unsigned int i; unsigned int samps; - float level, f; + float level; int len; float micamp = cl_voip_micamp.value; qboolean voipsendenable = true; @@ -822,7 +887,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) qspeex_bits_init(&s_voip.speex.encbits); qspeex_bits_reset(&s_voip.speex.encbits); - s_voip.encoder = qspeex_encoder_init(voipcodec == VOIP_SPEEX_WIDE?s_voip.speex.modewb:s_voip.speex.modenb); + s_voip.encoder = qspeex_encoder_init((voipcodec == VOIP_SPEEX_WIDE)?s_voip.speex.modewb:s_voip.speex.modenb); if (!s_voip.encoder) return; qspeex_encoder_ctl(s_voip.encoder, SPEEX_GET_FRAME_SIZE, &s_voip.encframesize); @@ -835,6 +900,10 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) s_voip.encsamplerate = 11025; qspeex_encoder_ctl(s_voip.encoder, SPEEX_SET_SAMPLING_RATE, &s_voip.encsamplerate); break; + case VOIP_RAW: + s_voip.encsamplerate = 11025; + s_voip.encframesize = 256; + break; case VOIP_OPUS: if (!S_Opus_Init()) { @@ -845,6 +914,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) //use whatever is convienient. s_voip.encsamplerate = 48000; s_voip.encframesize = s_voip.encsamplerate / 400; //2.5ms frames, at a minimum. + s_voip.encframesize *= 4; //go for 10ms s_voip.encoder = qopus_encoder_create(s_voip.encsamplerate, 1, OPUS_APPLICATION_VOIP, NULL); if (!s_voip.encoder) return; @@ -907,6 +977,8 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) case VOIP_SPEEX_WIDE: qspeex_bits_reset(&s_voip.speex.encbits); break; + case VOIP_RAW: + break; case VOIP_OPUS: qopus_encoder_ctl(s_voip.encoder, OPUS_RESET_STATE); break; @@ -960,21 +1032,17 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) s_voip.speexdsp.cursamplerate = s_voip.encsamplerate; } } - if (s_voip.speexdsp.preproc) - qspeex_preprocess_run(s_voip.speexdsp.preproc, start); } - - for (i = 0; i < s_voip.encframesize; i++) + else if (s_voip.speexdsp.preproc) { - f = start[i] * micamp; - start[i] = f; - f = fabs(start[i]); - level += f*f; + qspeex_preprocess_state_destroy(s_voip.speexdsp.preproc); + s_voip.speexdsp.preproc = NULL; } switch(s_voip.enccodec) { case VOIP_SPEEX_OLD: + level += S_Voip_Preprocess(start, s_voip.encframesize, micamp); qspeex_bits_reset(&s_voip.speex.encbits); qspeex_encode_int(s_voip.encoder, start, &s_voip.speex.encbits); len = qspeex_bits_write(&s_voip.speex.encbits, outbuf+(outpos+1), sizeof(outbuf) - (outpos+1)); @@ -983,7 +1051,6 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) outbuf[outpos] = len; outpos += 1+len; s_voip.encsequence++; - s_voip.enctimestamp += s_voip.encframesize; samps+=s_voip.encframesize; encpos += s_voip.encframesize*2; break; @@ -993,19 +1060,76 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) for (; s_voip.capturepos-encpos >= s_voip.encframesize*2 && sizeof(outbuf)-outpos > 64; ) { start = (short*)(s_voip.capturebuf + encpos); + level += S_Voip_Preprocess(start, s_voip.encframesize, micamp); qspeex_encode_int(s_voip.encoder, start, &s_voip.speex.encbits); s_voip.encsequence++; samps+=s_voip.encframesize; - s_voip.enctimestamp += s_voip.encframesize; encpos += s_voip.encframesize*2; - if (rtpstream) + if (rtpstream) //FIXME: why? break; } len = qspeex_bits_write(&s_voip.speex.encbits, outbuf+outpos, sizeof(outbuf) - outpos); outpos += len; break; + case VOIP_RAW: + len = s_voip.capturepos-encpos; //amount of data to be eaten in this frame + len = min(len, sizeof(outbuf)-outpos); + len &= ~((s_voip.encframesize*2)-1); + level += S_Voip_Preprocess(start, len/2, micamp); + memcpy(outbuf+outpos, start, len); //'encode' + outpos += len; //bytes written to output + encpos += len; //number of bytes consumed + + s_voip.encsequence++; //increment number of packets, for packetloss detection. + samps+=len / 2; //number of samplepairs eaten in this packet. for stats. + break; case VOIP_OPUS: +#if 1 + { + //opus rtp only supports/allows a single chunk in each packet. + int frames; + //densely pack the frames. + start = (short*)(s_voip.capturebuf + encpos); + frames = (s_voip.capturepos-encpos)/2; + frames = s_voip.encframesize; + if (frames >= 2880) + frames = 2880; + else if (frames >= 1920) + frames = 1920; + else if (frames >= 960) + frames = 960; + else if (frames >= 480) + frames = 480; + else if (frames >= 240) + frames = 240; + else if (frames >= 120) + frames = 120; + else + { + Con_Printf("invalid Opus frame size\n"); + frames = 0; + } + Con_Printf("Encoding %i frames", frames); + level += S_Voip_Preprocess(start, frames, micamp); + len = qopus_encode(s_voip.encoder, start, frames, outbuf+outpos, sizeof(outbuf) - outpos); + Con_Printf(" (%i bytes)\n", len); + if (len >= 0) + { + s_voip.encsequence += frames / s_voip.encframesize; + outpos += len; + samps+=frames; + encpos += frames*2; + } + else + { + Con_Printf("Opus encoding error: %i\n", len); + encpos = s_voip.capturepos; + } + } + break; +#else + level += S_Voip_Preprocess(start, s_voip.encframesize, micamp); len = qopus_encode(s_voip.encoder, start, s_voip.encframesize, outbuf+(outpos+1), max(255, sizeof(outbuf) - (outpos+1))); if (len == 1) //packet does not need to be transmitted if it returns 1, supposedly. crazyness. len = 0; @@ -1021,20 +1145,21 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) } s_voip.encsequence++; samps+=s_voip.encframesize; - s_voip.enctimestamp += s_voip.encframesize; encpos += s_voip.encframesize*2; break; +#endif default: outbuf[outpos] = 0; break; } - if (rtpstream) + if (rtpstream || s_voip.enccodec == VOIP_OPUS) break; } if (samps) { float nl; + s_voip.enctimestamp += samps; nl = (3000*level) / (32767.0f*32767*samps); s_voip.voiplevel = (s_voip.voiplevel*7 + nl)/8; if (s_voip.voiplevel < cl_voip_vad_threshhold.ival && !(cl_voip_send.ival & 6)) @@ -1188,134 +1313,6 @@ void S_Voip_Parse(void) #endif -sounddriver pOPENAL_InitCard; -sounddriver pDSOUND_InitCard; -sounddriver pALSA_InitCard; -sounddriver pSNDIO_InitCard; -sounddriver pOSS_InitCard; -sounddriver pMacOS_InitCard; -sounddriver pSDL_InitCard; -sounddriver pWAV_InitCard; -sounddriver pDroid_InitCard; -sounddriver pAHI_InitCard; -#ifdef NACL -extern sounddriver pPPAPI_InitCard; -#endif - -typedef struct { - char *name; - sounddriver *ptr; -} sdriver_t; -sdriver_t drivers[] = { -//in order of preference - {"OpenAL", &pOPENAL_InitCard}, //yay, get someone else to sort out sound support, woot - - {"DSound", &pDSOUND_InitCard}, //prefered on windows - {"MacOS", &pMacOS_InitCard}, //prefered on mac - {"Droid", &pDroid_InitCard}, //prefered on android (java thread) - {"AHI", &pAHI_InitCard}, //prefered on morphos -#ifdef NACL - {"PPAPI", &pPPAPI_InitCard}, //google's native client -#endif - {"SNDIO", &pSNDIO_InitCard}, //prefered on OpenBSD - - {"SDL", &pSDL_InitCard}, //prefered on linux - {"ALSA", &pALSA_InitCard}, //pure shite - {"OSS", &pOSS_InitCard}, //good, but not likely to work any more - - {"WaveOut", &pWAV_InitCard}, //doesn't work properly in vista, etc. - {NULL, NULL} -}; - -static int SNDDMA_Init(soundcardinfo_t *sc, int *cardnum, int *drivernum) -{ - sdriver_t *sd; - int st = 0; - - memset(sc, 0, sizeof(*sc)); - - // set requested rate - if (snd_khz.ival >= 1000) - sc->sn.speed = snd_khz.ival; - else if (snd_khz.ival <= 0) - sc->sn.speed = 22050; -/* else if (snd_khz.ival >= 195) - sc->sn.speed = 200000; - else if (snd_khz.ival >= 180) - sc->sn.speed = 192000; - else if (snd_khz.ival >= 90) - sc->sn.speed = 96000; */ - else if (snd_khz.ival >= 45) - sc->sn.speed = 48000; - else if (snd_khz.ival >= 30) - sc->sn.speed = 44100; - else if (snd_khz.ival >= 20) - sc->sn.speed = 22050; - else if (snd_khz.ival >= 10) - sc->sn.speed = 11025; - else - sc->sn.speed = 8000; - - // set requested speaker count - if (snd_speakers.ival > MAXSOUNDCHANNELS) - sc->sn.numchannels = MAXSOUNDCHANNELS; - else if (snd_speakers.ival > 1) - sc->sn.numchannels = (int)snd_speakers.ival; - else - sc->sn.numchannels = 1; - - // set requested sample bits - if (snd_samplebits.ival >= 16) - sc->sn.samplebits = 16; - else - sc->sn.samplebits = 8; - - // set requested buffer size - if (snd_buffersize.ival > 0) - sc->sn.samples = snd_buffersize.ival * sc->sn.numchannels; - else - sc->sn.samples = 0; - - if (*snd_driver.string) - { - if (*drivernum) - return 2; - for (sd = drivers; sd->name; sd++) - if (!Q_strcasecmp(sd->name, snd_driver.string)) - break; - } - else - sd = &drivers[*drivernum]; - if (!sd->ptr) - return 2; //no more cards. - if (!*sd->ptr) //driver not loaded - { - Con_DPrintf("Sound driver %s is not loaded\n", sd->name); - st = 2; - } - else - { - Con_DPrintf("Trying to load a %s sound device\n", sd->name); - st = (**sd->ptr)(sc, *cardnum); - } - - if (st == 1) //worked - { - *cardnum += 1; //use the next card next time - return st; - } - else if (st == 0) //failed, try the next card with this driver. - { - *cardnum += 1; - return SNDDMA_Init(sc, cardnum, drivernum); - } - else //card number wasn't valid, try the first card of the next driver - { - *cardnum = 0; - *drivernum += 1; - return SNDDMA_Init(sc, cardnum, drivernum); - } -} void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc) { @@ -1370,6 +1367,211 @@ void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc) } +sounddriver_t DSOUND_Output; +sounddriver_t OPENAL_Output; + +sounddriver pALSA_InitCard; +sounddriver pSNDIO_InitCard; +sounddriver pOSS_InitCard; +sounddriver pMacOS_InitCard; +sounddriver pSDL_InitCard; +sounddriver pWAV_InitCard; +sounddriver pDroid_InitCard; +sounddriver pAHI_InitCard; +#ifdef NACL +extern sounddriver pPPAPI_InitCard; +#endif + +//in order of preference +sounddriver_t *outputdrivers[] = +{ + &OPENAL_Output, + &DSOUND_Output, + NULL +}; +typedef struct { + char *name; + sounddriver *ptr; +} sdriver_t; +sdriver_t olddrivers[] = { +//in order of preference + {"MacOS", &pMacOS_InitCard}, //prefered on mac + {"Droid", &pDroid_InitCard}, //prefered on android (java thread) + {"AHI", &pAHI_InitCard}, //prefered on morphos +#ifdef NACL + {"PPAPI", &pPPAPI_InitCard}, //google's native client +#endif + {"SNDIO", &pSNDIO_InitCard}, //prefered on OpenBSD + + {"SDL", &pSDL_InitCard}, //prefered on linux + {"ALSA", &pALSA_InitCard}, //pure shite + {"OSS", &pOSS_InitCard}, //good, but not likely to work any more + + {"WaveOut", &pWAV_InitCard}, //doesn't work properly in vista, etc. + {NULL, NULL} +}; + +static soundcardinfo_t *SNDDMA_Init(char *driver, char *device) +{ + soundcardinfo_t *sc = Z_Malloc(sizeof(soundcardinfo_t)); + sdriver_t *od; + sounddriver_t *sd; + int i; + int st; + + memset(sc, 0, sizeof(*sc)); + + // set requested rate + if (snd_khz.ival >= 1000) + sc->sn.speed = snd_khz.ival; + else if (snd_khz.ival <= 0) + sc->sn.speed = 22050; +/* else if (snd_khz.ival >= 195) + sc->sn.speed = 200000; + else if (snd_khz.ival >= 180) + sc->sn.speed = 192000; + else if (snd_khz.ival >= 90) + sc->sn.speed = 96000; */ + else if (snd_khz.ival >= 45) + sc->sn.speed = 48000; + else if (snd_khz.ival >= 30) + sc->sn.speed = 44100; + else if (snd_khz.ival >= 20) + sc->sn.speed = 22050; + else if (snd_khz.ival >= 10) + sc->sn.speed = 11025; + else + sc->sn.speed = 8000; + + // set requested speaker count + if (snd_speakers.ival > MAXSOUNDCHANNELS) + sc->sn.numchannels = MAXSOUNDCHANNELS; + else if (snd_speakers.ival > 1) + sc->sn.numchannels = (int)snd_speakers.ival; + else + sc->sn.numchannels = 1; + + // set requested sample bits + if (snd_samplebits.ival >= 16) + sc->sn.samplebits = 16; + else + sc->sn.samplebits = 8; + + // set requested buffer size + if (snd_buffersize.ival > 0) + sc->sn.samples = snd_buffersize.ival * sc->sn.numchannels; + else + sc->sn.samples = 0; + + for (i = 0; outputdrivers[i]; i++) + { + sd = outputdrivers[i]; + if (sd && !driver || !Q_strcasecmp(sd->name, driver)) + { + //skip drivers which are not present. + if (!sd->InitCard) + continue; + + st = (**sd->InitCard)(sc, device); + if (st) + { + S_DefaultSpeakerConfiguration(sc); + if (sndcardinfo) + { //if the sample speeds of multiple soundcards do not match, it'll fail. + if (snd_speed != sc->sn.speed) + { + Con_Printf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\nTry running Quake with -singlesound to use just the primary soundcard\n", sc->name); + S_ShutdownCard(sc); + continue; + } + } + else + snd_speed = sc->sn.speed; + + sc->next = sndcardinfo; + sndcardinfo = sc; + return sc; + } + } + } + + for (i = 0; olddrivers[i].name; i++) + { + od = &olddrivers[i]; + if (!driver || !Q_strcasecmp(od->name, driver)) + { + //skip drivers which are not present. + if (!*od->ptr) + continue; + + st = (**od->ptr)(sc, device?atoi(device):0); + if (st == 1) + { + S_DefaultSpeakerConfiguration(sc); + if (sndcardinfo) + { //if the sample speeds of multiple soundcards do not match, it'll fail. + if (snd_speed != sc->sn.speed) + { + Con_Printf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\nTry running Quake with -singlesound to use just the primary soundcard\n", sc->name); + S_ShutdownCard(sc); + continue; + } + } + else + snd_speed = sc->sn.speed; + + sc->next = sndcardinfo; + sndcardinfo = sc; + return sc; + } + } + } + + Z_Free(sc); + Con_Printf("Could not start \"%s\" device \"%s\"\n", driver?driver:"audio", device?device:"default"); + return NULL; +} + +int numsoundoutdevices; +char **soundoutdevicecodes; +char **soundoutdevicenames; +void QDECL S_EnumeratedOutDevice(const char *driver, const char *devicecode, const char *readabledevice) +{ + const char *fullintname; + + if (devicecode && strchr(devicecode, ' ')) + fullintname = va("\"%s:%s\"", driver, devicecode); + else if (devicecode) + fullintname = va("%s:%s", driver, devicecode); + else + fullintname = driver; + + soundoutdevicecodes = realloc(soundoutdevicecodes, (numsoundoutdevices+2) * sizeof(char*)); + soundoutdevicecodes[numsoundoutdevices] = strdup(fullintname); + soundoutdevicecodes[numsoundoutdevices+1] = NULL; + soundoutdevicenames = realloc(soundoutdevicenames, (numsoundoutdevices+2) * sizeof(char*)); + soundoutdevicenames[numsoundoutdevices] = strdup(readabledevice); + soundoutdevicenames[numsoundoutdevices+1] = NULL; + numsoundoutdevices++; +} +void S_EnumerateDevices(void) +{ + int i; + sounddriver_t *sd; + numsoundoutdevices = 0; + S_EnumeratedOutDevice("", NULL, "Default"); + + for (i = 0; outputdrivers[i]; i++) + { + sd = outputdrivers[i]; + if (sd && sd->name) + { + if (!sd->Enumerate || !sd->Enumerate(S_EnumeratedOutDevice)) + S_EnumeratedOutDevice(sd->name, "", va("Default %s", sd->name)); + } + } +} + /* ================ S_Startup @@ -1379,10 +1581,7 @@ S_Startup void S_ClearRaw(void); void S_Startup (void) { - int cardnum, drivernum; - int warningmessage=0; - int rc; - soundcardinfo_t *sc; + char *s; if (!snd_initialized) return; @@ -1393,51 +1592,22 @@ void S_Startup (void) snd_blocked = 0; snd_speed = 0; - for(cardnum = 0, drivernum = 0;;) + for (s = snd_device.string; ; ) { - sc = Z_Malloc(sizeof(soundcardinfo_t)); - rc = SNDDMA_Init(sc, &cardnum, &drivernum); - - if (!rc) //error stop - { - Con_Printf("S_Startup: SNDDMA_Init failed.\n"); - Z_Free(sc); + char *sep; + s = COM_Parse(s); + if (!*com_token) break; - } - if (rc == 2) //silently stop (no more cards) - { - Z_Free(sc); - break; - } - S_DefaultSpeakerConfiguration(sc); - - if (sndcardinfo) - { //if the sample speeds of multiple soundcards do not match, it'll fail. - if (snd_speed != sc->sn.speed) - { - if (!warningmessage) - { - Con_Printf("S_Startup: Ignoring soundcard %s due to mismatched sample speeds.\nTry running Quake with -singlesound to use just the primary soundcard\n", sc->name); - S_ShutdownCard(sc); - warningmessage = true; - } - - Z_Free(sc); - continue; - } - } - else - snd_speed = sc->sn.speed; - - sc->next = sndcardinfo; - sndcardinfo = sc; - - if (!snd_usemultipledevices.ival) - break; + sep = strchr(com_token, ':'); + if (sep) + *sep++ = 0; + SNDDMA_Init(com_token, sep); } + if (!sndcardinfo) + SNDDMA_Init(NULL, NULL); - sound_started = true;//!!sndcardinfo; + sound_started = true; S_ClearRaw(); @@ -1506,29 +1676,6 @@ void S_Control_f (void) S_Shutdown(); sound_started = 0; } - else if (!Q_strcasecmp(command, "multi") || !Q_strcasecmp(command, "multiple")) - { - if (!Q_strcasecmp(Cmd_Argv (2), "off")) - { - if (snd_usemultipledevices.ival) - { - Cvar_SetValue(&snd_usemultipledevices, 0); - S_Restart_f(); - } - } - else if (!snd_usemultipledevices.ival) - { - Cvar_SetValue(&snd_usemultipledevices, 1); - S_Restart_f(); - } - return; - } - if (!Q_strcasecmp(command, "single")) - { - Cvar_SetValue(&snd_usemultipledevices, 0); - S_Restart_f(); - return; - } if (!Q_strcasecmp(command, "rate") || !Q_strcasecmp(command, "speed")) { @@ -1612,6 +1759,8 @@ void S_Init (void) { int p; + S_EnumerateDevices(); + Con_DPrintf("\nSound Initialization\n"); Cmd_AddCommand("play", S_Play); @@ -1653,8 +1802,7 @@ void S_Init (void) Cvar_Register(&snd_mixerthread, "Sound controls"); #endif Cvar_Register(&snd_playersoundvolume, "Sound controls"); - Cvar_Register(&snd_usemultipledevices, "Sound controls"); - Cvar_Register(&snd_driver, "Sound controls"); + Cvar_Register(&snd_device, "Sound controls"); Cvar_Register(&snd_linearresample, "Sound controls"); Cvar_Register(&snd_linearresample_stream, "Sound controls"); @@ -1687,12 +1835,6 @@ void S_Init (void) Sys_Error ("S_Init: you must specify a speed in KB after -soundspeed"); } - if (COM_CheckParm ("-nomultipledevices") || COM_CheckParm ("-singlesound")) - Cvar_SetValue(&snd_usemultipledevices, 0); - - if (COM_CheckParm ("-multisound")) - Cvar_SetValue(&snd_usemultipledevices, 1); - snd_initialized = true; known_sfx = Z_Malloc(MAX_SFX*sizeof(sfx_t)); @@ -1740,6 +1882,17 @@ void S_Shutdown(void) Z_Free(known_sfx); known_sfx = NULL; num_sfx = 0; + + while (numsoundoutdevices) + { + numsoundoutdevices--; + free(soundoutdevicenames[numsoundoutdevices]); + free(soundoutdevicecodes[numsoundoutdevices]); + } + free(soundoutdevicenames); + soundoutdevicenames = NULL; + free(soundoutdevicecodes); + soundoutdevicecodes = NULL; } @@ -2034,7 +2187,7 @@ static void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sf target_chan->entchannel = entchannel; SND_Spatialize(sc, target_chan); - if (!target_chan->vol[0] && !target_chan->vol[1] && !target_chan->vol[2] && !target_chan->vol[3] && !target_chan->vol[4] && !target_chan->vol[5]) + if (!target_chan->vol[0] && !target_chan->vol[1] && !target_chan->vol[2] && !target_chan->vol[3] && !target_chan->vol[4] && !target_chan->vol[5] && sc->ChannelUpdate) return; // not audible at all // new channel @@ -2434,9 +2587,9 @@ static void S_UpdateCard(soundcardinfo_t *sc) } #ifdef AVAIL_OPENAL - if (sc->openal == 1) + if (sc->ListenerUpdate) { - OpenAL_Update_Listener(listener_origin, listener_forward, listener_right, listener_up, listener_velocity); + sc->ListenerUpdate(sc, listener_origin, listener_forward, listener_right, listener_up, listener_velocity); } #endif @@ -2974,6 +3127,8 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, if (si->channel[i].pos < 0) si->channel[i].pos = 0; + if (si->ChannelUpdate) + si->ChannelUpdate(si, &si->channel[i], false); break; } if (i == si->total_chans) //this one wasn't playing. @@ -2990,6 +3145,9 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, c->sfx = &s->sfx; c->start = 0; SND_Spatialize(si, c); + + if (si->ChannelUpdate) + si->ChannelUpdate(si, &si->channel[i], true); } } S_UnlockMixer(); diff --git a/engine/client/sound.h b/engine/client/sound.h index 89ccbb5e5..025ea5d86 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -190,9 +190,6 @@ void SNDVC_MicInput(qbyte *buffer, int samples, int freq, int width); #ifdef AVAIL_OPENAL -void OpenAL_LoadCache(sfx_t *s, sfxcache_t *sc); -void OpenAL_StartSound(int entnum, int entchannel, sfx_t * sfx, vec3_t origin, float fvol, float attenuation, float pitchscale); -void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity); void OpenAL_CvarInit(void); #endif @@ -236,7 +233,6 @@ extern cvar_t snd_capture; extern float voicevolumemod; extern qboolean snd_initialized; -extern cvar_t snd_usemultipledevices; extern cvar_t snd_mixerthread; extern int snd_blocked; @@ -254,6 +250,12 @@ void S_AmbientOn (void); //inititalisation functions. +typedef struct +{ + const char *name; //must be a single token, with no : + qboolean (QDECL *InitCard) (soundcardinfo_t *sc, const char *cardname); //NULL for default device. + qboolean (QDECL *Enumerate) (void (QDECL *callback) (const char *drivername, const char *devicecode, const char *readablename)); +} sounddriver_t; typedef int (*sounddriver) (soundcardinfo_t *sc, int cardnum); extern sounddriver pOPENAL_InitCard; extern sounddriver pDSOUND_InitCard; @@ -296,6 +298,7 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound void (*SetWaterDistortion) (soundcardinfo_t *sc, qboolean underwater); //if you have eax enabled, change the environment. fixme. generally this is a stub. optional. void (*Restore) (soundcardinfo_t *sc); //called before lock/unlock/lock/unlock/submit. optional void (*ChannelUpdate) (soundcardinfo_t *sc, channel_t *channel, unsigned int schanged); //properties of a sound effect changed. this is to notify hardware mixers. optional. + void (*ListenerUpdate) (soundcardinfo_t *sc, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity); //player moved or something. this is to notify hardware mixers. optional. //driver-specific - if you need more stuff, you should just shove it in the handle pointer void *thread; @@ -303,11 +306,6 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound int snd_sent; int snd_completed; int audio_fd; - -// no clue how else to handle this yet! -#ifdef AVAIL_OPENAL - int openal; -#endif }; extern soundcardinfo_t *sndcardinfo; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 0db3280aa..2e6623125 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -2421,7 +2421,10 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin cds.cbData = strlen(qtvfile); cds.lpData = (void*)qtvfile; if (SendMessage(old, WM_COPYDATA, (WPARAM)GetDesktopWindow(), (LPARAM)&cds)) + { + Sleep(10*1000); //sleep for 10 secs so the real engine has a chance to open it, if the program that gave it is watching to see if we quit. return 0; //message sent. + } } } else diff --git a/engine/client/view.c b/engine/client/view.c index 455d537fc..5f430820a 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1250,37 +1250,8 @@ void V_CalcRefdef (playerview_t *pv) r_refdef.vieworg[1] += 1.0/16; r_refdef.vieworg[2] += 1.0/16; - if (pv->fixangle) - { - if (pv->oldfixangle) - { - float frac, move; - if (cl.gametime <= cl.oldgametime) - frac = 1; - else - { - frac = (realtime - cl.gametimemark) / (cl.gametime - cl.oldgametime); - frac = bound(0, frac, 1); - } - for (i = 0; i < 3; i++) - { - move = pv->fixangles[i] - pv->oldfixangles[i]; - if (move >= 180) - move -= 360; - if (move <= -180) - move += 360; - r_refdef.viewangles[i] = pv->oldfixangles[i] + frac * move; - } - } - else - { - VectorCopy (pv->fixangles, r_refdef.viewangles); - } - } - else - { - VectorCopy (pv->simangles, r_refdef.viewangles); - } + VectorCopy (pv->simangles, r_refdef.viewangles); + V_CalcViewRoll (pv); V_AddIdle (pv); @@ -1685,7 +1656,6 @@ void V_RenderView (void) SCR_VRectForPlayer(&r_refdef.grect, viewnum); V_RenderPlayerViews(r_refdef.playerview); - GL_Set2D (false); Plug_SBar(r_refdef.playerview); SCR_TileClear (); } diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 18ae11ee1..f63bbfa6a 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -95,7 +95,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define AVAIL_OGGVORBIS /* Jogi's OpenAL support */ -// #define AVAIL_OPENAL + #define AVAIL_OPENAL #endif #if defined(MINGW) || defined(MACOSX) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index adbfb3272..5963ce92d 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2679,7 +2679,7 @@ void Cmd_set_f(void) { Cmd_ShiftArgs(1, false); text = Cmd_Args(); - if (*text == '\"') //if it's already quoted, dequote it, and ignore trailing stuff, for q2/q3 compatability + if (*text == '\"' || (*text == '\\' && text[1] == '\"')) //if it's already quoted, dequote it, and ignore trailing stuff, for q2/q3 compatability text = Cmd_Argv(1); else { diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 19c929435..e49ae68b7 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -5737,6 +5737,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) byte_vec4_t *oindex; float *opose,*oposebase; vec2_t *otcoords; + int memsize; galiasinfo_t *gai; @@ -5846,13 +5847,16 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) mesh = (struct iqmmesh*)(buffer + h->ofs_meshes); - /*allocate a nice big block of memory and figure out where stuff is*/ - gai = ZG_Malloc(&loadmodel->memgroup, sizeof(*gai)*h->num_meshes + + + memsize = sizeof(*gai)*h->num_meshes; + memsize += sizeof(*fgroup)*numgroups + sizeof(float)*12*(h->num_joints + (h->num_poses*h->num_frames)) + sizeof(*bones)*h->num_joints; + memsize += (sizeof(*opos) + sizeof(*onorm1) + sizeof(*onorm2) + sizeof(*onorm3) + sizeof(*otcoords) + (noweights?0:(sizeof(*oindex)+sizeof(*oweight)))) * h->num_vertexes; #ifndef SERVERONLY - sizeof(*skin)*h->num_meshes + sizeof(*shaders)*h->num_meshes + + memsize += sizeof(*skin)*h->num_meshes + sizeof(*shaders)*h->num_meshes; #endif - sizeof(*fgroup)*numgroups + sizeof(float)*12*(h->num_joints + (h->num_poses*h->num_frames)) + sizeof(*bones)*h->num_joints + - (sizeof(*opos) + sizeof(*onorm1) + sizeof(*onorm2) + sizeof(*onorm3) + sizeof(*otcoords) + (noweights?0:(sizeof(*oindex)+sizeof(*oweight)))) * h->num_vertexes); + + /*allocate a nice big block of memory and figure out where stuff is*/ + gai = ZG_Malloc(&loadmodel->memgroup, memsize); bones = (galiasbone_t*)(gai + h->num_meshes); opos = (vecV_t*)(bones + h->num_joints); onorm3 = (vec3_t*)(opos + h->num_vertexes); diff --git a/engine/common/common.c b/engine/common/common.c index 3ffbf2f69..2047fccdc 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -3060,6 +3060,7 @@ skipwhite: } #endif +//semi-colon delimited tokens char *COM_ParseStringSet (const char *data) { int c; @@ -3243,6 +3244,10 @@ skipwhite: goto skipwhite; } + if (c == '\\' && data[1] == '\"') + { + return COM_ParseCString(data+1, token, tokenlen); + } // handle quoted strings specially if (c == '\"') @@ -3506,13 +3511,73 @@ skipwhite: return (char*)data; } -char *COM_ParseCString (const char *data) +const char *COM_QuotedString(const char *string, char *buf, int buflen) +{ + const char *result = buf; + if (strchr(string, '\r') || strchr(string, '\n') || strchr(string, '\"')) + { + *buf++ = '\\'; //prefix so the reader knows its a quoted string. + *buf++ = '\"'; //opening quote + buflen -= 4; + while(*string && buflen >= 2) + { + switch(*string) + { + case '\n': + *buf++ = '\\'; + *buf++ = 'n'; + break; + case '\r': + *buf++ = '\\'; + *buf++ = 'r'; + break; + case '\'': + *buf++ = '\\'; + *buf++ = '\''; + break; + case '\"': + *buf++ = '\\'; + *buf++ = '\"'; + break; + case '\\': + *buf++ = '\\'; + *buf++ = '\\'; + break; + case '$': + *buf++ = '\\'; + *buf++ = '$'; + break; + default: + *buf++ = *string; + break; + } + string++; + } + *buf++ = '\"'; //closing quote + *buf++ = 0; + return result; + } + else + { + *buf++ = '\"'; //opening quote + buflen -= 3; + while(*string && buflen >= 0) + { + *buf++ = *string++; + } + *buf++ = '\"'; //closing quote + *buf++ = 0; + return result; + } +} + +char *COM_ParseCString (const char *data, char *token, int tokenlen) { int c; int len; len = 0; - com_token[0] = 0; + token[0] = 0; if (!data) return NULL; @@ -3544,16 +3609,16 @@ skipwhite: data++; while (1) { - if (len >= TOKENSIZE-2) + if (len >= tokenlen-2) { - com_token[len] = '\0'; + token[len] = '\0'; return (char*)data; } c = *data++; if (!c) { - com_token[len] = 0; + token[len] = 0; return (char*)data; } if (c == '\\') @@ -3561,28 +3626,37 @@ skipwhite: c = *data++; switch(c) { + case '\r': + if (*data == '\n') + data++; + case '\n': + continue; case 'n': c = '\n'; break; + case 'r': + c = '\r'; + break; + case '$': case '\\': - c = '\\'; + case '\'': break; case '"': c = '"'; - com_token[len] = c; + token[len] = c; len++; continue; default: - com_token[len] = 0; - return (char*)data; + c = '?'; + break; } } if (c=='\"' || !c) { - com_token[len] = 0; + token[len] = 0; return (char*)data; } - com_token[len] = c; + token[len] = c; len++; } } @@ -3590,15 +3664,15 @@ skipwhite: // parse a regular word do { - if (len >= sizeof(com_token)-1) + if (len >= tokenlen-1) break; - com_token[len] = c; + token[len] = c; data++; len++; c = *data; } while (c>32); - com_token[len] = 0; + token[len] = 0; return (char*)data; } diff --git a/engine/common/common.h b/engine/common/common.h index 76ebd005a..adf802e3b 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -273,10 +273,11 @@ extern qboolean com_eof; #define COM_Parse(d) COM_ParseOut(d,com_token, sizeof(com_token)) char *COM_ParseOut (const char *data, char *out, int outlen); char *COM_ParseStringSet (const char *data); -char *COM_ParseCString (const char *data); +char *COM_ParseCString (const char *data, char *out, int outlen); char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize); char *COM_ParseToken (const char *data, const char *punctuation); char *COM_TrimString(char *str); +const char *COM_QuotedString(const char *string, char *buf, int buflen); //inverse of COM_StringParse extern int com_argc; diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 8bc74ceaf..a3d32db19 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -1104,6 +1104,7 @@ qboolean Cvar_Command (int level) { cvar_t *v; char *str; + char buffer[65536]; // check variables v = Cvar_FindVar (Cmd_Argv(0)); @@ -1128,29 +1129,29 @@ qboolean Cvar_Command (int level) { if (v->flags & CVAR_LATCH) { - Con_Printf ("\"%s\" is currently \"%s\"\n", v->name, v->string); - Con_Printf ("Will be changed to \"%s\" on the next map\n", v->latched_string); + Con_Printf ("\"%s\" is currently %s\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer))); + Con_Printf ("Will be changed to %s on the next map\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer))); } else if (v->flags & CVAR_RENDERERLATCH) { - Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string); - Con_Printf ("Will be changed to \"%s\" on vid_restart\n", v->latched_string); + Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer))); + Con_Printf ("Will be changed to %s on vid_restart\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer))); } else { - Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->latched_string); - Con_Printf ("Effective value is \"%s\"\n", v->string); + Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer))); + Con_Printf ("Effective value is %s\n", COM_QuotedString(v->string, buffer, sizeof(buffer))); } - Con_Printf("Default: \"%s\"\n", v->defaultstr); + Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer))); } else { if (!strcmp(v->string, v->defaultstr)) - Con_Printf ("\"%s\" is \"%s\" (default)\n", v->name, v->string); + Con_Printf ("\"%s\" is %s (default)\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer))); else { - Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string); - Con_Printf("Default: \"%s\"\n", v->defaultstr); + Con_Printf ("\"%s\" is %s\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer))); + Con_Printf("Default: %s\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer))); } } return true; @@ -1170,7 +1171,7 @@ qboolean Cvar_Command (int level) #ifndef SERVERONLY if (Cmd_ExecLevel > RESTRICT_SERVER) { //directed at a secondary player. - CL_SendClientCommand(true, "%i setinfo %s \"%s\"", Cmd_ExecLevel - RESTRICT_SERVER-1, v->name, str); + CL_SendClientCommand(true, "%i setinfo %s %s", Cmd_ExecLevel - RESTRICT_SERVER-1, v->name, COM_QuotedString(str, buffer, sizeof(buffer))); return true; } @@ -1221,6 +1222,7 @@ void Cvar_WriteVariables (vfsfile_t *f, qboolean all) cvar_t *var; char *val; char *s; + char buffer[65536]; for (grp=cvar_groups ; grp ; grp=grp->next) { @@ -1242,12 +1244,12 @@ void Cvar_WriteVariables (vfsfile_t *f, qboolean all) if (var->flags & CVAR_USERCREATED) { if (var->flags & CVAR_ARCHIVE) - s = va("seta %s \"%s\"\n", var->name, val); + s = va("seta %s %s\n", var->name, COM_QuotedString(val, buffer, sizeof(buffer))); else - s = va("set %s \"%s\"\n", var->name, val); + s = va("set %s %s\n", var->name, COM_QuotedString(val, buffer, sizeof(buffer))); } else - s = va("%s \"%s\"\n", var->name, val); + s = va("%s %s\n", var->name, COM_QuotedString(val, buffer, sizeof(buffer))); VFS_WRITE(f, s, strlen(s)); } } diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 8a4695dd6..33263ee3a 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -42,7 +42,7 @@ packet header The remote connection never knows if it missed a reliable message, the local side detects that it has been dropped by seeing a sequence acknowledge -higher thatn the last reliable sequence, but without the correct evon/odd +higher thatn the last reliable sequence, but without the correct even/odd bit for the reliable set. If the sender notices that a reliable message has been dropped, it will be @@ -84,9 +84,10 @@ int net_drop; cvar_t showpackets = SCVAR("showpackets", "0"); cvar_t showdrop = SCVAR("showdrop", "0"); cvar_t qport = SCVAR("qport", "0"); -cvar_t net_mtu = CVARD("net_mtu", "1450", "Specifies a maximum udp payload size, above which packets will be fragmented. If routers all worked properly this could be some massive value, and some massive value may work really nicely for lans. Use smaller values than the default if you're connecting through nested tunnels through routers that fail with IP fragmentation."); +cvar_t net_mtu = CVARD("net_mtu", "1440", "Specifies a maximum udp payload size, above which packets will be fragmented. If routers all worked properly this could be some massive value, and some massive value may work really nicely for lans. Use smaller values than the default if you're connecting through nested tunnels through routers that fail with IP fragmentation."); cvar_t pext_replacementdeltas = CVAR("pext_replacementdeltas", "1"); +cvar_t pext_nqpredinfo = CVAR("debug_pext_nqpredinfo", "0"); /*returns the entire bitmask of supported+enabled extensions*/ unsigned int Net_PextMask(int maskset, qboolean fornq) @@ -196,7 +197,8 @@ unsigned int Net_PextMask(int maskset, qboolean fornq) if (pext_replacementdeltas.ival) mask |= PEXT2_REPLACEMENTDELTAS; - //mask |= PEXT2_PREDINFO; + if (fornq && pext_nqpredinfo.ival) + mask |= PEXT2_PREDINFO; if (MAX_CLIENTS != QWMAX_CLIENTS) mask |= PEXT2_MAXPLAYERS; @@ -206,6 +208,8 @@ unsigned int Net_PextMask(int maskset, qboolean fornq) //only ones that are tested mask &= PEXT2_VOICECHAT | PEXT2_REPLACEMENTDELTAS | PEXT2_PREDINFO; } + else + mask &= ~PEXT2_PREDINFO; } return mask; @@ -221,6 +225,7 @@ void Netchan_Init (void) { int port; + Cvar_Register (&pext_nqpredinfo, "Protocol Extensions"); Cvar_Register (&pext_replacementdeltas, "Protocol Extensions"); Cvar_Register (&showpackets, "Networking"); Cvar_Register (&showdrop, "Networking"); diff --git a/engine/common/pmovetst.c b/engine/common/pmovetst.c index bbe53db3e..2cfe62ea4 100644 --- a/engine/common/pmovetst.c +++ b/engine/common/pmovetst.c @@ -118,7 +118,7 @@ int PM_PointContents (vec3_t p) model_t *pm; pm = pmove.physents[0].model; - if (!pm) + if (!pm || pm->needload) return FTECONTENTS_EMPTY; pc = pm->funcs.PointContents(pm, NULL, p); //we need this for e2m2 - waterjumping on to plats wouldn't work otherwise. diff --git a/engine/common/protocol.h b/engine/common/protocol.h index b37226439..573e827c8 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -75,7 +75,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PEXT2_SETANGLEDELTA 0x00000004 #define PEXT2_REPLACEMENTDELTAS 0x00000008 #define PEXT2_MAXPLAYERS 0x00000010 //Client is able to cope with more players than 32. abs max becomes 255, due to colormap issues. -#define PEXT2_PREDINFO 0x00000020 //movevars, NQ input sequences+acks. +#define PEXT2_PREDINFO 0x00000020 //movevar stats, NQ input sequences+acks. //ZQuake transparent protocol extensions. #define Z_EXT_PM_TYPE (1<<0) // basic PM_TYPE functionality (reliable jump_held) @@ -164,7 +164,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svc_lightstyle 12 // [qbyte] [string] #define svc_updatename 13 // [qbyte] [string] #define svc_updatefrags 14 // [qbyte] [short] -#define svc_clientdata 15 // +#define svcnq_clientdata 15 // #define svc_stopsound 16 // #define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte] #define svc_particle 18 // [vec3] @@ -951,10 +951,12 @@ extern entity_state_t nullentitystate; #define MAX_MVDPACKET_ENTITIES 196 // doesn't count nails typedef struct { - float servertime; - int num_entities; - int max_entities; + float servertime; + int num_entities; + int max_entities; entity_state_t *entities; + qboolean fixangles[MAX_SPLITS]; + vec3_t fixedangles[MAX_SPLITS]; } packet_entities_t; typedef struct usercmd_s diff --git a/engine/common/translate.c b/engine/common/translate.c index af164380b..74393b54c 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -551,7 +551,7 @@ void TL_ParseLanguage (char *name, char *data, int num) //this is one of the fir break; } - s = COM_ParseCString(s); + s = COM_ParseCString(s, com_token, sizeof(com_token)); if (i == STL_MAXSTL) //silently ignore - allow other servers or clients to add stuff continue; diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index d23f53697..96b42fb36 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -2369,7 +2369,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) VectorScale((m+8), mod->clampscale, (m+8)); } - if (e->flags & Q2RF_WEAPONMODEL && r_refdef.currentplayernum>=0) + if (e->flags & Q2RF_WEAPONMODEL) { /*FIXME: no bob*/ float iv[16]; diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 7287153c0..daa899a73 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -60,17 +60,36 @@ extern cvar_t gl_picmip2d; texid_t D3D9_AllocNewTexture(char *ident, int width, int height, unsigned int flags) { IDirect3DTexture9 *tx; - texid_t ret = r_nulltex; - if (!FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, width, height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tx, NULL))) - ret.ptr = tx; - return ret; + + /*unconditionally allocate a new texture*/ + d3dtexture_t *tex = calloc(1, sizeof(*tex)+strlen(ident)); + strcpy(tex->name, ident); + tex->tex.ptr = NULL; + tex->tex.ref = &tex->com; + tex->next = d3dtextures; + d3dtextures = tex; + + if (!tex->tex.ptr) + { + if (!FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, width, height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tx, NULL))) + tex->tex.ptr = tx; + } + return tex->tex; } void D3D9_DestroyTexture (texid_t tex) { - IDirect3DTexture9 *tx = tex.ptr; - if (tx) - IDirect3DTexture9_Release(tx); + d3dtexture_t **link; + for (link = &d3dtextures; *link; link = &(*link)->next) + { + if (*link == (d3dtexture_t*)tex.ref) + { + *link = (*link)->next; + if (tex.ptr) + IDirect3DTexture9_Release((IDirect3DTexture9*)tex.ptr); + return; + } + } } static void D3D9_RoundDimensions(int *scaled_width, int *scaled_height, qboolean mipmap) diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index f927cff89..204d0759d 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -770,7 +770,6 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette) // pD3DX->lpVtbl->GetBufferSize((void*)pD3DX, &width, &height); vid.pixelwidth = width; vid.pixelheight = height; - vid.recalc_refdef = true; vid.width = width; vid.height = height; diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index 1560ebefb..38717715a 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -1,17 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}" - ProjectSection(ProjectDependencies) = postProject - {0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdlfte", "ftequake_SDL.vcproj", "{F384725A-62D4-4063-9941-6D8D2D6C2A47}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "npfte", "npfte.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}" - ProjectSection(ProjectDependencies) = postProject - {0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080} - EndProjectSection -EndProject Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FTEQuake", "..\setup\setup.vdproj", "{E0EE8B50-3A75-42A9-B80A-787675979B0C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "botlib", "botlib.vcproj", "{0018E098-B12A-4E4D-9B22-6772DA287080}" @@ -38,6 +26,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fs_mpq", "..\..\plugins\mpq EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpserver", "..\http\httpserver.vcproj", "{E6BAD203-4704-4860-9C38-D4702E9CAD7D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}" + ProjectSection(ProjectDependencies) = postProject + {0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dedserver", "dedserver.vcproj", "{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}" + ProjectSection(ProjectDependencies) = postProject + {0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "npfte", "npfte.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution D3DDebug|Win32 = D3DDebug|Win32 @@ -66,114 +66,6 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|Win32.ActiveCfg = D3DDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|Win32.Build.0 = D3DDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|x64.ActiveCfg = D3DDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|x64.Build.0 = D3DDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|Win32.ActiveCfg = D3DRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|Win32.Build.0 = D3DRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|x64.ActiveCfg = D3DRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|x64.Build.0 = D3DRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|Win32.ActiveCfg = Debug Dedicated Server|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|Win32.Build.0 = Debug Dedicated Server|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|x64.ActiveCfg = Debug Dedicated Server|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|x64.Build.0 = Debug Dedicated Server|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|Win32.ActiveCfg = MDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|x64.ActiveCfg = D3DRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|x64.Build.0 = D3DRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|Win32.Build.0 = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|x64.ActiveCfg = GLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|x64.Build.0 = GLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|Win32.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|Win32.Build.0 = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|x64.ActiveCfg = GLRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|x64.Build.0 = GLRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|Win32.ActiveCfg = MDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|Win32.Build.0 = MDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|x64.ActiveCfg = MDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|x64.Build.0 = MDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|Win32.ActiveCfg = MinGLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|Win32.Build.0 = MinGLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|x64.ActiveCfg = MinGLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|x64.Build.0 = MinGLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|Win32.ActiveCfg = MinGLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|Win32.Build.0 = MinGLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|x64.ActiveCfg = MinGLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|x64.Build.0 = MinGLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|Win32.ActiveCfg = MRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|Win32.Build.0 = MRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|x64.ActiveCfg = MinGLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|x64.Build.0 = MinGLDebug|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|Win32.ActiveCfg = Release Dedicated Server|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|Win32.Build.0 = Release Dedicated Server|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|x64.ActiveCfg = GLRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|x64.Build.0 = GLRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|Win32.ActiveCfg = MRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|Win32.Build.0 = MRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|x64.ActiveCfg = GLRelease|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|x64.Build.0 = GLRelease|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.D3DDebug|Win32.ActiveCfg = D3DRelease_SDL|Win32 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.D3DDebug|x64.ActiveCfg = D3DDebug_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.D3DRelease|Win32.ActiveCfg = D3DDebug_SDL|Win32 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.D3DRelease|x64.ActiveCfg = D3DDebug_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Debug Dedicated Server|Win32.ActiveCfg = Debug Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Debug Dedicated Server|x64.ActiveCfg = Debug Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Debug Dedicated Server|x64.Build.0 = Debug Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Debug|Win32.ActiveCfg = Debug Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Debug|x64.ActiveCfg = Debug Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Debug|x64.Build.0 = Debug Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.GLDebug|Win32.ActiveCfg = GLDebug_SDL|Win32 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.GLDebug|Win32.Build.0 = GLDebug_SDL|Win32 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.GLDebug|x64.ActiveCfg = GLDebug_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.GLRelease|Win32.ActiveCfg = GLRelease_SDL|Win32 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.GLRelease|Win32.Build.0 = GLRelease_SDL|Win32 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.GLRelease|x64.ActiveCfg = GLRelease_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MDebug|Win32.ActiveCfg = MDebug_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MDebug|x64.ActiveCfg = MDebug_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MinGLDebug|Win32.ActiveCfg = MinGLDebug_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MinGLDebug|x64.ActiveCfg = MinGLDebug_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MinGLRelease|Win32.ActiveCfg = MinGLRelease_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MinGLRelease|x64.ActiveCfg = MinGLRelease_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MRelease|Win32.ActiveCfg = MRelease_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.MRelease|x64.ActiveCfg = MRelease_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Release Dedicated Server|Win32.ActiveCfg = Release Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Release Dedicated Server|x64.ActiveCfg = Release Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Release Dedicated Server|x64.Build.0 = Release Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Release|Win32.ActiveCfg = Release Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Release|x64.ActiveCfg = Release Dedicated Server_SDL|x64 - {F384725A-62D4-4063-9941-6D8D2D6C2A47}.Release|x64.Build.0 = Release Dedicated Server_SDL|x64 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DDebug|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DDebug|Win32.Build.0 = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DDebug|x64.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DRelease|Win32.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DRelease|x64.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug Dedicated Server|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug Dedicated Server|Win32.Build.0 = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug Dedicated Server|x64.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|Win32.Build.0 = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|x64.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|x64.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLRelease|Win32.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLRelease|x64.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MDebug|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MDebug|x64.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLDebug|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLDebug|x64.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLRelease|Win32.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLRelease|Win32.Build.0 = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLRelease|x64.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MRelease|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MRelease|Win32.Build.0 = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MRelease|x64.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release Dedicated Server|Win32.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release Dedicated Server|Win32.Build.0 = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release Dedicated Server|x64.ActiveCfg = GLDebug|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release|Win32.ActiveCfg = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release|Win32.Build.0 = GLRelease|Win32 - {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release|x64.ActiveCfg = GLDebug|Win32 {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DDebug|Win32.ActiveCfg = Release {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DDebug|x64.ActiveCfg = Release {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DRelease|Win32.ActiveCfg = Release @@ -551,6 +443,134 @@ Global {E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release|Win32.ActiveCfg = Release|Win32 {E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release|Win32.Build.0 = Release|Win32 {E6BAD203-4704-4860-9C38-D4702E9CAD7D}.Release|x64.ActiveCfg = Release|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|Win32.ActiveCfg = D3DDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|Win32.Build.0 = D3DDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|x64.ActiveCfg = D3DDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DDebug|x64.Build.0 = D3DDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|Win32.ActiveCfg = D3DRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|Win32.Build.0 = D3DRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|x64.ActiveCfg = D3DRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.D3DRelease|x64.Build.0 = D3DRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|Win32.ActiveCfg = Debug Dedicated Server|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|Win32.Build.0 = Debug Dedicated Server|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|x64.ActiveCfg = Debug Dedicated Server|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|x64.Build.0 = Debug Dedicated Server|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|Win32.ActiveCfg = MDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|Win32.Build.0 = MDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|x64.ActiveCfg = MDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|x64.Build.0 = MDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|Win32.ActiveCfg = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|Win32.Build.0 = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|x64.ActiveCfg = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|x64.Build.0 = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|Win32.ActiveCfg = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|Win32.Build.0 = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLRelease|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|Win32.ActiveCfg = MDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|Win32.Build.0 = MDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|x64.ActiveCfg = MDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MDebug|x64.Build.0 = MDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|Win32.ActiveCfg = MinGLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|Win32.Build.0 = MinGLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|x64.ActiveCfg = MinGLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLDebug|x64.Build.0 = MinGLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|Win32.ActiveCfg = MinGLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|Win32.Build.0 = MinGLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|x64.ActiveCfg = MinGLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MinGLRelease|x64.Build.0 = MinGLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|Win32.ActiveCfg = MRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|Win32.Build.0 = MRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|x64.ActiveCfg = MRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.MRelease|x64.Build.0 = MRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|Win32.ActiveCfg = Release Dedicated Server|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|Win32.Build.0 = Release Dedicated Server|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|x64.ActiveCfg = Release Dedicated Server|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release Dedicated Server|x64.Build.0 = Release Dedicated Server|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|Win32.ActiveCfg = D3DRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|Win32.Build.0 = D3DRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|x64.ActiveCfg = D3DRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Release|x64.Build.0 = D3DRelease|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DDebug|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DDebug|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DDebug|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DRelease|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DRelease|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.D3DRelease|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|Win32.ActiveCfg = Debug Dedicated Server|Win32 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|Win32.Build.0 = Debug Dedicated Server|Win32 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug Dedicated Server|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MDebug|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MDebug|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MDebug|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MinGLDebug|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MinGLDebug|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MinGLDebug|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MinGLRelease|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MinGLRelease|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MinGLRelease|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MRelease|Win32.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MRelease|x64.ActiveCfg = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.MRelease|x64.Build.0 = Debug Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release Dedicated Server|Win32.ActiveCfg = Release Dedicated Server|Win32 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release Dedicated Server|Win32.Build.0 = Release Dedicated Server|Win32 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release Dedicated Server|x64.ActiveCfg = Release Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release Dedicated Server|x64.Build.0 = Release Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release|Win32.ActiveCfg = Release Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release|x64.ActiveCfg = Release Dedicated Server|x64 + {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release|x64.Build.0 = Release Dedicated Server|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DDebug|Win32.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DDebug|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DDebug|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DRelease|Win32.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DRelease|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.D3DRelease|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug Dedicated Server|Win32.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug Dedicated Server|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug Dedicated Server|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|Win32.ActiveCfg = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|Win32.Build.0 = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|x64.ActiveCfg = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Debug|x64.Build.0 = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|Win32.ActiveCfg = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|Win32.Build.0 = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|x64.ActiveCfg = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLDebug|x64.Build.0 = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLRelease|Win32.ActiveCfg = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLRelease|Win32.Build.0 = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLRelease|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.GLRelease|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MDebug|Win32.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MDebug|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MDebug|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLDebug|Win32.ActiveCfg = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLDebug|Win32.Build.0 = GLDebug|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLDebug|x64.ActiveCfg = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLDebug|x64.Build.0 = GLDebug|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLRelease|Win32.ActiveCfg = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLRelease|Win32.Build.0 = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLRelease|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MinGLRelease|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MRelease|Win32.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MRelease|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.MRelease|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release Dedicated Server|Win32.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release Dedicated Server|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release Dedicated Server|x64.Build.0 = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release|Win32.ActiveCfg = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release|Win32.Build.0 = GLRelease|Win32 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release|x64.ActiveCfg = GLRelease|x64 + {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1365}.Release|x64.Build.0 = GLRelease|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 7e41ddc86..6a2496918 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -4062,7 +4062,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLR_DrawPortal(batch, cl.worldmodel->batches, 1); GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); - qglViewport (0, 0, vid.pixelwidth, vid.pixelheight); + qglViewport (oprect.x, oprect.y - oprect.height, oprect.width, oprect.height); r_refdef.vrect = orect; r_refdef.pxrect = oprect; } @@ -4116,7 +4116,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) GLR_DrawPortal(batch, cl.worldmodel->batches, ((batch->shader->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); - qglViewport (0, 0, vid.pixelwidth, vid.pixelheight); + qglViewport (oprect.x, oprect.y - oprect.height, oprect.width, oprect.height); r_refdef.vrect = ovrect; r_refdef.pxrect = oprect; } @@ -4157,7 +4157,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) r_refdef.recurse = false; GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); - qglViewport (0, 0, vid.pixelwidth, vid.pixelheight); + qglViewport (oprect.x, oprect.height + oprect.y, oprect.width, oprect.height); r_refdef.vrect = orect; r_refdef.pxrect = oprect; } diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index c8472887a..8843de796 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -204,12 +204,20 @@ texid_t GL_AllocNewTexture(char *name, int w, int h, unsigned int flags) void GL_DestroyTexture(texid_t tex) { + gltexture_t **link; if (!tex.ref) return; - - //FIXME: unlink the old one - - qglDeleteTextures(1, &tex.num); + for (link = &gltextures; *link; link = &(*link)->next) + { + if (*link == (gltexture_t*)tex.ref) + { + Hash_RemoveData(&gltexturetable, (*link)->identifier, *link); + *link = (*link)->next; + qglDeleteTextures(1, &tex.num); + BZ_Free(tex.ref); + return; + } + } } //============================================================================= @@ -422,6 +430,8 @@ void GLDraw_FlushOldTextures(void) t = *link; if (t->com.regsequence != r_regsequence) { + //make sure the hash table can't still find it... + Hash_RemoveData(&gltexturetable, t->identifier, t); qglDeleteTextures(1, &t->texnum.num); (*link)->next = t->next; BZ_Free(t); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 08c2a0c55..02d0b1afc 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -1305,6 +1305,7 @@ int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode) } //obtains the width of a character from a given font. This is how wide it is. The next char should be drawn at x + result. +//FIXME: this function cannot cope with tab and should not be used. int Font_CharWidth(unsigned int charcode) { struct charcache_s *c; @@ -1324,6 +1325,7 @@ int Font_CharWidth(unsigned int charcode) } //obtains the width of a character from a given font. This is how wide it is. The next char should be drawn at x + result. +//FIXME: this function cannot cope with tab and should not be used. float Font_CharScaleWidth(unsigned int charcode) { struct charcache_s *c; diff --git a/engine/gl/gl_ngraph.c b/engine/gl/gl_ngraph.c index 2dd36c37f..72248171c 100644 --- a/engine/gl/gl_ngraph.c +++ b/engine/gl/gl_ngraph.c @@ -102,7 +102,7 @@ void R_NetGraph (void) lost = CL_CalcNet(); for (a=0 ; atype->type == ev_variant || field->type->type != ev_field || !field->type->aux_type) { if (field->type->type != ev_variant) { - QCC_PR_ParseWarning(ERR_INTERNAL, "QCC_PR_ExpandField: invalid field type"); - QCC_PR_ParsePrintDef(ERR_INTERNAL, field); + QCC_PR_ParseErrorPrintDef(ERR_INTERNAL, field, "QCC_PR_ExpandField: invalid field type"); } r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_V], ent, field, NULL); tmp = (void *)qccHunkAlloc (sizeof(QCC_def_t)); @@ -4530,8 +4530,8 @@ static QCC_def_t *QCC_PR_ExpandField(QCC_def_t *ent, QCC_def_t *field) switch(field->type->aux_type->type) { default: - QCC_PR_ParseWarning(ERR_INTERNAL, "QCC_PR_ExpandField: invalid field type"); - QCC_PR_ParsePrintDef(ERR_INTERNAL, field); + QCC_PR_ParseErrorPrintDef(ERR_INTERNAL, field, "QCC_PR_ExpandField: invalid field type"); + r = field; break; case ev_integer: r = QCC_PR_Statement(&pr_opcodes[OP_LOAD_I], ent, field, NULL); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 69a6144ac..180bbb8c2 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -67,7 +67,7 @@ static char demomsgbuf[MAX_OVERALLMSGLEN]; mvddest_t *singledest; mvddest_t *SV_InitStream(int socket); -static qboolean SV_MVD_Record (mvddest_t *dest); +qboolean SV_MVD_Record (mvddest_t *dest); char *SV_MVDName2Txt(char *name); extern cvar_t qtv_password; @@ -1586,7 +1586,7 @@ void SV_WriteSetMVDMessage (void) } void SV_MVD_SendInitialGamestate(mvddest_t *dest); -static qboolean SV_MVD_Record (mvddest_t *dest) +qboolean SV_MVD_Record (mvddest_t *dest) { if (!dest) return false; @@ -2264,7 +2264,14 @@ void SV_MVDEasyRecord_f (void) else { i = Dem_CountPlayers(); - if (teamplay.value >= 1 && i > 2) + /*if (!deathmatch.ival) + { + if (coop.ival || i>1) + snprintf (name, sizeof(name), "coop_%s_%d(%d)", sv.name, skill.ival, i); + else + snprintf (name, sizeof(name), "sp_%s_%d_%s", sv.name, skill.ival, Dem_PlayerName(0)); + } + else*/ if (teamplay.value >= 1 && i > 2) { // Teamplay snprintf (name, sizeof(name), "%don%d_", Dem_CountTeamPlayers(Dem_Team(1)), Dem_CountTeamPlayers(Dem_Team(2))); diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 8ab8fc8ab..c0aefe37e 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1240,6 +1240,9 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg) // Con_Printf("%f\n", sv.world.physicstime); } + //predinfo extension reworks stats, making svc_clientdata redundant. + if (client->fteprotocolextensions2 & PEXT2_PREDINFO) + return; bits = 0; @@ -1327,7 +1330,7 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg) // send the data - MSG_WriteByte (msg, svc_clientdata); + MSG_WriteByte (msg, svcnq_clientdata); MSG_WriteShort (msg, bits); if (bits & SU_EXTEND1) @@ -1627,16 +1630,13 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf else statsi[STAT_VIEWZOOM] = ent->xv->viewzoom*255; - if (client->fteprotocolextensions2 & PEXT2_PREDINFO) + if (client->protocol == SCP_DARKPLACES7 || (client->fteprotocolextensions2 & PEXT2_PREDINFO)) { - statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value; - statsf[STAT_MOVEVARS_ENTGRAVITY] = host_client->entgravity; - statsf[STAT_MOVEVARS_MAXSPEED] = host_client->maxspeed; - } - if (client->protocol == SCP_DARKPLACES7) - { - /*note: statsf is truncated, which would mess things up*/ - float *statsfi = (float*)statsi; + float *statsfi; + if (client->fteprotocolextensions2 & PEXT2_PREDINFO) + statsfi = statsf; + else + statsfi = (float*)statsi; /*dp requires a union of ints and floats, which is rather hideous...*/ // statsfi[STAT_MOVEVARS_WALLFRICTION] = sv_wall statsfi[STAT_MOVEVARS_FRICTION] = sv_friction.value; statsfi[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value; @@ -1649,7 +1649,7 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf statsfi[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value; statsfi[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value; statsfi[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value; - statsfi[STAT_MOVEVARS_ENTGRAVITY] = host_client->entgravity; + statsfi[STAT_MOVEVARS_ENTGRAVITY] = host_client->entgravity/sv_gravity.value; statsfi[STAT_MOVEVARS_JUMPVELOCITY] = 270;//sv_jumpvelocity.value; //bah statsfi[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value; statsfi[STAT_MOVEVARS_MAXAIRSPEED] = host_client->maxspeed; diff --git a/plugins/avplug/avdecode.c b/plugins/avplug/avdecode.c index 0ad5e5932..1493baf15 100644 --- a/plugins/avplug/avdecode.c +++ b/plugins/avplug/avdecode.c @@ -393,6 +393,7 @@ static qintptr_t AVDec_Shutdown(qintptr_t *args) static media_decoder_funcs_t decoderfuncs = { + "avplug", AVDec_Create, AVDec_DisplayFrame, NULL,//doneframe @@ -429,7 +430,10 @@ qintptr_t Plug_Init(qintptr_t *args) okay |= AVDec_Init(); okay |= AVEnc_Init(); if (okay) + { av_register_all(); + avcodec_register_all(); + } return okay; } diff --git a/plugins/avplug/avencode.c b/plugins/avplug/avencode.c index 2b67c0b32..caff80254 100644 --- a/plugins/avplug/avencode.c +++ b/plugins/avplug/avencode.c @@ -290,7 +290,7 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height audiocodec = avcodec_find_encoder_by_name(codecname); if (!audiocodec) { - Con_Printf("Unsupported avplug_codec \"%s\"\n", codecname); + Con_Printf("avplug: Unsupported avplug_codec \"%s\"\n", codecname); return NULL; } } @@ -299,19 +299,19 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height } } - Con_DPrintf("Using format \"%s\"\n", fmt->name); + Con_DPrintf("avplug: Using format \"%s\"\n", fmt->name); if (videocodec) - Con_DPrintf("Using Video Codec \"%s\"\n", videocodec->name); + Con_DPrintf("avplug: Using Video Codec \"%s\"\n", videocodec->name); else - Con_DPrintf("Not encoding video\n"); + Con_DPrintf("avplug: Not encoding video\n"); if (audiocodec) - Con_DPrintf("Using Audio Codec \"%s\"\n", audiocodec->name); + Con_DPrintf("avplug: Using Audio Codec \"%s\"\n", audiocodec->name); else - Con_DPrintf("Not encoding audio\n"); + Con_DPrintf("avplug: Not encoding audio\n"); if (!videocodec && !audiocodec) { - Con_DPrintf("Nothing to encode!\n"); + Con_DPrintf("avplug: Nothing to encode!\n"); return NULL; } @@ -339,7 +339,7 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height AVCodecContext *c = ctx->video_st->codec; if (avcodec_open2(c, videocodec, NULL) < 0) { - Con_Printf("Could not init codec instance \"%s\". Maybe try a different framerate/resolution/bitrate\n", videocodec->name); + Con_Printf("avplug: Could not init codec instance \"%s\". Maybe try a different framerate/resolution/bitrate\n", videocodec->name); AVEnc_End(ctx); return NULL; } @@ -360,7 +360,7 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height AVCodecContext *c = ctx->audio_st->codec; if (avcodec_open2(c, audiocodec, NULL) < 0) { - Con_Printf("Could not init codec instance \"%s\".\n", audiocodec->name); + Con_Printf("avplug: Could not init codec instance \"%s\".\n", audiocodec->name); AVEnc_End(ctx); return NULL; } @@ -406,6 +406,7 @@ static void AVEnc_End (void *vctx) } static media_encoder_funcs_t encoderfuncs = { + "avplug", AVEnc_Begin, AVEnc_Video, AVEnc_Audio, @@ -438,15 +439,15 @@ menutext 0 24 "Cancel" qboolean AVEnc_Init(void) { - pCvar_Register("avplug_format", "", 0, "avplug"); + pCvar_Register("avplug_format", "mp4", 0, "avplug"); - pCvar_Register("avplug_videocodec", "", 0, "avplug"); - pCvar_Register("avplug_videocodecprofile", "", 0, "avplug"); - pCvar_Register("avplug_videobitrate", "4000000", 0, "avplug"); - pCvar_Register("avplug_videoforcewidth", "", 0, "avplug"); - pCvar_Register("avplug_videoforceheight", "", 0, "avplug"); - pCvar_Register("avplug_audiocodec", "", 0, "avplug"); - pCvar_Register("avplug_audiobitrate", "64000", 0, "avplug"); + pCvar_Register("avplug_videocodec", "mpeg4", 0, "avplug"); + pCvar_Register("avplug_videocodecprofile", "", 0, "avplug"); + pCvar_Register("avplug_videobitrate", "4000000", 0, "avplug"); + pCvar_Register("avplug_videoforcewidth", "", 0, "avplug"); + pCvar_Register("avplug_videoforceheight", "", 0, "avplug"); + pCvar_Register("avplug_audiocodec", "libmp3lame", 0, "avplug"); + pCvar_Register("avplug_audiobitrate", "64000", 0, "avplug"); if (!pPlug_ExportNative("Media_VideoEncoder", &encoderfuncs)) { diff --git a/plugins/mpq/fs_mpq.vcproj b/plugins/mpq/fs_mpq.vcproj new file mode 100644 index 000000000..70673e3ef --- /dev/null +++ b/plugins/mpq/fs_mpq.vcproj @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +