diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 2b55edbf..00e42e72 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2688,7 +2688,7 @@ void CLQ1_AddVisibleBBoxes(void) for (i = 1; i < w->num_edicts; i++) { e = WEDICT_NUM(w->progs, i); - if (e->isfree) + if (ED_ISFREE(e)) continue; if (r_showbboxes.ival & 4) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index b87fb2b4..c0992b96 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -52,7 +52,7 @@ usercmd_t independantphysics[MAX_SPLITS]; vec3_t mousemovements[MAX_SPLITS]; /*kinda a hack...*/ -int con_splitmodifier; +unsigned int con_splitmodifier; cvar_t cl_forceseat = CVARAD("in_forceseat", "0", "in_forcesplitclient", "Overrides the device identifiers to control a specific client from any device. This can be used for debugging mods, where you only have one keyboard/mouse."); extern cvar_t cl_splitscreen; int CL_TargettedSplit(qboolean nowrap) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index cfd442f4..918b8c9e 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -67,6 +67,7 @@ void RSpeedShow(void) RSpNames[RSPEED_SUBMIT] = "submit/finish"; RSpNames[RSPEED_PRESENT] = "present"; + RSpNames[RSPEED_ACQUIRE] = "acquire"; memset(RQntNames, 0, sizeof(RQntNames)); RQntNames[RQUANT_MSECS] = "Microseconds"; @@ -294,7 +295,8 @@ CENTER PRINTING typedef struct { unsigned int flags; - conchar_t string[1024]; + conchar_t *string; + size_t stringbytes; char titleimage[MAX_QPATH]; unsigned int charcount; float time_start; // for slow victory printing @@ -493,7 +495,20 @@ void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode) } } - p->charcount = COM_ParseFunString(CON_WHITEMASK, str, p->string, sizeof(p->string), false) - p->string; + for (;;) + { + p->charcount = COM_ParseFunString(CON_WHITEMASK, str, p->string, p->stringbytes, false) - p->string; + + if ((p->charcount+1)*sizeof(*p->string) < p->stringbytes) + break; + else + { + p->stringbytes=p->stringbytes*2+sizeof(*p->string); + Z_Free(p->string); + p->string = Z_Malloc(p->stringbytes); + } + } + p->time_off = scr_centertime.value; p->time_start = cl.time; } @@ -514,7 +529,21 @@ void VARGS Stats_Message(char *msg, ...) p->flags = CPRINT_OBITUARTY; p->titleimage[0] = 0; - p->charcount = COM_ParseFunString(CON_WHITEMASK, str, p->string, sizeof(p->string), false) - p->string; + + for (;;) + { + p->charcount = COM_ParseFunString(CON_WHITEMASK, str, p->string, p->stringbytes, false) - p->string; + + if ((p->charcount+1)*sizeof(*p->string) < p->stringbytes) + break; + else + { + p->stringbytes=p->stringbytes*2+sizeof(*p->string); + Z_Free(p->string); + p->string = Z_Malloc(p->stringbytes); + } + } + p->time_off = scr_centertime.value; p->time_start = cl.time; } @@ -696,14 +725,17 @@ void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int { cprint_t p; vrect_t r; + conchar_t buffer[16384]; //FIXME: make dynamic. + p.string = buffer; + p.stringbytes = sizeof(buffer); r.x = x; r.y = y; r.width = w; r.height = h; p.flags = fieldflags; - p.charcount = COM_ParseFunString(defaultmask, text, p.string, sizeof(p.string), false) - p.string; + p.charcount = COM_ParseFunString(defaultmask, text, p.string, p.stringbytes, false) - p.string; p.time_off = scr_centertime.value; p.time_start = cl.time; *p.titleimage = 0; @@ -2963,6 +2995,12 @@ void SCR_DeInit (void) } key_customcursor[i].dirty = true; } + for (i = 0; i < countof(scr_centerprint); i++) + { + Z_Free(scr_centerprint[i].string); + scr_centerprint[i].string = NULL; + scr_centerprint[i].stringbytes = 0; + } if (scr_initialized) { scr_initialized = false; diff --git a/engine/client/client.h b/engine/client/client.h index ba1d065c..11bf7141 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1360,10 +1360,10 @@ void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd); void CSQC_WorldLoaded(void); qboolean CSQC_ParseTempEntity(void); qboolean CSQC_ConsoleCommand(char *cmd); -qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid); -qboolean CSQC_MouseMove(float xdelta, float ydelta, int devid); -qboolean CSQC_MousePosition(float xabs, float yabs, int devid); -qboolean CSQC_JoystickAxis(int axis, float value, int devid); +qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid); +qboolean CSQC_MouseMove(float xdelta, float ydelta, unsigned int devid); +qboolean CSQC_MousePosition(float xabs, float yabs, unsigned int devid); +qboolean CSQC_JoystickAxis(int axis, float value, unsigned int devid); qboolean CSQC_Accelerometer(float x, float y, float z); qboolean CSQC_Gyroscope(float x, float y, float z); int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod, float timeofs, unsigned int flags); diff --git a/engine/client/console.c b/engine/client/console.c index 5734fba8..07f1c411 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -2790,12 +2790,12 @@ void Con_NotifyBox (char *text) qboolean hadconsole; // during startup for sound / cd warnings - Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); + Con_Printf("\n\n^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f\n"); Con_Printf ("%s", text); Con_Printf ("Press a key.\n"); - Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); + Con_Printf("^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f\n"); key_count = -2; // wait for a key down and up hadconsole = !!Key_Dest_Has(kdm_console); diff --git a/engine/client/image.c b/engine/client/image.c index 18344c11..b8e8e6d8 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -2961,6 +2961,47 @@ static void Image_MipMap8888 (qbyte *in, int inwidth, int inheight, qbyte *out, } } +static qbyte Image_BlendPalette_2(qbyte a, qbyte b) +{ + return a; +} +static qbyte Image_BlendPalette_4(qbyte a, qbyte b, qbyte c, qbyte d) +{ + return a; +} +//this is expected to be slow, thanks to those two expensive helpers. +static void Image_MipMap8Pal (qbyte *in, int inwidth, int inheight, qbyte *out, int outwidth, int outheight) +{ + int i, j; + qbyte *inrow; + + int rowwidth = inwidth; //rowwidth is the byte width of the input + inrow = in; + + //mips round down, except for when the input is 1. which bugs out. + if (inwidth <= 1 && inheight <= 1) + out[0] = in[0]; + else if (inheight <= 1) + { + //single row, don't peek at the next + for (in = inrow, j=0 ; jencoding) { case PTI_R8: + if (sh_config.can_mipcap) + return; //if we can cap mips, do that. it'll save lots of expensive lookups and uglyness. + for (mip = mips->mipcount; mip < 32; mip++) + { + mips->mip[mip].width = mips->mip[mip-1].width >> 1; + mips->mip[mip].height = mips->mip[mip-1].height >> 1; + if (mips->mip[mip].width < 1 && mips->mip[mip].height < 1) + break; + if (mips->mip[mip].width < 1) + mips->mip[mip].width = 1; + if (mips->mip[mip].height < 1) + mips->mip[mip].height = 1; + mips->mip[mip].datasize = ((mips->mip[mip].width+3)&~3) * mips->mip[mip].height*4; + mips->mip[mip].data = BZ_Malloc(mips->mip[mip].datasize); + mips->mip[mip].needfree = true; + + Image_MipMap8Pal(mips->mip[mip-1].data, mips->mip[mip-1].width, mips->mip[mip-1].height, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height); + mips->mipcount = mip+1; + } return; case PTI_RGBA8: case PTI_RGBX8: diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index 128ea08f..51d13eda 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -127,7 +127,7 @@ struct eventlist_s IEV_MOUSEDELTA, IEV_JOYAXIS } type; - int devid; + unsigned int devid; union { @@ -171,7 +171,7 @@ struct mouse_s M_MOUSE, //using deltas M_TOUCH //using absolutes } type; - int qdeviceid; //so we can just use pointers. + unsigned int qdeviceid; //so we can just use pointers. vec2_t oldpos; vec2_t downpos; float moveddist; //how far it has moved while held. this provides us with our emulated mouse1 when they release the press @@ -187,7 +187,7 @@ int touchcursor; //the cursor follows whichever finger was most recently pressed #define MAXJOYSTICKS 8 struct joy_s { - int qdeviceid; + unsigned int qdeviceid; float axis[MAXJOYAXIS]; } joy[MAXJOYSTICKS]; @@ -220,11 +220,11 @@ struct remapctx { char *type; char *devicename; - int newdevid; + unsigned int newdevid; unsigned int found; unsigned int failed; }; -static void IN_DeviceIDs_DoRemap(void *vctx, const char *type, const char *devicename, int *qdevid) +static void IN_DeviceIDs_DoRemap(void *vctx, const char *type, const char *devicename, unsigned int *qdevid) { struct remapctx *ctx = vctx; @@ -238,7 +238,7 @@ static void IN_DeviceIDs_DoRemap(void *vctx, const char *type, const char *devic ctx->found++; } } -void IN_DeviceIDs_Enumerate(void *ctx, const char *type, const char *devicename, int *qdevid) +void IN_DeviceIDs_Enumerate(void *ctx, const char *type, const char *devicename, unsigned int *qdevid) { char buf[8192]; devicename = COM_QuotedString(devicename, buf, sizeof(buf), false); @@ -247,7 +247,7 @@ void IN_DeviceIDs_Enumerate(void *ctx, const char *type, const char *devicename, else if (*qdevid == DEVID_UNSET) Con_Printf("%s\t%s\t%s\n", type, "Unset", devicename); else - Con_Printf("%s\t%i\t%s\n", type, *qdevid, devicename); + Con_Printf("%s\t%u\t%s\n", type, *qdevid, devicename); } void IN_DeviceIDs_f(void) @@ -259,7 +259,7 @@ void IN_DeviceIDs_f(void) ctx.failed = false; ctx.found = 0; ctx.type = Cmd_Argv(1); - ctx.newdevid = atoi(Cmd_Argv(2)); + ctx.newdevid = strtoul(Cmd_Argv(2), NULL, 0); ctx.devicename = Cmd_Argv(3); INS_EnumerateDevices(&ctx, IN_DeviceIDs_DoRemap); @@ -333,7 +333,7 @@ void IN_Init(void) } //tells the keys.c code whether the cursor is currently active, causing mouse clicks instead of binds. -qboolean IN_MouseDevIsTouch(int devid) +qboolean IN_MouseDevIsTouch(unsigned int devid) { if (devid < MAXPOINTERS) return ptr[devid].type == M_TOUCH; @@ -343,7 +343,7 @@ qboolean IN_MouseDevIsTouch(int devid) //translates MOUSE1 press events into begin-look-or-strafe events. //translates to MOUSE2 accordingly //returns 0 if it ate it completely. -int IN_TranslateMButtonPress(int devid) +int IN_TranslateMButtonPress(unsigned int devid) { int ret; if (!ptr[devid].down) @@ -919,7 +919,7 @@ void IN_Move (float *movements, int pnum, float frametime) IN_MoveJoystick(&joy[i], movements, pnum, frametime); } -void IN_JoystickAxisEvent(int devid, int axis, float value) +void IN_JoystickAxisEvent(unsigned int devid, int axis, float value) { struct eventlist_s *ev = in_newevent(); if (!ev) @@ -931,7 +931,7 @@ void IN_JoystickAxisEvent(int devid, int axis, float value) in_finishevent(); } -void IN_KeyEvent(int devid, int down, int keycode, int unicode) +void IN_KeyEvent(unsigned int devid, int down, int keycode, int unicode) { struct eventlist_s *ev = in_newevent(); if (!ev) @@ -949,7 +949,7 @@ for multitouch, devid might be the touch identifier, which will persist until re x is horizontal, y is vertical. z is height... generally its used as a mousewheel instead, but there are some '3d' mice out there, so its provided in this api. */ -void IN_MouseMove(int devid, int abs, float x, float y, float z, float size) +void IN_MouseMove(unsigned int devid, int abs, float x, float y, float z, float size) { struct eventlist_s *ev = in_newevent(); if (!ev) diff --git a/engine/client/in_morphos.c b/engine/client/in_morphos.c index 2af7be8e..25b288cc 100644 --- a/engine/client/in_morphos.c +++ b/engine/client/in_morphos.c @@ -213,7 +213,7 @@ void INS_ProcessInputMessage(struct InputEvent *msg, qboolean consumemotion) void INS_Commands(void) { } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } void INS_Move (float *movements, int pnum) diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index d9b040d5..2c3f9c55 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -520,7 +520,7 @@ static unsigned int tbl_sdltoquake[] = 0,0, 0, //SDLK_CLEAR = 12, K_ENTER, //SDLK_RETURN = 13, - 0,0,0,0,0, + 0,0,0,0,0, K_PAUSE, //SDLK_PAUSE = 19, 0,0,0,0,0,0,0, K_ESCAPE, //SDLK_ESCAPE = 27, @@ -913,7 +913,7 @@ void INS_Accumulate(void) //input polling void INS_Commands (void) //used to Cbuf_AddText joystick button events in windows. { } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 8d054764..ebd78e28 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -2088,7 +2088,7 @@ void INS_JoyMove (float *movements, int pnum) } } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { int idx; diff --git a/engine/client/input.h b/engine/client/input.h index 76546c49..6c6d0895 100644 --- a/engine/client/input.h +++ b/engine/client/input.h @@ -29,8 +29,8 @@ void IN_Shutdown (void); void IN_Commands (void); // oportunity for devices to stick commands on the script buffer -qboolean IN_MouseDevIsTouch(int devid); //check if a mouse devid is a touch screen, and thus if we should check the cursor and simulate a ui event or not -int IN_TranslateMButtonPress(int devid); //allow the touchscreen code to swallow mouse1 as a begin-looking event +qboolean IN_MouseDevIsTouch(unsigned int devid); //check if a mouse devid is a touch screen, and thus if we should check the cursor and simulate a ui event or not +int IN_TranslateMButtonPress(unsigned int devid); //allow the touchscreen code to swallow mouse1 as a begin-looking event void IN_Move (float *movements, int pnum, float frametime); // add additional movement on top of the keyboard move cmd @@ -46,9 +46,9 @@ void IN_DeactivateMouse(void); int CL_TargettedSplit(qboolean nowrap); //specific events for the system-specific input code to call. may be called outside the main thread (so long as you don't call these simultaneously - ie: use a mutex or only one input thread). -void IN_KeyEvent(int devid, int down, int keycode, int unicode); //don't use IN_KeyEvent for mice if you ever use abs mice... -void IN_MouseMove(int devid, int abs, float x, float y, float z, float size); -void IN_JoystickAxisEvent(int devid, int axis, float value); +void IN_KeyEvent(unsigned int devid, int down, int keycode, int unicode); //don't use IN_KeyEvent for mice if you ever use abs mice... +void IN_MouseMove(unsigned int devid, int abs, float x, float y, float z, float size); +void IN_JoystickAxisEvent(unsigned int devid, int axis, float value); //system-specific functions void INS_Move (float *movements, int pnum); @@ -58,10 +58,10 @@ void INS_ReInit (void); void INS_Init (void); void INS_Shutdown (void); void INS_Commands (void); //final chance to call IN_MouseMove/IN_KeyEvent each frame -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)); +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)); void INS_SetupControllerAudioDevices(qboolean enabled); //creates audio devices for each controller (where controllers have their own audio devices) -#define DEVID_UNSET -1 +#define DEVID_UNSET ~0u extern cvar_t cl_nodelta; extern cvar_t cl_c2spps; diff --git a/engine/client/keys.c b/engine/client/keys.c index f96ac19b..433d9a14 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -2305,7 +2305,7 @@ Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ -void Key_Event (int devid, int key, unsigned int unicode, qboolean down) +void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down) { int bl, bkey; char *dc, *uc; diff --git a/engine/client/keys.h b/engine/client/keys.h index faea871b..bee76198 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -220,7 +220,7 @@ extern unsigned char *chat_buffer; extern int chat_bufferpos; extern qboolean chat_team; -void Key_Event (int devid, int key, unsigned int unicode, qboolean down); +void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down); void Key_Init (void); void IN_WriteButtons(vfsfile_t *f, qboolean all); void Key_WriteBindings (struct vfsfile_s *f); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 3022709d..f77c3440 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -444,7 +444,7 @@ static void M_CheckMouseMove(void) { if (menu->selecteditem != option) { - if (!option->common.noselectionsound) + if (!option->common.noselectionsound && vid.activeapp) { #ifdef HEXEN2 if (M_GameType() == MGT_HEXEN2) diff --git a/engine/client/m_single.c b/engine/client/m_single.c index af0c6e54..ca752674 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -1026,7 +1026,7 @@ void M_Menu_Demos_f (void) info->ext[info->numext++] = ".pak"; MC_AddWhiteText(menu, 24, 170, 8, "Choose a Demo", false); - MC_AddWhiteText(menu, 16, 170, 24, "\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37", false); + MC_AddWhiteText(menu, 16, 170, 24, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f", false); info->list = MC_AddCustom(menu, 0, 32, NULL, 0); info->list->draw = M_DemoDraw; @@ -1081,7 +1081,7 @@ void M_Menu_MediaFiles_f (void) #endif MC_AddWhiteText(menu, 24, 170, 8, "Media List", false); - MC_AddWhiteText(menu, 16, 170, 24, "\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37", false); + MC_AddWhiteText(menu, 16, 170, 24, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f", false); info->list = MC_AddCustom(menu, 0, 32, NULL, 0); info->list->draw = M_DemoDraw; diff --git a/engine/client/menu.c b/engine/client/menu.c index 68dd4532..631ac5c1 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -1197,10 +1197,6 @@ void M_Init_Internal (void) Cmd_AddCommand ("menu_particles", M_Menu_Particles_f); Cmd_AddCommand ("menu_network", M_Menu_Network_f); -#ifdef WEBCLIENT - Cmd_AddCommand ("menu_download", Menu_DownloadStuff_f); -#endif - #ifdef CL_MASTER Cmd_AddCommand ("quickconnect", M_QuickConnect_f); #endif @@ -1253,8 +1249,6 @@ void M_DeInit_Internal (void) Cmd_RemoveCommand ("menu_textures"); Cmd_RemoveCommand ("menu_particles"); - Cmd_RemoveCommand ("menu_download"); - Cmd_RemoveCommand ("menu_main"); //I've moved main to last because that way tab gives us main and not quit. Cmd_RemoveCommand ("quickconnect"); @@ -1296,6 +1290,10 @@ void M_Init (void) //server browser is kinda complex, and has clipboard integration which we need to sandbox a little #ifdef CL_MASTER Cmd_AddCommand ("menu_servers", M_Menu_ServerList2_f); +#endif + //downloads menu needs sandboxing, so cannot be provided by qc. +#ifdef WEBCLIENT + Cmd_AddCommand ("menu_download", Menu_DownloadStuff_f); #endif //demo menu is allowed to see outside of the quakedir. you can't replicate that in qc's sandbox. Cmd_AddCommand ("menu_demo", M_Menu_Demos_f); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 5b0f81d7..26a7bf9b 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -685,10 +685,24 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) for (i = 0; i < ptype->nummodels; i++) ptype->models[i].model = NULL; - if (*ptype->texname && ptype->looks.blendmode == BM_BLEND) + if (*ptype->texname) { + char *bmpostfix; + switch(ptype->looks.blendmode) + { //we typically need the blendmode as part of the shader name, so that we don't end up with collisions with default shaders and different particle blend modes. + //shader blend modes still override, although I guess this way the shader itself can contain conditionals to use different blend modes... if needed. + default: bmpostfix = "#BLEND"; break; + case BM_BLEND: bmpostfix = ""; break; + case BM_BLENDCOLOUR:bmpostfix = "#BLENDCOLOUR"; break; + case BM_ADDA: bmpostfix = "#ADDA"; break; + case BM_ADDC: bmpostfix = "#ADDC"; break; + case BM_SUBTRACT: bmpostfix = "#SUBTRACT"; break; + case BM_INVMODA: bmpostfix = "#INVMODA"; break; + case BM_INVMODC: bmpostfix = "#INVMODC"; break; + case BM_PREMUL: bmpostfix = "#PREMUL"; break; + } /*try and load the shader, fail if we would need to generate one*/ - ptype->looks.shader = R_RegisterCustom(ptype->texname, SUF_NONE, NULL, NULL); + ptype->looks.shader = R_RegisterCustom(va("%s%s", ptype->texname, bmpostfix), SUF_NONE, NULL, NULL); } else ptype->looks.shader = NULL; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 10b1189e..1bcc9a62 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -154,13 +154,16 @@ extern sfx_t *cl_sfx_r_exp3; globalvector(trace_plane_normal, "trace_plane_normal"); /*vector written by traceline*/ \ globalfloat(trace_plane_dist, "trace_plane_dist"); /*float written by traceline*/ \ globalentity(trace_ent, "trace_ent"); /*entity written by traceline*/ \ - globalfloat(trace_surfaceflagsf, "trace_surfaceflags"); /*float written by traceline*/ \ - globalint(trace_surfaceflagsi, "trace_surfaceflags"); /*int written by traceline*/ \ + globalfloat(trace_surfaceflagsf, "trace_surfaceflagsf"); /*float written by traceline*/ \ + globalint(trace_surfaceflagsi, "trace_surfaceflagsi"); /*int written by traceline*/ \ globalstring(trace_surfacename, "trace_surfacename"); /*string written by traceline*/ \ - globalfloat(trace_endcontents, "trace_endcontents"); /*float written by traceline EXT_CSQC_1*/ \ + globalfloat(trace_endcontentsf, "trace_endcontentsf"); /*float written by traceline EXT_CSQC_1*/ \ globalint(trace_endcontentsi, "trace_endcontentsi"); /*int written by traceline EXT_CSQC_1*/ \ globalint(trace_brush_id, "trace_brush_id"); /*int written by traceline*/ \ globalint(trace_brush_faceid, "trace_brush_faceid"); /*int written by traceline*/ \ + globalint(trace_surface_id, "trace_surface_id"); /*int written by traceline*/ \ + globalint(trace_bone_id, "trace_bone_id"); /*int written by traceline*/ \ + globalint(trace_triangle_id, "trace_triangle_id"); /*int written by traceline*/ \ \ globalfloat(clientcommandframe, "clientcommandframe"); /*float the next frame that will be sent*/ \ globalfloat(servercommandframe, "servercommandframe"); /*float the most recent frame received from the server*/ \ @@ -288,6 +291,7 @@ static void CSQC_ChangeLocalPlayer(int seat) static void CSQC_FindGlobals(qboolean nofuncs) { + static eval_t junk; static float csphysicsmode = 0; static float dimension_default = 255; static vec3_t defaultgravity = {0, 0, -1}; @@ -307,6 +311,50 @@ static void CSQC_FindGlobals(qboolean nofuncs) #undef globalstring #undef globalfunction +#define ensurefloat(name) if (!csqcg.name) csqcg.name = &junk._float; +#define ensureint(name) if (!csqcg.name) csqcg.name = &junk._int; +#define ensurevector(name) if (!csqcg.name) csqcg.name = junk._vector; +#define ensureentity(name) if (!csqcg.name) csqcg.name = &junk.edict; + + if (!csqcg.trace_surfaceflagsf && !csqcg.trace_surfaceflagsi) + { + etype_t etype; + eval_t *v = PR_FindGlobal(csqcprogs, "trace_surfaceflags", 0, &etype); + if (etype == ev_float) + csqcg.trace_surfaceflagsf = &v->_float; + else if (etype == ev_integer) + csqcg.trace_surfaceflagsi = &v->_int; + } + if (!csqcg.trace_endcontentsf && !csqcg.trace_endcontentsi) + { + etype_t etype; + eval_t *v = PR_FindGlobal(csqcprogs, "trace_endcontents", 0, &etype); + if (etype == ev_float) + csqcg.trace_endcontentsf = &v->_float; + else if (etype == ev_integer) + csqcg.trace_endcontentsi = &v->_int; + } + + ensurefloat(trace_allsolid); + ensurefloat(trace_startsolid); + ensurefloat(trace_fraction); + ensurefloat(trace_inwater); + ensurefloat(trace_inopen); + ensurevector(trace_endpos); + ensurevector(trace_plane_normal); + ensurefloat(trace_plane_dist); + ensurefloat(trace_surfaceflagsf); + ensureint(trace_surfaceflagsi); + ensurefloat(trace_endcontentsf); + ensureint(trace_endcontentsi); + ensureint(trace_brush_id); + ensureint(trace_brush_faceid); + ensureint(trace_surface_id); + ensureint(trace_bone_id); + ensureint(trace_triangle_id); + ensureentity(trace_ent); + + if (csqcg.simtime) *csqcg.simtime = cl.servertime; if (csqcg.cltime) @@ -561,7 +609,7 @@ static void QCBUILTIN PF_cs_remove (pubprogfuncs_t *prinst, struct globalvars_s ed = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); - if (ed->isfree) + if (ED_ISFREE(ed)) { csqc_deprecated("Tried removing free entity"); return; @@ -883,7 +931,7 @@ static void QCBUILTIN PF_R_AddEntity(pubprogfuncs_t *prinst, struct globalvars_s { csqcedict_t *in = (void*)G_EDICT(prinst, OFS_PARM0); entity_t ent; - if (in->isfree || in->entnum == 0) + if (ED_ISFREE(in) || in->entnum == 0) { csqc_deprecated("Tried drawing a free/removed/world entity\n"); return; @@ -1158,19 +1206,19 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva for (e=1; e < maxe; e++) { ent = (void*)EDICT_NUM(prinst, e); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (ent->v->think) { WPhys_RunThink (&csqc_world, (wedict_t*)ent); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; } if (ent->xv->predraw) { *csqcg.self = EDICT_TO_PROG(prinst, (void*)ent); PR_ExecuteProgram(prinst, ent->xv->predraw); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; //bummer... } if ((int)ent->xv->drawmask & mask) @@ -1189,7 +1237,7 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva for (e=1; e < maxe; e++) { ent = (void*)EDICT_NUM(prinst, e); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if ((int)ent->xv->drawmask & mask) @@ -1199,7 +1247,7 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva *csqcg.self = EDICT_TO_PROG(prinst, (void*)ent); PR_ExecuteProgram(prinst, ent->xv->predraw); - if (ent->isfree || G_FLOAT(OFS_RETURN)) + if (ED_ISFREE(ent) || G_FLOAT(OFS_RETURN)) continue; //bummer... } if (CopyCSQCEdictToEntity(ent, &rent)) @@ -2225,7 +2273,7 @@ static void QCBUILTIN PF_cs_SetSize (pubprogfuncs_t *prinst, struct globalvars_s float *min, *max; e = G_WEDICT(prinst, OFS_PARM0); - if (e->isfree) + if (ED_ISFREE(e)) { PR_RunWarning(prinst, "%s edict was free\n", "setsize"); return; @@ -2253,20 +2301,17 @@ static void cs_settracevars(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob VectorCopy (tr->endpos, csqcg.trace_endpos); VectorCopy (tr->plane.normal, csqcg.trace_plane_normal); *csqcg.trace_plane_dist = tr->plane.dist; - if (csqcg.trace_surfaceflagsf) - *csqcg.trace_surfaceflagsf = tr->surface?tr->surface->flags:0; - if (csqcg.trace_surfaceflagsi) - *csqcg.trace_surfaceflagsi = tr->surface?tr->surface->flags:0; + *csqcg.trace_surfaceflagsf = tr->surface?tr->surface->flags:0; + *csqcg.trace_surfaceflagsi = tr->surface?tr->surface->flags:0; if (csqcg.trace_surfacename) prinst->SetStringField(prinst, NULL, csqcg.trace_surfacename, tr->surface?tr->surface->name:NULL, true); - if (csqcg.trace_endcontents) - *csqcg.trace_endcontents = tr->contents; - if (csqcg.trace_endcontentsi) - *csqcg.trace_endcontentsi = tr->contents; - if (csqcg.trace_brush_id) - *csqcg.trace_brush_id = tr->brush_id; - if (csqcg.trace_brush_faceid) - *csqcg.trace_brush_faceid = tr->brush_face; + *csqcg.trace_endcontentsf = tr->contents; + *csqcg.trace_endcontentsi = tr->contents; + *csqcg.trace_brush_id = tr->brush_id; + *csqcg.trace_brush_faceid = tr->brush_face; + *csqcg.trace_surface_id = tr->surface_id; + *csqcg.trace_bone_id = tr->bone_id; + *csqcg.trace_triangle_id = tr->triangle_id; if (tr->ent) *csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)tr->ent); else @@ -3693,7 +3738,7 @@ static void QCBUILTIN PF_cs_findchainflags (pubprogfuncs_t *prinst, struct globa for (i = 1; i < *prinst->parms->sv_num_edicts; i++) { ent = (csqcedict_t*)EDICT_NUM(prinst, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (!((int)((float *)ent->v)[f] & s)) continue; @@ -3720,7 +3765,7 @@ static void QCBUILTIN PF_cs_findchainfloat (pubprogfuncs_t *prinst, struct globa for (i = 1; i < *prinst->parms->sv_num_edicts; i++) { ent = (csqcedict_t*)EDICT_NUM(prinst, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (((float *)ent->v)[f] != s) continue; @@ -3750,7 +3795,7 @@ static void QCBUILTIN PF_cs_findchain (pubprogfuncs_t *prinst, struct globalvars for (i = 1; i < *prinst->parms->sv_num_edicts; i++) { ent = (csqcedict_t*)EDICT_NUM(prinst, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; t = *(string_t *)&((float*)ent->v)[f]; if (!t) @@ -7226,7 +7271,7 @@ qboolean CSQC_DrawView(void) return true; } -qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid) +qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid) { static qbyte csqckeysdown[K_MAX]; void *pr_globals; @@ -7269,7 +7314,7 @@ qboolean CSQC_KeyPress(int key, int unicode, qboolean down, int devid) return G_FLOAT(OFS_RETURN); } -qboolean CSQC_MousePosition(float xabs, float yabs, int devid) +qboolean CSQC_MousePosition(float xabs, float yabs, unsigned int devid) { void *pr_globals; @@ -7286,7 +7331,7 @@ qboolean CSQC_MousePosition(float xabs, float yabs, int devid) return G_FLOAT(OFS_RETURN); } -qboolean CSQC_MouseMove(float xdelta, float ydelta, int devid) +qboolean CSQC_MouseMove(float xdelta, float ydelta, unsigned int devid) { void *pr_globals; @@ -7304,7 +7349,7 @@ qboolean CSQC_MouseMove(float xdelta, float ydelta, int devid) return G_FLOAT(OFS_RETURN); } -qboolean CSQC_JoystickAxis(int axis, float value, int devid) +qboolean CSQC_JoystickAxis(int axis, float value, unsigned int devid) { void *pr_globals; if (!csqcprogs || !csqcg.input_event) diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index 4fdf3c9b..b88bc52c 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -671,17 +671,19 @@ void rag_freedoll(doll_t *doll) BZ_Free(doll); } +void rag_uninstanciateall(void) +{ + int i; + for (i = 0; i < numskelobjectsused; i++) + { + rag_uninstanciate(&skelobjects[i]); + } +} void rag_flushdolls(qboolean force) { doll_t *d, **link; - int i; if (force) - { - for (i = 0; i < numskelobjectsused; i++) - { - rag_uninstanciate(&skelobjects[i]); - } - } + rag_uninstanciateall(); for (link = &dolllist; *link; ) { d = *link; @@ -1089,6 +1091,12 @@ static void rag_uninstanciate(skelobject_t *sko) if (!sko->doll) return; + if (!sko->world || !sko->world->rbe) + { + sko->numbodies = sko->numjoints = 0; + Con_Printf(CON_ERROR "ERROR: Uninstanciating ragdoll from invalid world\n"); + } + for (i = 0; i < sko->numbodies; i++) { sko->world->rbe->RagDestroyBody(sko->world, &sko->body[i].odebody); diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 62c4a879..e763b825 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -291,7 +291,7 @@ extern qboolean noclip_anglehack; extern quakeparms_t host_parms; extern cvar_t fs_gamename; -extern cvar_t fs_gamemanifest; +extern cvar_t fs_downloads_url; extern cvar_t com_protocolname; extern cvar_t com_nogamedirnativecode; extern cvar_t com_parseutf8; diff --git a/engine/client/render.h b/engine/client/render.h index 67a00f04..da21eaf1 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -49,12 +49,14 @@ static const texid_t r_nulltex = NULL; #if sizeof_index_t == 2 #define GL_INDEX_TYPE GL_UNSIGNED_SHORT #define D3DFMT_QINDEX D3DFMT_INDEX16 + #define DXGI_FORMAT_INDEX_UINT DXGI_FORMAT_R16_UINT #define VK_INDEX_TYPE VK_INDEX_TYPE_UINT16 typedef unsigned short index_t; #define MAX_INDICIES 0xffffu #else #define GL_INDEX_TYPE GL_UNSIGNED_INT #define D3DFMT_QINDEX D3DFMT_INDEX32 + #define DXGI_FORMAT_INDEX_UINT DXGI_FORMAT_R32_UINT #define VK_INDEX_TYPE VK_INDEX_TYPE_UINT32 typedef unsigned int index_t; #define MAX_INDICIES 0x00ffffffu @@ -636,6 +638,7 @@ enum { RSPEED_SETUP, RSPEED_SUBMIT, RSPEED_PRESENT, + RSPEED_ACQUIRE, RSPEED_MAX }; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 96248cff..20dab11d 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -424,7 +424,8 @@ cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0", cvar_t r_fog_exp2 = CVARD ("r_fog_exp2", "1", "Expresses how fog fades with distance. 0 (matching DarkPlaces's default) is typically more realistic, while 1 (matching FitzQuake and others) is more common."); #ifdef VKQUAKE -cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "0", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers."); +cvar_t vk_stagingbuffers = CVARD ("vk_stagingbuffers", "", "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0."); +cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "1", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers."); cvar_t vk_debug = CVARD ("vk_debug", "0", "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers."); #endif @@ -851,6 +852,7 @@ void Renderer_Init(void) Cvar_Register (&r_forceprogramify, GLRENDEREROPTIONS); #ifdef VKQUAKE + Cvar_Register (&vk_stagingbuffers, VKRENDEREROPTIONS); Cvar_Register (&vk_submissionthread, VKRENDEREROPTIONS); Cvar_Register (&vk_debug, VKRENDEREROPTIONS); #endif @@ -1350,7 +1352,7 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n")); ent = (wedict_t*)EDICT_NUM(svprogfuncs, i); if (!ent) continue; - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (ent->area.prev) diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 42e7e4ae..e03d276d 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -88,7 +88,7 @@ void INS_Move(float *movements, int pnum) void INS_Commands(void) { } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } void INS_Init(void) diff --git a/engine/client/view.c b/engine/client/view.c index a5556861..ddce5a4d 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1908,7 +1908,7 @@ void R_DrawNameTags(void) for (i = 1; i < w->num_edicts; i++) { e = WEDICT_NUM(w->progs, i); - if (e->isfree) + if (ED_ISFREE(e)) continue; VectorInterpolate(e->v->mins, 0.5, e->v->maxs, org); VectorAdd(org, e->v->origin, org); diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 71507a5c..c3d3c2d6 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2240,7 +2240,7 @@ void Cmd_ExecuteString (char *text, int level) #ifndef SERVERONLY //an emergency escape mechansim, to avoid infinatly recursing aliases. extern qboolean keydown[]; - extern int con_splitmodifier; + extern unsigned int con_splitmodifier; if (keydown[K_SHIFT] && (keydown[K_LCTRL]||keydown[K_RCTRL]) && (keydown[K_LALT]||keydown[K_RALT])) return; @@ -3125,7 +3125,7 @@ void Cmd_set_f(void) end--; while (end >= text) { - if (*end == ' ') + if (*end == ' ' || *end == '\t' || *end == '\r') end--; else break; diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 00e9b863..db679a5f 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -2145,6 +2145,7 @@ qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, v } VectorCopy(normal, trace->plane.normal); trace->plane.dist = planedist; + trace->triangle_id = 1+i/3; impacted = true; // if (fabs(normal[0]) != 1 && fabs(normal[1]) != 1 && fabs(normal[2]) != 1) @@ -2243,8 +2244,26 @@ qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], } trace->truefraction = 1; - if (Mod_Trace_Trisoup(posedata, indexes, mod->numindexes, start_l, end_l, mins, maxs, trace) && axis) + if (Mod_Trace_Trisoup(posedata, indexes, mod->numindexes, start_l, end_l, mins, maxs, trace)) { + trace->surface_id = 1+surfnum; + trace->bone_id = 0; + if (mod->ofs_skel_weight) + { //fixme: would be better to consider the distance to the vertex too. cartesian coord stuff etc. + unsigned int best = 0, v, w, i; + float bw = 0; + for (i = 0; i < 3; i++) + { + for (v = indexes[(trace->triangle_id-1)*3+i], w = 0; w < 4; w++) + { + if (bw < mod->ofs_skel_weight[v][w]) + { + bw = mod->ofs_skel_weight[v][w]; + trace->bone_id = 1 + mod->ofs_skel_idx[v][w]; + } + } + } + } if (axis) { vec3_t iaxis[3]; @@ -2254,27 +2273,27 @@ qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], trace->plane.normal[0] = DotProduct(norm, iaxis[0]); trace->plane.normal[1] = DotProduct(norm, iaxis[1]); trace->plane.normal[2] = DotProduct(norm, iaxis[2]); - } -// frac = traceinfo.truefraction; - /* - diststart = DotProduct(traceinfo.start, trace->plane.normal); - distend = DotProduct(traceinfo.end, trace->plane.normal); - if (diststart == distend) - frac = 0; - else - { - frac = (diststart - trace->plane.dist) / (diststart-distend); - if (frac < 0) +// frac = traceinfo.truefraction; + /* + diststart = DotProduct(traceinfo.start, trace->plane.normal); + distend = DotProduct(traceinfo.end, trace->plane.normal); + if (diststart == distend) frac = 0; - else if (frac > 1) - frac = 1; - }*/ + else + { + frac = (diststart - trace->plane.dist) / (diststart-distend); + if (frac < 0) + frac = 0; + else if (frac > 1) + frac = 1; + }*/ - /*okay, this is where it hits this plane*/ - trace->endpos[0] = start[0] + trace->fraction*(end[0] - start[0]); - trace->endpos[1] = start[1] + trace->fraction*(end[1] - start[1]); - trace->endpos[2] = start[2] + trace->fraction*(end[2] - start[2]); + /*okay, this is where it hits this plane*/ + trace->endpos[0] = start[0] + trace->fraction*(end[0] - start[0]); + trace->endpos[1] = start[1] + trace->fraction*(end[1] - start[1]); + trace->endpos[2] = start[2] + trace->fraction*(end[2] - start[2]); + } } } diff --git a/engine/common/common.c b/engine/common/common.c index e877241a..fa65810d 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -103,7 +103,7 @@ cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers"); cvar_t gameversion_max = CVARD("gameversion_max","", "gamecode version for server browsers"); cvar_t fs_gamename = CVARAFD("com_fullgamename", NULL, "fs_gamename", CVAR_NOSET, "The filesystem is trying to run this game"); -cvar_t fs_gamemanifest = CVARFD("fs_gamemanifest", "", CVAR_NOSET, "A small updatable file containing a description of the game, including download mirrors."); +cvar_t fs_downloads_url = CVARFD("fs_downloads_url", NULL, CVAR_NOSET, "The URL of a package updates list."); cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers."); cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. cvar_t com_parseezquake = CVARD("com_parseezquake", "0", "Treat chevron chars from configs as a per-character flag. You should use this only for compat with nquake's configs."); @@ -205,7 +205,12 @@ void QDECL Q_strncpyz(char *d, const char *s, int n) //size is the total size of the buffer void VARGS Q_vsnprintfz (char *dest, size_t size, const char *fmt, va_list argptr) { +#ifdef _DEBUG + if ((size_t)vsnprintf (dest, size, fmt, argptr) > size-1) + Sys_Error("Q_vsnprintfz: truncation"); +#else vsnprintf (dest, size, fmt, argptr); +#endif dest[size-1] = 0; } @@ -1583,18 +1588,20 @@ char *MSG_ReadStringBuffer (char *out, size_t outsize) } char *MSG_ReadString (void) { - static char string[8192]; + static char string[65536]; int l,c; l = 0; - do + for(;;) { c = MSG_ReadChar (); if (msg_badread || c == 0) break; - string[l] = c; - l++; - } while (l < sizeof(string)-1); + if (l < sizeof(string)-1) + string[l++] = c; + else + msg_badread = true; + } string[l] = 0; diff --git a/engine/common/common.h b/engine/common/common.h index 1827c6cd..e236bbb8 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -601,6 +601,7 @@ typedef struct char *updatefile; //this is the file that needs to be written to update the manifest. char *installation; //optional hardcoded commercial name, used for scanning the registry to find existing installs. char *formalname; //the commercial name of the game. you'll get FULLENGINENAME otherwise. + char *downloadsurl; //optional installable files (menu) char *protocolname; //the name used for purposes of dpmaster char *defaultexec; //execed after cvars are reset, to give game-specific defaults. char *eula; //when running as an installer, the user will be presented with this as a prompt diff --git a/engine/common/fs.c b/engine/common/fs.c index 8499b336..414c2cb6 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -205,6 +205,7 @@ void FS_Manifest_Free(ftemanifest_t *man) Z_Free(man->updatefile); Z_Free(man->installation); Z_Free(man->formalname); + Z_Free(man->downloadsurl); Z_Free(man->protocolname); Z_Free(man->eula); Z_Free(man->defaultexec); @@ -235,6 +236,8 @@ static ftemanifest_t *FS_Manifest_Clone(ftemanifest_t *oldm) newm->installation = Z_StrDup(oldm->installation); if (oldm->formalname) newm->formalname = Z_StrDup(oldm->formalname); + if (oldm->downloadsurl) + newm->downloadsurl = Z_StrDup(oldm->downloadsurl); if (oldm->protocolname) newm->protocolname = Z_StrDup(oldm->protocolname); if (oldm->eula) @@ -277,6 +280,8 @@ void FS_Manifest_Print(ftemanifest_t *man) Con_Printf("game %s\n", COM_QuotedString(man->installation, buffer, sizeof(buffer), false)); if (man->formalname) Con_Printf("name %s\n", COM_QuotedString(man->formalname, buffer, sizeof(buffer), false)); + if (man->downloadsurl) + Con_Printf("downloadsurl %s\n", COM_QuotedString(man->downloadsurl, buffer, sizeof(buffer), false)); if (man->protocolname) Con_Printf("protocolname %s\n", COM_QuotedString(man->protocolname, buffer, sizeof(buffer), false)); if (man->defaultexec) @@ -501,6 +506,11 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man) Z_Free(man->eula); man->eula = Z_StrDup(Cmd_Argv(1)); } + else if (!Q_strcasecmp(cmd, "downloadsurl")) + { + Z_Free(man->downloadsurl); + man->downloadsurl = Z_StrDup(Cmd_Argv(1)); + } else if (!Q_strcasecmp(cmd, "protocolname")) { Z_Free(man->protocolname); @@ -1705,6 +1715,26 @@ vfsfile_t *FS_OpenWithFriends(const char *fname, char *sysname, size_t sysnamesi return NULL; } +//returns false if the string didn't fit. we're not trying to be clever and reallocate the buffer +qboolean try_snprintf(char *buffer, size_t size, const char *format, ...) +{ + size_t ret; + va_list argptr; + + va_start (argptr, format); +#ifdef _WIN32 +#undef _vsnprintf + ret = _vsnprintf(buffer, size, format, argptr); +#define _vsnprintf unsafe_vsnprintf +#else + ret = vsnprintf (buffer, size, format,argptr); +#endif + va_end (argptr); + if (ret > size-1) //should cope with microsoft's -1s and linuxes total-length return values. + return false; + return true; +} + /*locates and opens a file modes: r = read @@ -1747,7 +1777,8 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r case FS_GAMEONLY: //OS access only, no paks if (com_homepathenabled) { - snprintf(fullname, sizeof(fullname), "%s%s/%s", com_homepath, gamedirfile, filename); + if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_homepath, gamedirfile, filename)) + return NULL; if (*mode == 'w') COM_CreatePath(fullname); vfs = VFSOS_Open(fullname, mode); @@ -1756,23 +1787,27 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r } if (*gamedirfile) { - snprintf(fullname, sizeof(fullname), "%s%s/%s", com_gamepath, gamedirfile, filename); + if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_gamepath, gamedirfile, filename)) + return NULL; if (*mode == 'w') COM_CreatePath(fullname); return VFSOS_Open(fullname, mode); } return NULL; case FS_PUBGAMEONLY: - FS_NativePath(filename, relativeto, fullname, sizeof(fullname)); + if (!FS_NativePath(filename, relativeto, fullname, sizeof(fullname))) + return NULL; if (*mode == 'w') COM_CreatePath(fullname); return VFSOS_Open(fullname, mode); case FS_GAME: //load from paks in preference to system paths. overwriting be damned. case FS_PUBBASEGAMEONLY: //load from paks in preference to system paths. overwriting be damned. - FS_NativePath(filename, relativeto, fullname, sizeof(fullname)); + if (!FS_NativePath(filename, relativeto, fullname, sizeof(fullname))) + return NULL; break; case FS_BINARYPATH: - FS_NativePath(filename, relativeto, fullname, sizeof(fullname)); + if (!FS_NativePath(filename, relativeto, fullname, sizeof(fullname))) + return NULL; if (*mode == 'w') COM_CreatePath(fullname); return VFSOS_Open(fullname, mode); @@ -1781,22 +1816,26 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r return NULL; if (com_homepathenabled) { - snprintf(fullname, sizeof(fullname), "%s%s", com_homepath, filename); + if (!try_snprintf(fullname, sizeof(fullname), "%s%s", com_homepath, filename)) + return NULL; vfs = VFSOS_Open(fullname, mode); if (vfs) return vfs; } - snprintf(fullname, sizeof(fullname), "%s%s", com_gamepath, filename); + if (!try_snprintf(fullname, sizeof(fullname), "%s%s", com_gamepath, filename)) + return NULL; return VFSOS_Open(fullname, mode); case FS_BASEGAMEONLY: //always bypass packs+pure. if (com_homepathenabled) { - snprintf(fullname, sizeof(fullname), "%sfte/%s", com_homepath, filename); + if (!try_snprintf(fullname, sizeof(fullname), "%sfte/%s", com_homepath, filename)) + return NULL; vfs = VFSOS_Open(fullname, mode); if (vfs) return vfs; } - snprintf(fullname, sizeof(fullname), "%sfte/%s", com_gamepath, filename); + if (!try_snprintf(fullname, sizeof(fullname), "%sfte/%s", com_gamepath, filename)) + return NULL; return VFSOS_Open(fullname, mode); default: Sys_Error("FS_OpenVFS: Bad relative path (%i)", relativeto); @@ -2855,6 +2894,7 @@ typedef struct { const char *dir[4]; const char *poshname; //Full name for the game. + const char *downloadsurl; const char *manifestfile; } gamemode_info_t; const gamemode_info_t gamemode_info[] = { @@ -2867,7 +2907,7 @@ const gamemode_info_t gamemode_info[] = { //for quake, we also allow extracting all files from paks. some people think it loads faster that way or something. //cmdline switch exename protocol name(dpmaster) identifying file exec dir1 dir2 dir3 dir(fte) full name - {"-quake", "q1", MASTER_PREFIX"Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake"/*, "id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/}, + {"-quake", "q1", MASTER_PREFIX"Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.txt" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/}, //quake's mission packs should not be favoured over the base game nor autodetected //third part mods also tend to depend upon the mission packs for their huds, even if they don't use any other content. //and q2 also has a rogue/pak0.pak file that we don't want to find and cause quake2 to look like dissolution of eternity @@ -3795,14 +3835,14 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base return false; } #else -#ifdef __linux__ +#if defined(__linux__) || defined(__unix__) || defined(__apple__) #include #endif qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *basepath, int basepathlen, qboolean allowprompts) { -#ifdef __linux__ +#if defined(__linux__) || defined(__unix__) || defined(__apple__) struct stat sb; - if (!strcmp(gamename, "quake")) + if (!strcmp(gamename, "quake")) { if (stat("/usr/share/quake/", &sb) == 0) { @@ -3859,6 +3899,7 @@ void FS_Shutdown(void) fs_thread_mutex = NULL; Cvar_SetEngineDefault(&fs_gamename, NULL); + Cvar_SetEngineDefault(&fs_downloads_url, NULL); Cvar_SetEngineDefault(&com_protocolname, NULL); } @@ -3930,7 +3971,8 @@ static int FS_IdentifyDefaultGameFromDir(char *basedir) //3: if we are ftequake3.exe then we always try to run quake3. //4: identify characteristic files within the working directory (like id1/pak0.pak implies we're running quake) //5: check where the exe actually is instead of simply where we're being run from. -//6: fallback to prompting. just returns -1 here. +//6: try the homedir, just in case. +//7: fallback to prompting. just returns -1 here. //if autobasedir is not set, block gamedir changes/prompts. static int FS_IdentifyDefaultGame(char *newbase, int sizeof_newbase, qboolean fixedbase) { @@ -3961,6 +4003,12 @@ static int FS_IdentifyDefaultGame(char *newbase, int sizeof_newbase, qboolean fi if (gamenum != -1) Q_strncpyz(newbase, host_parms.binarydir, sizeof_newbase); } + if (gamenum == -1 && *com_homepath && !fixedbase) + { + gamenum = FS_IdentifyDefaultGameFromDir(com_homepath); + if (gamenum != -1) + Q_strncpyz(newbase, com_homepath, sizeof_newbase); + } return gamenum; } @@ -4828,6 +4876,11 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean } } + if (!man->downloadsurl) + { + Cmd_TokenizeString(va("downloadsurl \"%s\"", gamemode_info[i].downloadsurl), false, false); + FS_Manifest_ParseTokens(man); + } if (!man->protocolname) { Cmd_TokenizeString(va("protocolname \"%s\"", gamemode_info[i].protocolname), false, false); @@ -4954,9 +5007,11 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean if (reloadconfigs) { Cvar_SetEngineDefault(&fs_gamename, man->formalname?man->formalname:"FTE"); + Cvar_SetEngineDefault(&fs_downloads_url, man->downloadsurl?man->downloadsurl:""); Cvar_SetEngineDefault(&com_protocolname, man->protocolname?man->protocolname:"FTE"); //FIXME: flag this instead and do it after a delay? Cvar_ForceSet(&fs_gamename, fs_gamename.enginevalue); + Cvar_ForceSet(&fs_downloads_url, fs_downloads_url.enginevalue); Cvar_ForceSet(&com_protocolname, com_protocolname.enginevalue); vidrestart = false; @@ -5398,7 +5453,7 @@ void COM_InitFilesystem (void) Cvar_Register(&cfg_reload_on_gamedir, "Filesystem"); Cvar_Register(&com_fs_cache, "Filesystem"); Cvar_Register(&fs_gamename, "Filesystem"); - Cvar_Register(&fs_gamemanifest, "Filesystem"); + Cvar_Register(&fs_downloads_url, "Filesystem"); Cvar_Register(&com_protocolname, "Server Info"); Cvar_Register(&fs_game, "Filesystem"); #ifdef Q2SERVER diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 12bb3ed8..953d5bc0 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1205,7 +1205,7 @@ void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo for (e++; e < *prinst->parms->sv_num_edicts; e++) { ed = WEDICT_NUM(prinst, e); - if (ed->isfree) + if (ED_ISFREE(ed)) continue; if ((int)((float *)ed->v)[f] & s) { @@ -1237,7 +1237,7 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo for (e++; e < *prinst->parms->sv_num_edicts; e++) { ed = WEDICT_NUM(prinst, e); - if (ed->isfree) + if (ED_ISFREE(ed)) continue; if (((int *)ed->v)[f] == s) { @@ -1270,7 +1270,7 @@ void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl for (e++ ; e < *prinst->parms->sv_num_edicts ; e++) { ed = WEDICT_NUM(prinst, e); - if (ed->isfree) + if (ED_ISFREE(ed)) continue; t = ((string_t *)ed->v)[f]; if (!t) @@ -2616,7 +2616,7 @@ void QCBUILTIN PF_WasFreed (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob { wedict_t *ent; ent = G_WEDICT(prinst, OFS_PARM0); - G_FLOAT(OFS_RETURN) = ent->isfree; + G_FLOAT(OFS_RETURN) = ED_ISFREE(ent); } void QCBUILTIN PF_num_for_edict (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -2666,7 +2666,7 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl for (i=1 ; inum_edicts ; i++) { ent = WEDICT_NUM(prinst, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (ent->v->solid == SOLID_NOT && (!((int)ent->v->flags & FL_FINDABLE_NONSOLID)) && !sv_gameplayfix_blowupfallenzombies.value) continue; @@ -2698,7 +2698,7 @@ void QCBUILTIN PF_nextent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa return; } ent = WEDICT_NUM(prinst, i); - if (!ent->isfree) + if (!ED_ISFREE(ent)) { RETURN_EDICT(prinst, ent); return; @@ -2740,9 +2740,9 @@ void QCBUILTIN PF_copyentity (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl else out = G_WEDICT(prinst, OFS_PARM1); - if (in->isfree) + if (ED_ISFREE(in)) PR_BIError(prinst, "PF_copyentity: source is free"); - if (!out || out->isfree) + if (!out || ED_ISFREE(out)) PR_BIError(prinst, "PF_copyentity: destination is free"); if (out->readonly) PR_BIError(prinst, "PF_copyentity: destination is read-only"); @@ -2760,7 +2760,7 @@ void QCBUILTIN PF_entityprotection (pubprogfuncs_t *prinst, struct globalvars_s wedict_t *e = G_WEDICT(prinst, OFS_PARM0); int prot = G_FLOAT(OFS_PARM1); - if (e->isfree) + if (ED_ISFREE(e)) PR_BIError(prinst, "PF_entityprotection: entity is free"); G_FLOAT(OFS_RETURN) = prot; diff --git a/engine/common/world.h b/engine/common/world.h index 711d15ad..f68086c0 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -74,6 +74,9 @@ typedef struct trace_s float truefraction; //can be negative, also has floating point precision issues, etc. int brush_id; int brush_face; + int surface_id; + int triangle_id; + int bone_id; } trace_t; typedef struct q2trace_s diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 52453c0c..653d4fc3 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -2096,7 +2096,7 @@ static void BE_DrawMeshChain_Internal(void) { m = shaderstate.meshlist[0]; - ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, shaderstate.batchvbo->indicies.d3d.buff, DXGI_FORMAT_R16_UINT, shaderstate.batchvbo->indicies.d3d.offs); + ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, shaderstate.batchvbo->indicies.d3d.buff, DXGI_FORMAT_INDEX_UINT, shaderstate.batchvbo->indicies.d3d.offs); idxfirst = m->vbofirstelement; vertcount = m->vbofirstvert + m->numvertexes; @@ -2123,7 +2123,7 @@ static void BE_DrawMeshChain_Internal(void) map += m->numindexes; } ID3D11DeviceContext_Unmap(d3ddevctx, (ID3D11Resource*)buf, 0); - ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, buf, DXGI_FORMAT_R16_UINT, byteofs); + ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, buf, DXGI_FORMAT_INDEX_UINT, byteofs); idxfirst = 0; } else @@ -2149,7 +2149,7 @@ static void BE_DrawMeshChain_Internal(void) vertcount += m->numvertexes; } ID3D11DeviceContext_Unmap(d3ddevctx, (ID3D11Resource*)buf, 0); - ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, buf, DXGI_FORMAT_R16_UINT, byteofs); + ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, buf, DXGI_FORMAT_INDEX_UINT, byteofs); idxfirst = 0; } @@ -3517,7 +3517,7 @@ void D3D11BE_RenderShadowBuffer(unsigned int numverts, void *vbuf, unsigned int shaderstate.lastpasscount = 0; ID3D11DeviceContext_IASetVertexBuffers(d3ddevctx, 0, 1, vbufs, vstrides, voffsets); - ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, ibuf, DXGI_FORMAT_R16_UINT, 0); + ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, ibuf, DXGI_FORMAT_INDEX_UINT, 0); BE_ApplyUniforms(shaderstate.depthonly->prog, 0); diff --git a/engine/d3d/d3d11_image.c b/engine/d3d/d3d11_image.c index de04cf86..c80add0d 100644 --- a/engine/d3d/d3d11_image.c +++ b/engine/d3d/d3d11_image.c @@ -278,6 +278,7 @@ void D3D11_UploadLightmap(lightmapinfo_t *lm) mips.mip[0].needfree = false; mips.mip[0].width = lm->width; mips.mip[0].height = lm->height; + mips.mip[0].datasize = lm->width*lm->height*4; if (lightmap_bgra) mips.encoding = PTI_BGRX8; else diff --git a/engine/d3d/d3d11_shader.c b/engine/d3d/d3d11_shader.c index 20d8f06f..b4269bf5 100644 --- a/engine/d3d/d3d11_shader.c +++ b/engine/d3d/d3d11_shader.c @@ -105,7 +105,8 @@ extern ID3D11Device *pD3DDev11; #include #endif -const GUID IID_ID3D11ShaderReflection = {0x8d536ca1, 0x0cca, 0x4956, {0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84}}; +//const GUID IID_ID3D11ShaderReflection = {0x8d536ca1, 0x0cca, 0x4956, {0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84}}; +const GUID IID_ID3D11ShaderReflection = {0x0a233719, 0x3960, 0x4578, {0x9d, 0x7c, 0x20, 0x3b, 0x8b, 0x1d, 0x9c, 0xc1}}; #define ID3DBlob_GetBufferPointer(b) b->lpVtbl->GetBufferPointer(b) #define ID3DBlob_Release(b) b->lpVtbl->Release(b) #define ID3DBlob_GetBufferSize(b) b->lpVtbl->GetBufferSize(b) @@ -678,6 +679,8 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned } ID3D11ShaderReflection_Release(freflect); } + else + Con_Printf("%s: D3DReflect failed, unable to get reflection info\n", name); } if (vcode) @@ -739,6 +742,8 @@ qboolean D3D11Shader_Init(unsigned int flevel) sh_config.pCreateProgram = D3D11Shader_CreateProgram; sh_config.pProgAutoFields = NULL; + sh_config.can_mipcap = true; //at creation time + // sh_config.tex_env_combine = 1; // sh_config.nv_tex_env_combine4 = 1; // sh_config.env_add = 1; diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index ee40994d..87590401 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -485,6 +485,8 @@ void D3D9Shader_Init(void) sh_config.texfmt[PTI_ARGB1555] = true; sh_config.texfmt[PTI_ARGB4444] = true; + sh_config.can_mipcap = true; //at creation time, I think. + IDirect3DDevice9_GetDeviceCaps(pD3DDev9, &caps); if (caps.TextureCaps & D3DPTEXTURECAPS_POW2) diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 51f4098f..480ffacb 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1184,42 +1184,44 @@ static void D3D9_SetupViewPortProjection(void) static void (D3D9_R_RenderView) (void) { - Surf_SetupFrame(); - - //check if we can do underwater warp - if (cls.protocol != CP_QUAKE2) //quake2 tells us directly + if (!r_norefresh.value) { - if (r_viewcontents & FTECONTENTS_FLUID) - r_refdef.flags |= RDF_UNDERWATER; - else - r_refdef.flags &= ~RDF_UNDERWATER; - } - if (r_refdef.flags & RDF_UNDERWATER) - { - extern cvar_t r_projection; - if (!r_waterwarp.value || r_projection.ival) - r_refdef.flags &= ~RDF_UNDERWATER; //no warp at all -// else if (r_waterwarp.value > 0 && scenepp_waterwarp) -// r_refdef.flags |= RDF_WATERWARP; //try fullscreen warp instead if we can - } + Surf_SetupFrame(); - D3D9_SetupViewPortProjection(); + //check if we can do underwater warp + if (cls.protocol != CP_QUAKE2) //quake2 tells us directly + { + if (r_viewcontents & FTECONTENTS_FLUID) + r_refdef.flags |= RDF_UNDERWATER; + else + r_refdef.flags &= ~RDF_UNDERWATER; + } + if (r_refdef.flags & RDF_UNDERWATER) + { + extern cvar_t r_projection; + if (!r_waterwarp.value || r_projection.ival) + r_refdef.flags &= ~RDF_UNDERWATER; //no warp at all + // else if (r_waterwarp.value > 0 && scenepp_waterwarp) + // r_refdef.flags |= RDF_WATERWARP; //try fullscreen warp instead if we can + } -// if (r_clear.ival && !(r_refdef.flags & RDF_NOWORLDMODEL)) -// d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,0,0), 1, 0)); -// else - d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0)); + D3D9_SetupViewPortProjection(); - R_SetFrustum (r_refdef.m_projection, r_refdef.m_view); - RQ_BeginFrame(); - if (!(r_refdef.flags & RDF_NOWORLDMODEL)) - { - if (cl.worldmodel) - P_DrawParticles (); + // if (r_clear.ival && !(r_refdef.flags & RDF_NOWORLDMODEL)) + // d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,0,0), 1, 0)); + // else + d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0)); + + R_SetFrustum (r_refdef.m_projection, r_refdef.m_view); + RQ_BeginFrame(); + if (!(r_refdef.flags & RDF_NOWORLDMODEL)) + { + if (cl.worldmodel) + P_DrawParticles (); + } + Surf_DrawWorld(); + RQ_RenderBatchClear(); } - Surf_DrawWorld(); - RQ_RenderBatchClear(); - D3D9_Set2D (); } diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 06130d6e..f6e001fc 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -544,7 +544,7 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR Cbuf_AddText("\nquit\n", RESTRICT_LOCAL); } - break; + break; case WM_ACTIVATE: fActive = LOWORD(wParam); @@ -557,8 +557,11 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR if (modestate == MS_FULLSCREEN) { - IDXGISwapChain_SetFullscreenState(d3dswapchain, vid.activeapp, d3dscreen); - D3D11_DoResize(); + if (d3dswapchain) + { + IDXGISwapChain_SetFullscreenState(d3dswapchain, vid.activeapp, d3dscreen); + D3D11_DoResize(); + } } Cvar_ForceCallback(&v_gamma); @@ -1429,81 +1432,83 @@ static void (D3D11_R_RenderView) (void) qboolean dofbo = *r_refdef.rt_destcolour[0].texname || *r_refdef.rt_depth.texname; // texid_t colourrt[1]; - if (r_speeds.ival) - time1 = Sys_DoubleTime(); - - if (dofbo) - D3D11_ApplyRenderTargets(true); - else - ID3D11DeviceContext_ClearDepthStencilView(d3ddevctx, fb_backdepthstencil, D3D11_CLEAR_DEPTH, 1, 0); //is it faster to clear the stencil too? - - //check if we can do underwater warp - if (cls.protocol != CP_QUAKE2) //quake2 tells us directly + if (!r_norefresh.value) { - if (r_viewcontents & FTECONTENTS_FLUID) - r_refdef.flags |= RDF_UNDERWATER; + if (r_speeds.ival) + time1 = Sys_DoubleTime(); + + if (dofbo) + D3D11_ApplyRenderTargets(true); else - r_refdef.flags &= ~RDF_UNDERWATER; - } - if (r_refdef.flags & RDF_UNDERWATER) - { - extern cvar_t r_projection; - if (!r_waterwarp.value || r_projection.ival) - r_refdef.flags &= ~RDF_UNDERWATER; //no warp at all -// else if (r_waterwarp.value > 0 && scenepp_waterwarp) -// r_refdef.flags |= RDF_WATERWARP; //try fullscreen warp instead if we can - } + ID3D11DeviceContext_ClearDepthStencilView(d3ddevctx, fb_backdepthstencil, D3D11_CLEAR_DEPTH, 1, 0); //is it faster to clear the stencil too? - D3D11_SetupViewPort(); - //unlike gl, we clear colour beforehand, because that seems more sane. - //always clear depth - - x = (r_refdef.vrect.x * (int)vid.pixelwidth)/(int)vid.width; - x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.pixelwidth/(int)vid.width; - y = (r_refdef.vrect.y * (int)vid.pixelheight)/(int)vid.height; - y2 = (r_refdef.vrect.y + r_refdef.vrect.height) * (int)vid.pixelheight/(int)vid.height; - r_refdef.pxrect.x = floor(x); - r_refdef.pxrect.y = floor(y); - r_refdef.pxrect.width = (int)ceil(x2) - r_refdef.pxrect.x; - r_refdef.pxrect.height = (int)ceil(y2) - r_refdef.pxrect.y; - - Surf_SetupFrame(); - - //fixme: waterwarp fov - - R_SetFrustum (r_refdef.m_projection, r_refdef.m_view); - RQ_BeginFrame(); -// if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL)) -// { -// if (cl.worldmodel) -// P_DrawParticles (); -// } - - if (!(r_refdef.flags & RDF_NOWORLDMODEL)) - if (!r_worldentity.model || r_worldentity.model->loadstate != MLS_LOADED || !cl.worldmodel) + //check if we can do underwater warp + if (cls.protocol != CP_QUAKE2) //quake2 tells us directly { - D3D11_Set2D (); - R2D_ImageColours(0, 0, 0, 1); - R2D_FillBlock(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height); - R2D_ImageColours(1, 1, 1, 1); - - if (dofbo) - D3D11_ApplyRenderTargets(false); - return; + if (r_viewcontents & FTECONTENTS_FLUID) + r_refdef.flags |= RDF_UNDERWATER; + else + r_refdef.flags &= ~RDF_UNDERWATER; + } + if (r_refdef.flags & RDF_UNDERWATER) + { + extern cvar_t r_projection; + if (!r_waterwarp.value || r_projection.ival) + r_refdef.flags &= ~RDF_UNDERWATER; //no warp at all + // else if (r_waterwarp.value > 0 && scenepp_waterwarp) + // r_refdef.flags |= RDF_WATERWARP; //try fullscreen warp instead if we can } - Surf_DrawWorld(); - RQ_RenderBatchClear(); - D3D11_Set2D (); + D3D11_SetupViewPort(); + //unlike gl, we clear colour beforehand, because that seems more sane. + //always clear depth - if (r_speeds.ival) - { - time2 = Sys_DoubleTime(); - RQuantAdd(RQUANT_MSECS, (int)((time2-time1)*1000000)); + x = (r_refdef.vrect.x * (int)vid.pixelwidth)/(int)vid.width; + x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.pixelwidth/(int)vid.width; + y = (r_refdef.vrect.y * (int)vid.pixelheight)/(int)vid.height; + y2 = (r_refdef.vrect.y + r_refdef.vrect.height) * (int)vid.pixelheight/(int)vid.height; + r_refdef.pxrect.x = floor(x); + r_refdef.pxrect.y = floor(y); + r_refdef.pxrect.width = (int)ceil(x2) - r_refdef.pxrect.x; + r_refdef.pxrect.height = (int)ceil(y2) - r_refdef.pxrect.y; + + Surf_SetupFrame(); + + //fixme: waterwarp fov + + R_SetFrustum (r_refdef.m_projection, r_refdef.m_view); + RQ_BeginFrame(); + // if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL)) + // { + // if (cl.worldmodel) + // P_DrawParticles (); + // } + + if (!(r_refdef.flags & RDF_NOWORLDMODEL)) + if (!r_worldentity.model || r_worldentity.model->loadstate != MLS_LOADED || !cl.worldmodel) + { + D3D11_Set2D (); + R2D_ImageColours(0, 0, 0, 1); + R2D_FillBlock(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height); + R2D_ImageColours(1, 1, 1, 1); + + if (dofbo) + D3D11_ApplyRenderTargets(false); + return; + } + Surf_DrawWorld(); + RQ_RenderBatchClear(); + + if (r_speeds.ival) + { + time2 = Sys_DoubleTime(); + RQuantAdd(RQUANT_MSECS, (int)((time2-time1)*1000000)); + } + + if (dofbo) + D3D11_ApplyRenderTargets(false); } - - if (dofbo) - D3D11_ApplyRenderTargets(false); + D3D11_Set2D (); } void D3D11BE_RenderToTextureUpdate2d(qboolean destchanged) diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 54e7e891..1100f221 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -126,6 +126,7 @@ static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx) float x=0, y=0; float w, h; int iw=0, ih=0; + float s1 = 0, t1 = 0, s2 = 1, t2 = 1; float r=1,g=1,b=1,a=1; int l; char *s, tname[MAX_QPATH]; @@ -173,6 +174,18 @@ static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx) s++; h = strtod(s, &s); break; + case '$': + s1 = strtod(s+1, &s); + if (*s == ',') + s++; + t1 = strtod(s, &s); + if (*s == ',') + s++; + s2 = strtod(s, &s); + if (*s == ',') + s++; + t2 = strtod(s, &s); + break; case '?': r = strtod(s+1, &s); if (*s == ',') @@ -210,7 +223,7 @@ static void Mod_ComposeSkin(char *texture, struct cctx_s *cctx) return; R2D_ImageColours(r,g,b,a); - R2D_Image(x, 512-(y+h), w, h, 0, 1, 1, 0, sourceimg); + R2D_Image(x, cctx->height-(y+h), w, h, s1, t2, s2, t1, sourceimg); R_UnloadShader(sourceimg); //we're done with it now } //create a new skin with explicit name and text. even if its already loaded. this means you can free it safely. diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index d9fe334e..63daa2c6 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -332,7 +332,7 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips) //note that some drivers will just ignore levels that are not valid. //this means that we can't make this setting dynamic, so we might as well let the drivers know BEFORE we do the uploads, to be kind to those that are buggy.. //this is available in gles3 - if (!gl_config.gles || gl_config.glversion >= 3.0) + if (sh_config.can_mipcap) { if (targ != GL_TEXTURE_CUBE_MAP_ARB) { diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 870cfb17..86521776 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -59,6 +59,7 @@ typedef enum { #define MAX_GPU_BONES 64 //ATI drivers bug out and start to crash if you put this at 128. FIXME: make dynamic. #endif struct doll_s; +void rag_uninstanciateall(void); void rag_flushdolls(qboolean force); void rag_freedoll(struct doll_s *doll); struct doll_s *rag_createdollfromstring(struct model_s *mod, const char *fname, int numbones, const char *file); diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 3a7b9b54..c9dc0ebc 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -2753,9 +2753,13 @@ void GL_Init(void *(*getglfunction) (char *name)) sh_config.blobpath = "gles/%s.blob"; sh_config.progpath = "glsl/%s.glsl"; sh_config.shadernamefmt = "%s_gles"; + + sh_config.can_mipcap = gl_config.glversion >= 3.0; } else { + sh_config.can_mipcap = gl_config.glversion >= 1.2; + sh_config.texfmt[PTI_RGBX8] = true; //proper support //these require stuff like GL_UNSIGNED_SHORT_5_5_5_1 etc, which needs gl 1.2+ diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index e9125721..4ef44a23 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -2108,7 +2108,7 @@ void INS_ReInit(void) void INS_Shutdown(void) { } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } diff --git a/engine/gl/gl_vidmacos.c b/engine/gl/gl_vidmacos.c index 9cdb3e5c..090f2feb 100644 --- a/engine/gl/gl_vidmacos.c +++ b/engine/gl/gl_vidmacos.c @@ -205,7 +205,7 @@ void INS_Shutdown (void) void INS_Commands (void) { } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } void INS_Move (float *movements, int pnum) diff --git a/engine/gl/shader.h b/engine/gl/shader.h index ce24dd98..32069357 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -703,6 +703,7 @@ typedef struct qboolean tex_env_combine; qboolean nv_tex_env_combine4; qboolean env_add; + qboolean can_mipcap; // void (*pDeleteProg) (program_t *prog); qboolean (*pLoadBlob) (program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile); diff --git a/engine/nacl/sys_ppapi.c b/engine/nacl/sys_ppapi.c index e1c6b3d4..c507afc8 100644 --- a/engine/nacl/sys_ppapi.c +++ b/engine/nacl/sys_ppapi.c @@ -169,7 +169,7 @@ void INS_ReInit(void) void INS_Shutdown(void) { } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { } diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 90f06d2b..011948bf 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -56,7 +56,7 @@ enum ereftype_e ER_FREE, ER_OBJECT //custom sized, no vm/engine fields. }; -#define isfree ereftype != ER_ENTITY +#define ED_ISFREE(e) ((e)->ereftype != ER_ENTITY) //used by progs engine. All nulls is reset. typedef struct { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 5ce445d9..b4a9200f 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -752,13 +752,16 @@ void PR_LoadGlabalStruct(qboolean muted) globalint (true, trace_ent); globalfloat (false, trace_inopen); globalfloat (false, trace_inwater); - globalfloat (false, trace_endcontents); + globalfloat (false, trace_endcontentsf); globalint (false, trace_endcontentsi); - globalfloat (false, trace_surfaceflags); + globalfloat (false, trace_surfaceflagsf); globalint (false, trace_surfaceflagsi); globalstring (false, trace_surfacename); globalint (false, trace_brush_id); globalint (false, trace_brush_faceid); + globalint (false, trace_surface_id); + globalint (false, trace_bone_id); + globalint (false, trace_triangle_id); globalfloat (false, cycle_wrapped); globalint (false, msg_entity); globalfunc (false, main); @@ -795,15 +798,37 @@ void PR_LoadGlabalStruct(qboolean muted) #define ensureglobal(name,var) if (!(pr_globals)->name) (pr_globals)->name = &var; + if (!(pr_globals)->trace_surfaceflagsf && !(pr_globals)->trace_surfaceflagsi) + { + etype_t etype; + eval_t *v = PR_FindGlobal(svprogfuncs, "trace_surfaceflags", 0, &etype); + if (etype == ev_float) + (pr_globals)->trace_surfaceflagsf = (float*)v; + else if (etype == ev_integer) + (pr_globals)->trace_surfaceflagsi = (int*)v; + } + if (!(pr_globals)->trace_endcontentsf && !(pr_globals)->trace_endcontentsi) + { + etype_t etype; + eval_t *v = PR_FindGlobal(svprogfuncs, "trace_endcontents", 0, &etype); + if (etype == ev_float) + (pr_globals)->trace_endcontentsf = (float*)v; + else if (etype == ev_integer) + (pr_globals)->trace_endcontentsi = (int*)v; + } + // make sure these entries are always valid pointers ensureglobal(dimension_send, dimension_send_default); ensureglobal(dimension_default, dimension_default); - ensureglobal(trace_endcontents, writeonly); + ensureglobal(trace_endcontentsf, writeonly); ensureglobal(trace_endcontentsi, writeonly_int); - ensureglobal(trace_surfaceflags, writeonly); + ensureglobal(trace_surfaceflagsf, writeonly); ensureglobal(trace_surfaceflagsi, writeonly_int); ensureglobal(trace_brush_id, writeonly_int); ensureglobal(trace_brush_faceid, writeonly_int); + ensureglobal(trace_surface_id, writeonly_int); + ensureglobal(trace_bone_id, writeonly_int); + ensureglobal(trace_triangle_id, writeonly_int); ensureglobal(input_timelength, input_timelength_default); ensureglobal(input_impulse, input_impulse_default); @@ -1185,7 +1210,7 @@ void PR_ApplyCompilation_f (void) for (i=0 ; iisfree) + if (ED_ISFREE(ent)) continue; World_LinkEdict (&sv.world, (wedict_t*)ent, false); // force retouch even for stationary @@ -2355,7 +2380,7 @@ static void QCBUILTIN PF_setsize (pubprogfuncs_t *prinst, struct globalvars_s *p float *min, *max; e = G_EDICT(prinst, OFS_PARM0); - if (e->isfree) + if (ED_ISFREE(e)) { if (progstype != PROG_H2 || developer.ival) PR_RunWarning(prinst, "%s edict %i was free\n", "setsize", e->entnum); @@ -2398,7 +2423,7 @@ void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m) PR_RunWarning(prinst, "%s edict %i is read-only\n", "setmodel", e->entnum); return; } - if (e->isfree) + if (ED_ISFREE(e)) { PR_RunWarning(prinst, "%s edict %i was free\n", "setmodel", e->entnum); return; @@ -3186,14 +3211,18 @@ static void set_trace_globals(pubprogfuncs_t *prinst, struct globalvars_s *pr_gl pr_global_struct->trace_fraction = trace->fraction; pr_global_struct->trace_inwater = trace->inwater; pr_global_struct->trace_inopen = trace->inopen; - pr_global_struct->trace_surfaceflags = trace->surface?trace->surface->flags:0; + pr_global_struct->trace_surfaceflagsf = trace->surface?trace->surface->flags:0; pr_global_struct->trace_surfaceflagsi = trace->surface?trace->surface->flags:0; if (pr_global_ptrs->trace_surfacename) prinst->SetStringField(prinst, NULL, &pr_global_struct->trace_surfacename, trace->surface?trace->surface->name:NULL, true); - pr_global_struct->trace_endcontents = trace->contents; + pr_global_struct->trace_endcontentsf = trace->contents; pr_global_struct->trace_endcontentsi = trace->contents; pr_global_struct->trace_brush_id = trace->brush_id; pr_global_struct->trace_brush_faceid = trace->brush_face; + pr_global_struct->trace_surface_id = trace->surface_id; + pr_global_struct->trace_bone_id = trace->bone_id; + pr_global_struct->trace_triangle_id = trace->triangle_id; + // if (trace.fraction != 1) // VectorMA (trace->endpos, 4, trace->plane.normal, P_VEC(trace_endpos)); // else @@ -3347,7 +3376,7 @@ int PF_newcheckclient (pubprogfuncs_t *prinst, int check) if (i == check) break; // didn't find anything else - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (ent->v->health <= 0) continue; @@ -3405,7 +3434,7 @@ int PF_checkclient_Internal (pubprogfuncs_t *prinst) // return check if it might be visible ent = EDICT_NUM(prinst, w->lastcheck); - if (ent->isfree || ent->v->health <= 0) + if (ED_ISFREE(ent) || ent->v->health <= 0) { return 0; } @@ -3747,7 +3776,7 @@ static void QCBUILTIN PF_Remove (pubprogfuncs_t *prinst, struct globalvars_s *pr ed = G_EDICT(prinst, OFS_PARM0); - if (ed->isfree) + if (ED_ISFREE(ed)) { ED_CanFree(ed); //fake it if (developer.value) @@ -5735,12 +5764,12 @@ static qboolean PR_SQLResultAvailable(queryrequest_t *req, int firstrow, int num // recall self and other references ent = PROG_TO_EDICT(prinst, req->user.selfent); - if (ent->isfree || ent->xv->uniquespawnid != req->user.selfid) + if (ED_ISFREE(ent) || ent->xv->uniquespawnid != req->user.selfid) pr_global_struct->self = pr_global_struct->world; else pr_global_struct->self = req->user.selfent; ent = PROG_TO_EDICT(prinst, req->user.otherent); - if (ent->isfree || ent->xv->uniquespawnid != req->user.otherid) + if (ED_ISFREE(ent) || ent->xv->uniquespawnid != req->user.otherid) pr_global_struct->other = pr_global_struct->world; else pr_global_struct->other = req->user.otherent; @@ -5783,9 +5812,9 @@ void QCBUILTIN PF_sqlopenquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_ qreq->user.qccallback = callfunc; // save self and other references - qreq->user.selfent = PROG_TO_EDICT(prinst, pr_global_struct->self)->isfree?pr_global_struct->world:pr_global_struct->self; + qreq->user.selfent = ED_ISFREE(PROG_TO_EDICT(prinst, pr_global_struct->self))?pr_global_struct->world:pr_global_struct->self; qreq->user.selfid = PROG_TO_EDICT(prinst, qreq->user.selfent)->xv->uniquespawnid; - qreq->user.otherent = PROG_TO_EDICT(prinst, pr_global_struct->other)->isfree?pr_global_struct->world:pr_global_struct->other; + qreq->user.otherent = ED_ISFREE(PROG_TO_EDICT(prinst, pr_global_struct->other))?pr_global_struct->world:pr_global_struct->other; qreq->user.otherid = PROG_TO_EDICT(prinst, qreq->user.otherent)->xv->uniquespawnid; if (querytype & 2) @@ -6640,7 +6669,7 @@ static void QCBUILTIN PF_sv_findchain (pubprogfuncs_t *prinst, struct globalvars for (i = 1; i < *prinst->parms->sv_num_edicts; i++) { ent = EDICT_NUM(prinst, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; t = *(string_t *)&((float*)ent->v)[f]; if (!t) @@ -6673,7 +6702,7 @@ static void QCBUILTIN PF_sv_findchainfloat (pubprogfuncs_t *prinst, struct globa for (i = 1; i < *prinst->parms->sv_num_edicts; i++) { ent = EDICT_NUM(prinst, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (((float *)ent->v)[f] != s) continue; @@ -6703,7 +6732,7 @@ static void QCBUILTIN PF_sv_findchainflags (pubprogfuncs_t *prinst, struct globa for (i = 1; i < *prinst->parms->sv_num_edicts; i++) { ent = EDICT_NUM(prinst, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (!((int)((float *)ent->v)[f] & s)) continue; @@ -10113,7 +10142,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"particleeffectquery",PF_Fixme,0, 0, 0, 374, D("string(float efnum, float body)", "Retrieves either the name or the body of the effect with the given number. The effect body is regenerated from internal state, and can be changed before being reapplied via the localcmd builtin.")}, {"adddecal", PF_Fixme, 0, 0, 0, 375, D("void(string shadername, vector origin, vector up, vector side, vector rgb, float alpha)", "Adds a temporary clipped decal shader to the scene, centered at the given point with given orientation. Will be drawn by the next renderscene call, and freed by the next clearscene call.")}, - {"setcustomskin", PF_Fixme, 0, 0, 0, 376, D("void(entity e, string skinfilename, optional string skindata)", "Sets an entity's skin overrides. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format:\nsurfacename,shadername - makes the named surface use the named shader\nreplace \"surfacename\" \"shadername\" - same.\nqwskin \"foo\" - use an unmodified quakeworld player skin (including crop+repalette rules)\nq1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red\nq1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue\ncompose \"surfacename\" \"shader\" \"imagename@x,y:w,h?r,g,b,a\" - compose a skin texture from multiple images.\n The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line.\n Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader).")}, + {"setcustomskin", PF_Fixme, 0, 0, 0, 376, D("void(entity e, string skinfilename, optional string skindata)", "Sets an entity's skin overrides. These are custom per-entity surface->shader lookups. The skinfilename/data should be in .skin format:\nsurfacename,shadername - makes the named surface use the named shader\nreplace \"surfacename\" \"shadername\" - same.\nqwskin \"foo\" - use an unmodified quakeworld player skin (including crop+repalette rules)\nq1lower 0xff0000 - specify an override for the entity's lower colour, in this case to red\nq1upper 0x0000ff - specify an override for the entity's lower colour, in this case to blue\ncompose \"surfacename\" \"shader\" \"imagename@x,y:w,h$s,t,s2,t2?r,g,b,a\" - compose a skin texture from multiple images.\n The texture is determined to be sufficient to hold the first named image, additional images can be named as extra tokens on the same line.\n Use a + at the end of the line to continue reading image tokens from the next line also, the named shader must use 'map $diffuse' to read the composed texture (compatible with the defaultskin shader).")}, //END EXT_CSQC {"memalloc", PF_memalloc, 0, 0, 0, 384, D("__variant*(int size)", "Allocate an arbitary block of memory")}, @@ -11042,8 +11071,14 @@ void PR_DumpPlatform_f(void) {"input_cursor_trace_endpos", "vector", CS/*|QW|NQ*/}, {"input_cursor_trace_entnum", "float", CS/*|QW|NQ*/}, + {"trace_endcontents", "int", QW|NQ|CS}, + {"trace_surfaceflags", "int", QW|NQ|CS}, +// {"trace_surfacename", "string", QW|NQ|CS}, {"trace_brush_id", "int", QW|NQ|CS}, {"trace_brush_faceid", "int", QW|NQ|CS}, + {"trace_surface_id", "int", QW|NQ|CS, "1-based. 0 if not known."}, + {"trace_bone_id", "int", QW|NQ|CS, "1-based. 0 if not known. typically needs MOVE_HITMODEL."}, + {"trace_triangle_id", "int", QW|NQ|CS, "1-based. 0 if not known."}, {"global_gravitydir", "vector", QW|NQ|CS, "The direction gravity should act in if not otherwise specified per entity.", 0,"'0 0 -1'"}, {"serverid", "int", QW|NQ|CS, "The unique id of this server within the server cluster."}, diff --git a/engine/server/pr_lua.c b/engine/server/pr_lua.c index c695ee39..38a6bd78 100644 --- a/engine/server/pr_lua.c +++ b/engine/server/pr_lua.c @@ -36,9 +36,9 @@ globalentity (true, trace_ent) \ globalfloat (true, trace_inopen) \ globalfloat (true, trace_inwater) \ - globalfloat (false, trace_endcontents) \ + globalfloat (false, trace_endcontentsf) \ globalint (false, trace_endcontentsi) \ - globalfloat (false, trace_surfaceflags) \ + globalfloat (false, trace_surfaceflagsf) \ globalint (false, trace_surfaceflagsi) \ globalfloat (false, cycle_wrapped) \ globalentity (false, msg_entity) \ diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index ce7d3af1..06db2caa 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -454,7 +454,7 @@ static edict_t *QDECL Q1QVMPF_EntAlloc(pubprogfuncs_t *pf, pbool object, size_t e = (edict_t*)EDICT_NUM(pf, i); // the first couple seconds of server time can involve a lot of // freeing and allocating, so relax the replacement policy - if (!e || (e->isfree && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )) + if (!e || (ED_ISFREE(e) && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )) { Q1QVMED_ClearEdict (e, true); @@ -470,7 +470,7 @@ static edict_t *QDECL Q1QVMPF_EntAlloc(pubprogfuncs_t *pf, pbool object, size_t e = (edict_t*)EDICT_NUM(pf, i); // the first couple seconds of server time can involve a lot of // freeing and allocating, so relax the replacement policy - if (!e || (e->isfree)) + if (!e || ED_ISFREE(e)) { Q1QVMED_ClearEdict (e, true); @@ -669,7 +669,7 @@ static qintptr_t QVM_LightStyle (void *offset, quintptr_t mask, const qintptr_t static qintptr_t QVM_SetOrigin (void *offset, quintptr_t mask, const qintptr_t *arg) { edict_t *e = Q1QVMPF_EdictNum(svprogfuncs, VM_LONG(arg[0])); - if (!e || e->isfree) + if (!e || ED_ISFREE(e)) return false; e->v->origin[0] = VM_FLOAT(arg[1]); @@ -681,7 +681,7 @@ static qintptr_t QVM_SetOrigin (void *offset, quintptr_t mask, const qintptr_t * static qintptr_t QVM_SetSize (void *offset, quintptr_t mask, const qintptr_t *arg) { edict_t *e = Q1QVMPF_EdictNum(svprogfuncs, arg[0]); - if (!e || e->isfree) + if (!e || ED_ISFREE(e)) return false; e->v->mins[0] = VM_FLOAT(arg[1]); @@ -793,7 +793,7 @@ static qintptr_t QVM_FindRadius (void *offset, quintptr_t mask, const qintptr_t for(start++; start < sv.world.num_edicts; start++) { ed = EDICT_NUM(svprogfuncs, start); - if (ed->isfree) + if (ED_ISFREE(ed)) continue; VectorSubtract(ed->v->origin, org, diff); if (rad > DotProduct(diff, diff)) @@ -875,7 +875,7 @@ static qintptr_t QVM_NextEnt (void *offset, quintptr_t mask, const qintptr_t *ar return 0; } ent = EDICT_NUM(svprogfuncs, i); - if (!ent->isfree) + if (!ED_ISFREE(ent)) { return i; } @@ -2034,9 +2034,9 @@ qboolean PR_LoadQ1QVM(void) globalint (true, trace_ent); globalfloat (true, trace_inopen); globalfloat (true, trace_inwater); - globalnull (false, trace_endcontents); + globalnull (false, trace_endcontentsf); globalnull (false, trace_endcontentsi); - globalnull (false, trace_surfaceflags); + globalnull (false, trace_surfaceflagsf); globalnull (false, trace_surfaceflagsi); globalnull (false, cycle_wrapped); globalint (false, msg_entity); @@ -2051,9 +2051,9 @@ qboolean PR_LoadQ1QVM(void) globalfunc (false, SetNewParms); globalfunc (false, SetChangeParms); - pr_global_ptrs->trace_surfaceflags = &writable; + pr_global_ptrs->trace_surfaceflagsf = &writable; pr_global_ptrs->trace_surfaceflagsi = &writable_int; - pr_global_ptrs->trace_endcontents = &writable; + pr_global_ptrs->trace_endcontentsf = &writable; pr_global_ptrs->trace_endcontentsi = &writable_int; pr_global_ptrs->dimension_default = &dimensiondefault; pr_global_ptrs->dimension_send = &dimensionsend; diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 056dc526..240c10a0 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -60,13 +60,16 @@ typedef struct nqglobalvars_s float *trace_allsolid; float *trace_startsolid; float *trace_fraction; - float *trace_surfaceflags; + float *trace_surfaceflagsf; int *trace_surfaceflagsi; string_t*trace_surfacename; - float *trace_endcontents; + float *trace_endcontentsf; int *trace_endcontentsi; int *trace_brush_id; int *trace_brush_faceid; + int *trace_surface_id; + int *trace_bone_id; + int *trace_triangle_id; vec3_t *trace_endpos; vec3_t *trace_plane_normal; float *trace_plane_dist; diff --git a/engine/server/savegame.c b/engine/server/savegame.c index b224e541..aaef861c 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -337,7 +337,7 @@ void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version) if (!ent) break; - if (ent->isfree) + if (ED_ISFREE(ent)) continue; World_LinkEdict (&sv.world, (wedict_t*)ent, false); @@ -839,7 +839,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char * for (i=0 ; iisfree) + if (ED_ISFREE(ent)) continue; World_LinkEdict (&sv.world, (wedict_t*)ent, false); @@ -847,7 +847,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char * for (i=0 ; iisfree) + if (ED_ISFREE(ent)) continue; /*hexen2 instead overwrites ents, which can theoretically be unreliable (ents with this flag are not saved in the first place, and thus are effectively reset instead of reloaded). diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index e6e6ad8d..a697b86d 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -3532,7 +3532,7 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t for ( ; eisfree) + if (ED_ISFREE(ent)) continue; if (ent->xv->customizeentityforclient) @@ -4001,7 +4001,7 @@ void SV_ProcessSendFlags(client_t *c) for (e=1 ; emax_net_ents; e++) { ent = EDICT_NUM(svprogfuncs, e); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (ent->xv->SendFlags) { diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 36079344..f1d70240 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -237,7 +237,7 @@ void SVQ1_CreateBaseline (void) memcpy(&svent->baseline, &nullentitystate, sizeof(entity_state_t)); svent->baseline.number = entnum; - if (svent->isfree) + if (ED_ISFREE(svent)) continue; // create baselines for all player slots, // and any other edict that has a visible model diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 7cab2c3d..32726852 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -192,7 +192,7 @@ qboolean WPhys_RunThink (world_t *w, wedict_t *ent) ent->v->nextthink = 0; *w->g.time = thinktime; w->Event_Think(w, ent); - return !ent->isfree; + return !ED_ISFREE(ent); } do @@ -212,7 +212,7 @@ qboolean WPhys_RunThink (world_t *w, wedict_t *ent) *w->g.time = thinktime; w->Event_Think(w, ent); - if (ent->isfree) + if (ED_ISFREE(ent)) return false; if (ent->v->nextthink <= thinktime) //hmm... infinate loop was possible here.. Quite a few non-QW mods do this. @@ -465,7 +465,7 @@ static int WPhys_FlyMove (world_t *w, wedict_t *ent, const vec3_t gravitydir, fl // run the impact function // WPhys_Impact (w, ent, &trace); - if (ent->isfree) + if (ED_ISFREE(ent)) break; // removed by the impact function @@ -698,7 +698,7 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec for (e = 1; e < w->num_edicts; e++) { check = WEDICT_NUM(w->progs, e); - if (check->isfree) + if (ED_ISFREE(check)) continue; if (check->v->movetype == MOVETYPE_PUSH @@ -891,7 +891,7 @@ static qboolean WPhys_Push (world_t *w, wedict_t *pusher, vec3_t move, vec3_t am for (e=1 ; enum_edicts ; e++) { check = WEDICT_NUM(w->progs, e); - if (check->isfree) + if (ED_ISFREE(check)) continue; if (check->v->movetype == MOVETYPE_PUSH || check->v->movetype == MOVETYPE_NONE @@ -1109,7 +1109,7 @@ VectorCopy (ent->v->angles, oldang); #endif PR_ExecuteProgram (svprogfuncs, ent->v->think); #endif - if (ent->isfree) + if (ED_ISFREE(ent)) return; VectorSubtract (ent->v->origin, oldorg, move); VectorSubtract (ent->v->angles, oldang, amove); @@ -1316,7 +1316,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) { wedict_t *onent; onent = PROG_TO_WEDICT(w->progs, ent->v->groundentity); - if (!onent->isfree) + if (!ED_ISFREE(onent)) return; //don't drop if our fround is still valid } else @@ -1365,7 +1365,7 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent) } if (trace.fraction == 1) return; - if (ent->isfree) + if (ED_ISFREE(ent)) return; VectorCopy(trace.endpos, move); @@ -2017,7 +2017,7 @@ void WPhys_MoveChain(world_t *w, wedict_t *ent, wedict_t *movechain, float *init VectorSubtract(ent->v->angles, initial_angle, moveang); VectorSubtract(ent->v->origin, initial_origin, moveorg); - for(i=16;i && movechain != w->edicts && !movechain->isfree;i--, movechain = PROG_TO_WEDICT(w->progs, movechain->xv->movechain)) + for(i=16;i && movechain != w->edicts && !ED_ISFREE(movechain);i--, movechain = PROG_TO_WEDICT(w->progs, movechain->xv->movechain)) { if ((int)movechain->v->flags & FL_MOVECHAIN_ANGLE) VectorAdd(movechain->v->angles, moveang, movechain->v->angles); //FIXME: axial only @@ -2319,7 +2319,7 @@ void World_Physics_Frame(world_t *w) for (i=0 ; inum_edicts ; i++) { ent = (wedict_t*)EDICT_NUM(w->progs, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; WPhys_RunThink (w, ent); @@ -2337,7 +2337,7 @@ void World_Physics_Frame(world_t *w) for (i=0 ; inum_edicts ; i++) { ent = (wedict_t*)EDICT_NUM(w->progs, i); - if (ent->isfree) + if (ED_ISFREE(ent)) continue; if (retouch) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 5cacc1ec..f8c5fffe 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -6309,7 +6309,7 @@ void AddAllEntsToPmove (edict_t *player) for (e=1 ; eisfree) + if (ED_ISFREE(check)) continue; if (check->v->owner == pl) continue; @@ -6993,7 +6993,7 @@ if (sv_player->v->health > 0 && before && !after ) sv.world.Event_Touch(&sv.world, (wedict_t*)ent, (wedict_t*)sv_player); } - if (sv_player->v->touch && !ent->isfree) + if (sv_player->v->touch && !ED_ISFREE(ent)) sv.world.Event_Touch(&sv.world, (wedict_t*)sv_player, (wedict_t*)ent); } } @@ -7095,7 +7095,7 @@ void SV_ReadPrydonCursor(void) } // as requested by FrikaC, cursor_trace_ent is reset to world if the // entity is free at time of receipt - if (!svprogfuncs || EDICT_NUM(svprogfuncs, entnum)->isfree) + if (!svprogfuncs || ED_ISFREE(EDICT_NUM(svprogfuncs, entnum))) entnum = 0; if (msg_badread) Con_Printf("SV_ReadPrydonCursor: badread at %s:%i\n", __FILE__, __LINE__); diff --git a/engine/server/world.c b/engine/server/world.c index 72ffc17a..39f852e9 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -355,7 +355,7 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node) touch = nodelinks[ln]; //make sure nothing moved it away - if (touch->isfree) + if (ED_ISFREE(touch)) continue; if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER) continue; @@ -373,13 +373,13 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node) w->Event_Touch(w, touch, ent); - if (ent->isfree) + if (ED_ISFREE(ent)) break; } // recurse down both sides - if (node->axis == -1 || ent->isfree) + if (node->axis == -1 || ED_ISFREE(ent)) return; if (ent->v->absmax[node->axis] > node->dist) @@ -474,7 +474,7 @@ void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers) if (ent == w->edicts) return; // don't add the world - if (ent->isfree) + if (ED_ISFREE(ent)) return; // set the abs box @@ -1538,8 +1538,8 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip) { touch = (wedict_t*)EDICT_NUM(w->progs, e); - if (touch->isfree) - continue; + if (ED_ISFREE(touch)) + continue; if (touch->v->solid == SOLID_NOT && !((int)touch->v->flags & FL_FINDABLE_NONSOLID)) continue; if (touch->v->solid == SOLID_TRIGGER && !((int)touch->v->flags & FL_FINDABLE_NONSOLID)) @@ -2139,7 +2139,7 @@ void World_RBE_Shutdown(world_t *world) void QDECL World_UnregisterPhysicsEngine(const char *enginename) { #ifdef RAGDOLL -// rag_uninstanciateall(); + rag_uninstanciateall(); #endif #if defined(CSQC_DAT) && !defined(SERVERONLY) diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 940ef96e..4c17736b 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -36,6 +36,9 @@ extern cvar_t r_portalrecursion; extern cvar_t r_polygonoffset_shadowmap_offset, r_polygonoffset_shadowmap_factor; extern cvar_t r_wireframe; +extern cvar_t vk_stagingbuffers; + +unsigned int vk_usedynamicstaging; static void VK_TerminateShadowMap(void); void VKBE_BeginShadowmapFace(void); @@ -629,6 +632,7 @@ static const char LIGHTPASS_SHADER[] = "\ void VKBE_Init(void) { int i; + char *c; sh_config.pDeleteProg = VKBE_DeleteProg; @@ -713,6 +717,29 @@ void VKBE_Init(void) } shaderstate.staticbuf = VKBE_FinishStaging(&lazybuf, &shaderstate.staticbufmem); } + + + c = vk_stagingbuffers.string; + if (*c) + { + vk_usedynamicstaging = 0; + while (*c) + { + if (*c == 'u') + vk_usedynamicstaging |= 1u<size = (1u<<20); - bufinf.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - bufinf.queueFamilyIndexCount = 0; - bufinf.pQueueFamilyIndices = NULL; -#ifdef USE_DYNAMIC_STAGING - bufinf.usage = ufl[type]|VK_BUFFER_USAGE_TRANSFER_DST_BIT; - vkCreateBuffer(vk.device, &bufinf, vkallocationcb, &n->devicebuf); - bufinf.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - vkCreateBuffer(vk.device, &bufinf, vkallocationcb, &n->stagingbuf); + bufinf.flags = 0; + bufinf.size = n->size = (1u<<20); + bufinf.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufinf.queueFamilyIndexCount = 0; + bufinf.pQueueFamilyIndices = NULL; - vkGetBufferMemoryRequirements(vk.device, n->devicebuf, &mem_reqs); - n->align = mem_reqs.alignment-1; - memAllocInfo.allocationSize = mem_reqs.size; - memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - if (memAllocInfo.memoryTypeIndex == ~0) - memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0); //device will still be okay with this usage... - VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &n->devicememory)); - VkAssert(vkBindBufferMemory(vk.device, n->devicebuf, n->devicememory, 0)); -#else - bufinf.usage = ufl[type]; - vkCreateBuffer(vk.device, &bufinf, vkallocationcb, &n->stagingbuf); -#endif + if (vk_usedynamicstaging & (1u<devicebuf); + bufinf.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + vkCreateBuffer(vk.device, &bufinf, vkallocationcb, &n->stagingbuf); + + vkGetBufferMemoryRequirements(vk.device, n->devicebuf, &mem_reqs); + n->align = mem_reqs.alignment-1; + memAllocInfo.allocationSize = mem_reqs.size; + memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (memAllocInfo.memoryTypeIndex == ~0) + memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0); //device will still be okay with this usage... + VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &n->devicememory)); + VkAssert(vkBindBufferMemory(vk.device, n->devicebuf, n->devicememory, 0)); + + n->renderbuf = n->devicebuf; + } + else + { + bufinf.usage = ufl[type]; + vkCreateBuffer(vk.device, &bufinf, vkallocationcb, &n->stagingbuf); + + n->renderbuf = n->stagingbuf; + } vkGetBufferMemoryRequirements(vk.device, n->stagingbuf, &mem_reqs); n->align = mem_reqs.alignment-1; @@ -827,17 +862,16 @@ static void *fte_restrict VKBE_AllocateBufferSpace(enum dynbuf_e type, size_t da range.memory = b->stagingmemory; vkFlushMappedMemoryRanges(vk.device, 1, &range); -#ifdef USE_DYNAMIC_STAGING + if (b->devicebuf != VK_NULL_HANDLE) { - VkCommandBuffer cb = VK_FencedBegin(); + struct vk_fencework *fence = VK_FencedBegin(NULL, 0); VkBufferCopy bcr = {0}; bcr.srcOffset = 0; bcr.dstOffset = 0; bcr.size = b->offset; - vkCmdCopyBuffer(cb, b->stagingbuf, b->devicebuf, 1, &bcr); - VK_FencedSubmit(cb, NULL, 0); + vkCmdCopyBuffer(fence->cbuf, b->stagingbuf, b->devicebuf, 1, &bcr); + VK_FencedSubmit(fence); } -#endif if (!b->next) VKBE_AllocNewBuffer(&b->next, type); @@ -845,11 +879,7 @@ static void *fte_restrict VKBE_AllocateBufferSpace(enum dynbuf_e type, size_t da b->offset = 0; } -#ifdef USE_DYNAMIC_STAGING - *buf = b->devicebuf; -#else - *buf = b->stagingbuf; -#endif + *buf = b->renderbuf; *offset = b->offset; ret = (qbyte*)b->ptr + b->offset; @@ -895,12 +925,9 @@ void VKBE_InitFramePools(struct vkframe *frame) //called just before submits //makes sure that our persistent-mapped memory writes can actually be seen by the hardware. -#ifdef USE_DYNAMIC_STAGING -void VKBE_FlushDynamicBuffers(VkCommandBuffer cb) -#else void VKBE_FlushDynamicBuffers(void) -#endif { + struct vk_fencework *fence = NULL; uint32_t i; struct dynbuffer *d; VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE}; @@ -916,16 +943,20 @@ void VKBE_FlushDynamicBuffers(void) range.memory = d->stagingmemory; vkFlushMappedMemoryRanges(vk.device, 1, &range); -#ifdef USE_DYNAMIC_STAGING + if (d->devicebuf != VK_NULL_HANDLE) { VkBufferCopy bcr = {0}; bcr.srcOffset = 0; bcr.dstOffset = 0; bcr.size = d->offset; - vkCmdCopyBuffer(cb, d->stagingbuf, d->devicebuf, 1, &bcr); + if (!fence) + fence = VK_FencedBegin(NULL, 0); + vkCmdCopyBuffer(fence->cbuf, d->stagingbuf, d->devicebuf, 1, &bcr); } -#endif } + + if (fence) + VK_FencedSubmit(fence); } void VKBE_Set2D(qboolean twodee) @@ -966,10 +997,11 @@ void VKBE_ShutdownFramePools(struct vkframe *frame) db = frame->dynbufs[i]; vkDestroyBuffer(vk.device, db->stagingbuf, vkallocationcb); vkFreeMemory(vk.device, db->stagingmemory, vkallocationcb); -#ifdef USE_DYNAMIC_STAGING - vkDestroyBuffer(vk.device, db->devicebuf, vkallocationcb); - vkFreeMemory(vk.device, db->devicememory, vkallocationcb); -#endif + if (db->devicebuf != VK_NULL_HANDLE) + { + vkDestroyBuffer(vk.device, db->devicebuf, vkallocationcb); + vkFreeMemory(vk.device, db->devicememory, vkallocationcb); + } frame->dynbufs[i] = db->next; Z_Free(db); } @@ -2049,8 +2081,17 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i pipe = Z_Malloc(sizeof(*pipe)); - pipe->next = p->pipelines; - p->pipelines = pipe; + if (!p->pipelines) + p->pipelines = pipe; + else + { //insert at end. if it took us a while to realise that we needed it, chances are its not that common. + //so don't cause the other pipelines to waste cycles for it. + struct pipeline_s *prev; + for (prev = p->pipelines; ; prev = prev->next) + if (!prev->next) + break; + prev->next = pipe; + } pipe->flags = shaderflags; pipe->blendbits = blendflags; diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 1749bb9c..50fa6f74 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -5,6 +5,7 @@ #include "shader.h" #include "renderque.h" //is anything still using this? +extern qboolean vid_isfullscreen; extern cvar_t vk_submissionthread; extern cvar_t vk_debug; extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method; @@ -281,7 +282,7 @@ static qboolean VK_CreateSwapChain(void) swapinfo.queueFamilyIndexCount = 0; swapinfo.pQueueFamilyIndices = NULL; swapinfo.oldSwapchain = vk.swapchain; - swapinfo.clipped = VK_TRUE; //allow fragment shaders to be skipped on parts that are obscured by another window. screenshots might get weird, so use proper captures if required/automagic. + swapinfo.clipped = vid_isfullscreen?VK_FALSE:VK_TRUE; //allow fragment shaders to be skipped on parts that are obscured by another window. screenshots might get weird, so use proper captures if required/automagic. swapinfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; //supposed to be guarenteed support. for (i = 0, curpri = 0; i < presentmodes; i++) @@ -376,7 +377,7 @@ static qboolean VK_CreateSwapChain(void) VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefences[i])); } /*-1 to hide any weird thread issues*/ - while (vk.aquirelast < ACQUIRELIMIT-1 && vk.aquirelast < vk.backbuf_count && vk.aquirelast <= vk.backbuf_count-surfcaps.minImageCount) + while (vk.aquirelast < ACQUIRELIMIT-1 && vk.aquirelast < vk.backbuf_count && vk.aquirelast < 2 && vk.aquirelast <= vk.backbuf_count-surfcaps.minImageCount) { VkAssert(vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT])); vk.aquirelast++; @@ -593,8 +594,6 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay format = VK_FORMAT_R5G5B5A1_UNORM_PACK16; else if (encoding == PTI_ARGB1555) format = VK_FORMAT_A1R5G5B5_UNORM_PACK16; - else if (encoding == PTI_ARGB1555) - format = VK_FORMAT_A1R5G5B5_UNORM_PACK16; //float formats else if (encoding == PTI_RGBA16F) format = VK_FORMAT_R16G16B16A16_SFLOAT; @@ -893,6 +892,7 @@ qboolean VK_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips) blocksize = 1; blockbytes = 2; break; + default: return false; } @@ -1746,7 +1746,7 @@ qboolean VK_SCR_GrabBackBuffer(void) } //wait for the queued acquire to actually finish - if (1)//vk.vsync) + if (vk.vsync) { //friendly wait VkAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX)); @@ -2033,14 +2033,7 @@ qboolean VK_SCR_UpdateScreen (void) { RSpeedRemark(); - -#ifdef USE_DYNAMIC_STAGING - bufs[0] = VK_FencedBegin(); - VKBE_FlushDynamicBuffers(bufs[0]); - VK_FencedSubmit(bufs[0], NULL, 0); -#else VKBE_FlushDynamicBuffers(); -#endif RSpeedEnd(RSPEED_SUBMIT); } @@ -2255,6 +2248,8 @@ static void VK_Submit_DoWork(void) Sys_LockMutex(vk.swapchain_mutex); err = vkQueuePresentKHR(vk.queue_present, &presinfo); Sys_UnlockMutex(vk.swapchain_mutex); + RSpeedEnd(RSPEED_PRESENT); + RSpeedRemark(); if (err) { Con_Printf("ERROR: vkQueuePresentKHR: %x\n", err); @@ -2263,7 +2258,7 @@ static void VK_Submit_DoWork(void) #ifdef THREADACQUIRE else { - err = vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]); + err = vkAcquireNextImageKHR(vk.device, vk.swapchain, 0, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]); if (err) { Con_Printf("ERROR: vkAcquireNextImageKHR: %x\n", err); @@ -2272,7 +2267,7 @@ static void VK_Submit_DoWork(void) vk.aquirelast++; } #endif - RSpeedEnd(RSPEED_PRESENT); + RSpeedEnd(RSPEED_ACQUIRE); } } @@ -2336,6 +2331,56 @@ void VK_Submit_Work(VkCommandBuffer cmdbuf, VkSemaphore semwait, VkPipelineStage Sys_UnlockConditional(vk.submitcondition); } +void VK_CheckTextureFormats(void) +{ + struct { + unsigned int pti; + VkFormat vulkan; + unsigned int needextra; + } texfmt[] = + { + {PTI_RGBA8, VK_FORMAT_R8G8B8A8_UNORM}, + {PTI_RGBX8, VK_FORMAT_R8G8B8A8_UNORM}, + {PTI_BGRA8, VK_FORMAT_B8G8R8A8_UNORM}, + {PTI_BGRX8, VK_FORMAT_B8G8R8A8_UNORM}, + {PTI_RGB565, VK_FORMAT_R5G6B5_UNORM_PACK16}, + {PTI_RGBA4444, VK_FORMAT_R4G4B4A4_UNORM_PACK16}, + {PTI_ARGB4444, VK_FORMAT_B4G4R4A4_UNORM_PACK16}, + {PTI_RGBA5551, VK_FORMAT_R5G5B5A1_UNORM_PACK16}, + {PTI_ARGB1555, VK_FORMAT_A1R5G5B5_UNORM_PACK16}, + {PTI_RGBA16F, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT}, + {PTI_RGBA32F, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT}, + {PTI_R8, VK_FORMAT_R8_UNORM}, + {PTI_RG8, VK_FORMAT_R8G8_UNORM}, + + {PTI_DEPTH16, VK_FORMAT_D16_UNORM, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + {PTI_DEPTH24, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + {PTI_DEPTH32, VK_FORMAT_D32_SFLOAT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + {PTI_DEPTH24_8, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + + {PTI_S3RGB1, VK_FORMAT_BC1_RGB_UNORM_BLOCK}, + {PTI_S3RGBA1, VK_FORMAT_BC1_RGBA_UNORM_BLOCK}, + {PTI_S3RGBA3, VK_FORMAT_BC2_UNORM_BLOCK}, + {PTI_S3RGBA5, VK_FORMAT_BC3_UNORM_BLOCK}, + }; + unsigned int i; + VkPhysicalDeviceProperties props; + + vkGetPhysicalDeviceProperties(vk.gpu, &props); + + sh_config.texture_maxsize = props.limits.maxImageDimension2D; + + for (i = 0; i < countof(texfmt); i++) + { + unsigned int need = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | texfmt[i].needextra; + VkFormatProperties fmt; + vkGetPhysicalDeviceFormatProperties(vk.gpu, texfmt[i].vulkan, &fmt); + + if ((fmt.optimalTilingFeatures & need) == need) + sh_config.texfmt[texfmt[i].pti] = true; + } +} + //initialise the vulkan instance, context, device, etc. qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*createSurface)(void)) { @@ -2356,6 +2401,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat vk.neednewswapchain = true; vk.triplebuffer = info->triplebuffer; vk.vsync = info->wait; + memset(&sh_config, 0, sizeof(sh_config)); //get second set of pointers... @@ -2492,6 +2538,58 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat } } + { + char *vendor, *type; + VkPhysicalDeviceProperties props; + vkGetPhysicalDeviceProperties(vk.gpu, &props); + + switch(props.vendorID) + { + //explicit vendors + case 0x10001: vendor = "Vivante"; break; + case 0x10002: vendor = "VeriSilicon"; break; + + //pci vendor ids + //there's a lot of pci vendors, some even still exist, but not all of them actually have 3d hardware. + //many of these probably won't even be used... Oh well. + //anyway, here's some of the ones that are listed + case 0x1002: vendor = "AMD"; break; + case 0x10DE: vendor = "NVIDIA"; break; + case 0x8086: vendor = "Intel"; break; //cute + case 0x13B5: vendor = "ARM"; break; + case 0x5143: vendor = "Qualcomm"; break; + case 0x1AEE: vendor = "Imagination";break; + case 0x1957: vendor = "Freescale"; break; + + case 0x1AE0: vendor = "Google"; break; + case 0x5333: vendor = "S3"; break; + case 0xA200: vendor = "NEC"; break; + case 0x0A5C: vendor = "Broadcom"; break; + case 0x1131: vendor = "NXP"; break; + case 0x1099: vendor = "Samsung"; break; + case 0x10C3: vendor = "Samsung"; break; + case 0x11E2: vendor = "Samsung"; break; + case 0x1249: vendor = "Samsung"; break; + + default: vendor = va("VEND_%x", props.vendorID); break; + } + + switch(props.deviceType) + { + default: + case VK_PHYSICAL_DEVICE_TYPE_OTHER: type = "(other)"; break; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: type = "integrated"; break; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: type = "discrete"; break; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: type = "virtual"; break; + case VK_PHYSICAL_DEVICE_TYPE_CPU: type = "software"; break; + } + + Con_Printf("Vulkan %u.%u.%u: %s %s %s (%u.%u.%u)\n", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion), + type, vendor, props.deviceName, + VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion), VK_VERSION_PATCH(props.driverVersion) + ); + } + //create the platform-specific surface createSurface(); @@ -2591,17 +2689,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat VkAssert(vkCreateCommandPool(vk.device, &cpci, vkallocationcb, &vk.cmdpool)); } - vk.depthformat = VK_FORMAT_D32_SFLOAT;//VK_FORMAT_D32_SFLOAT_S8_UINT;//VK_FORMAT_D24_UNORM_S8_UINT;//VK_FORMAT_D16_UNORM; - -#ifndef THREADACQUIRE - { - VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; - VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefence)); - } -#endif - - - memset(&sh_config, 0, sizeof(sh_config)); + sh_config.progpath = NULL;//"vulkan"; sh_config.blobpath = "spirv"; sh_config.shadernamefmt = NULL;//".spv"; @@ -2611,35 +2699,6 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat sh_config.minver = -1; sh_config.maxver = -1; - //depth formats need to support attachments - //other formats might be supported for staging - sh_config.texfmt[PTI_RGBA8] = true; - sh_config.texfmt[PTI_RGBX8] = true; - sh_config.texfmt[PTI_BGRA8] = true; - sh_config.texfmt[PTI_BGRX8] = true; - sh_config.texfmt[PTI_RGB565] = true; -// sh_config.texfmt[PTI_RGBA4444] = true; //FIXME: other formats -// sh_config.texfmt[PTI_ARGB4444] = true; //FIXME: other formats -// sh_config.texfmt[PTI_RGBA5551] = true; //FIXME: other formats -// sh_config.texfmt[PTI_ARGB1555] = true; //FIXME: other formats - sh_config.texfmt[PTI_RGBA16F] = true; -// sh_config.texfmt[PTI_RGBA32F] = true; - sh_config.texfmt[PTI_R8] = true; //FIXME: other formats - sh_config.texfmt[PTI_RG8] = true; //FIXME: other formats -// sh_config.texfmt[PTI_S3RGB1] = true; //FIXME: other formats -// sh_config.texfmt[PTI_S3RGBA1] = true; //FIXME: other formats -// sh_config.texfmt[PTI_S3RGBA3] = true; //FIXME: other formats -// sh_config.texfmt[PTI_S3RGBA5] = true; //FIXME: other formats - sh_config.texfmt[PTI_DEPTH16] = true; //guarenteed, supposedly. -// sh_config.texfmt[PTI_DEPTH24] = true; //FIXME: other formats -// sh_config.texfmt[PTI_DEPTH32] = true; //FIXME: other formats -// sh_config.texfmt[PTI_DEPTH24_8] = true; //FIXME: other formats - - sh_config.texfmt[PTI_S3RGB1] = true; - sh_config.texfmt[PTI_S3RGBA1] = true; - sh_config.texfmt[PTI_S3RGBA3] = true; - sh_config.texfmt[PTI_S3RGBA5] = true; - sh_config.texture_maxsize = 4096; //must be at least 4096, FIXME: query this properly sh_config.texture_non_power_of_two = true; //is this always true? sh_config.texture_non_power_of_two_pic = true; //probably true... @@ -2648,12 +2707,33 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat sh_config.nv_tex_env_combine4 = false; //fixme: figure out what this means... sh_config.env_add = false; //fixme: figure out what this means... + sh_config.can_mipcap = true; + + VK_CheckTextureFormats(); + sh_config.pDeleteProg = NULL; sh_config.pLoadBlob = NULL; sh_config.pCreateProgram = NULL; sh_config.pValidateProgram = NULL; sh_config.pProgAutoFields = NULL; + + if (sh_config.texfmt[PTI_DEPTH32]) + vk.depthformat = VK_FORMAT_D32_SFLOAT; + else if (sh_config.texfmt[PTI_DEPTH24]) + vk.depthformat = VK_FORMAT_X8_D24_UNORM_PACK32; + else if (sh_config.texfmt[PTI_DEPTH24_8]) + vk.depthformat = VK_FORMAT_D24_UNORM_S8_UINT; + else //16bit depth is guarenteed in vulkan + vk.depthformat = VK_FORMAT_D16_UNORM; + +#ifndef THREADACQUIRE + { + VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefence)); + } +#endif + /* void (*pDeleteProg) (program_t *prog, unsigned int permu); qboolean (*pLoadBlob) (program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile); diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 71a45c1d..ca9c0f95 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -18,8 +18,7 @@ #define UINT64_MAX _UI64_MAX #endif -//#define USE_DYNAMIC_STAGING //seems faster to not bother on nvidia. plus all other vendors seem to have host|device heaps -#define THREADACQUIRE //should be better controlled +#define THREADACQUIRE //should be better behaved, with no extra locks needed. @@ -48,6 +47,7 @@ VKFunc(GetPhysicalDeviceSurfacePresentModesKHR) \ VKFunc(GetPhysicalDeviceSurfaceCapabilitiesKHR) \ VKFunc(GetPhysicalDeviceMemoryProperties) \ + VKFunc(GetPhysicalDeviceFormatProperties) \ VKFunc(DestroySurfaceKHR) \ VKFunc(CreateDevice) \ VKFunc(DestroyInstance) \ @@ -257,10 +257,9 @@ extern struct vulkaninfo_s size_t align; VkBuffer stagingbuf; VkDeviceMemory stagingmemory; -#ifdef USE_DYNAMIC_STAGING VkBuffer devicebuf; VkDeviceMemory devicememory; -#endif + VkBuffer renderbuf; //either staging or device. void *ptr; struct dynbuffer *next; @@ -337,11 +336,7 @@ void VK_Shutdown(void); void VKBE_Init(void); void VKBE_InitFramePools(struct vkframe *frame); void VKBE_RestartFrame(void); -#ifdef USE_DYNAMIC_STAGING -void VKBE_FlushDynamicBuffers(VkCommandBuffer buf); -#else void VKBE_FlushDynamicBuffers(void); -#endif void VKBE_Set2D(qboolean twodee); void VKBE_ShutdownFramePools(struct vkframe *frame); void VKBE_Shutdown(void); diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index f9506270..399abe4a 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -305,7 +305,7 @@ void INS_Accumulate(void) void INS_Commands (void) { } -void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, int *qdevid)) +void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid)) { }