diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 3b97c666..fe9407c7 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -4662,30 +4662,34 @@ void CL_LinkViewModel(void) if (!CLHL_AnimateViewEntity(&ent)) #endif { - ent.framestate.g[FS_REG].frame[0] = pv->stats[STAT_WEAPONFRAME]; - ent.framestate.g[FS_REG].frame[1] = pv->oldframe; - - if (ent.framestate.g[FS_REG].frame[0] != pv->prevframe) + //if the model changed, reset everything. + if (ent.model != pv->vm.oldmodel) { - pv->oldframe = ent.framestate.g[FS_REG].frame[1] = pv->prevframe; - - pv->frameduration = (realtime - pv->lerptime); - if (pv->frameduration < 0.01)//no faster than 100 times a second... to avoid divide by zero - pv->frameduration = 0.01; - if (pv->frameduration > 0.2) //no slower than 5 times a second - pv->frameduration = 0.2; - pv->lerptime = realtime; + pv->vm.oldmodel = ent.model; + pv->vm.oldframe = pv->vm.prevframe = pv->stats[STAT_WEAPONFRAME]; + pv->vm.oldlerptime = pv->vm.lerptime = realtime; + pv->vm.frameduration = 0.1; } - pv->prevframe = ent.framestate.g[FS_REG].frame[0]; - - if (ent.model != pv->oldmodel) + //if the frame changed, update the oldframe to lerp into the new frame + else if (pv->stats[STAT_WEAPONFRAME] != pv->vm.prevframe) { - pv->oldmodel = ent.model; - pv->oldframe = ent.framestate.g[FS_REG].frame[1] = ent.framestate.g[FS_REG].frame[0]; - pv->frameduration = 0.1; - pv->lerptime = realtime; + pv->vm.oldframe = pv->vm.prevframe; + pv->vm.prevframe = pv->stats[STAT_WEAPONFRAME]; + pv->vm.oldlerptime = pv->vm.lerptime; + + pv->vm.frameduration = (realtime - pv->vm.lerptime); + if (pv->vm.frameduration < 0.01)//no faster than 100 times a second... to avoid divide by zero + pv->vm.frameduration = 0.01; + if (pv->vm.frameduration > 0.2) //no slower than 5 times a second + pv->vm.frameduration = 0.2; + pv->vm.lerptime = realtime; } - ent.framestate.g[FS_REG].lerpfrac = 1-(realtime-pv->lerptime)/pv->frameduration; + //work out the blend fraction + ent.framestate.g[FS_REG].frame[0] = pv->vm.prevframe; + ent.framestate.g[FS_REG].frame[1] = pv->vm.oldframe; + ent.framestate.g[FS_REG].frametime[0] = realtime - pv->vm.lerptime; + ent.framestate.g[FS_REG].frametime[1] = realtime - pv->vm.oldlerptime; + ent.framestate.g[FS_REG].lerpfrac = 1-(realtime-pv->vm.lerptime)/pv->vm.frameduration; ent.framestate.g[FS_REG].lerpfrac = bound(0, ent.framestate.g[FS_REG].lerpfrac, 1); } diff --git a/engine/client/client.h b/engine/client/client.h index 73967d31..e6a37dc2 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -576,11 +576,15 @@ struct playerview_s vec3_t vw_axis[3]; //weapons should be positioned relative to this vec3_t vw_origin; //weapons should be positioned relative to this // entity_t viewent; // is this not utterly redundant yet? - struct model_s *oldmodel; - float lerptime; - float frameduration; - int prevframe; - int oldframe; + struct + { + struct model_s *oldmodel; + float lerptime; + float oldlerptime; + float frameduration; + int prevframe; + int oldframe; + } vm; }; // diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 11414061..250965e9 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -2137,7 +2137,7 @@ static void P_ExportAllEffects_f(void) Con_Printf("Written %s\n", effect); } -#if _DEBUG +#if 1//_DEBUG // R_BeamInfo_f - debug junk static void P_BeamInfo_f (void) { @@ -2694,10 +2694,10 @@ static qboolean PScript_InitParticles (void) Cmd_AddCommand("r_importeffectinfo", P_ImportEffectInfo_f); Cmd_AddCommand("r_exportalleffects", P_ExportAllEffects_f); -#if _DEBUG +//#if _DEBUG Cmd_AddCommand("r_partinfo", P_PartInfo_f); Cmd_AddCommand("r_beaminfo", P_BeamInfo_f); -#endif +//#endif pt_pointfile = P_AllocateParticleType("", "PT_POINTFILE"); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a0a83a1c..4f9188a4 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -1420,21 +1420,35 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) newr->renderer = NULL; rendererstring = COM_Parse(rendererstring); - for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + if (!*com_token) { - if (!rendererinfo[i]->description) - continue; //not valid in this build. :( - for (j = 4-1; j >= 0; j--) + for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) { - if (!rendererinfo[i]->name[j]) - continue; - if (!stricmp(rendererinfo[i]->name[j], com_token)) + if (rendererinfo[i]->name[0] && stricmp(rendererinfo[i]->name[0], "none")) { newr->renderer = rendererinfo[i]; break; } } } + else + { + for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + { + if (!rendererinfo[i]->description) + continue; //not valid in this build. :( + for (j = 4-1; j >= 0; j--) + { + if (!rendererinfo[i]->name[j]) + continue; + if (!stricmp(rendererinfo[i]->name[j], com_token)) + { + newr->renderer = rendererinfo[i]; + break; + } + } + } + } rendererstring = COM_Parse(rendererstring); if (*com_token) @@ -1488,48 +1502,22 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) return newr->renderer != NULL; } -void R_RestartRenderer_f (void) +void R_RestartRenderer (rendererstate_t *newr) { rendererstate_t oldr; - rendererstate_t newr; if (r_blockvidrestart) { Con_Printf("Ignoring vid_restart from config\n"); return; } - memset(&newr, 0, sizeof(newr)); - -TRACE(("dbg: R_RestartRenderer_f\n")); - - Cvar_ApplyLatches(CVAR_RENDERERLATCH); - if (!R_BuildRenderstate(&newr, vid_renderer.string)) - { - int i; - if (*vid_renderer.string) - Con_Printf("vid_renderer \"%s\" unsupported. Using default.\n", vid_renderer.string); - else - Con_DPrintf("vid_renderer unset. Using default.\n"); - - //gotta do this after main hunk is saved off. - for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) - { - if (rendererinfo[i]->name[0] && stricmp(rendererinfo[i]->name[0], "none")) - { - Cmd_ExecuteString(va("setrenderer %s\n", rendererinfo[i]->name[0]), RESTRICT_LOCAL); - break; - } - } - return; - } - M_Shutdown(false); Media_CaptureDemoEnd(); TRACE(("dbg: R_RestartRenderer_f renderer %i\n", newr.renderer)); memcpy(&oldr, ¤trendererstate, sizeof(rendererstate_t)); - if (!R_ApplyRenderer(&newr)) + if (!R_ApplyRenderer(newr)) { TRACE(("dbg: R_RestartRenderer_f failed\n")); if (R_ApplyRenderer(&oldr)) @@ -1541,36 +1529,36 @@ TRACE(("dbg: R_RestartRenderer_f\n")); { int i; qboolean failed = true; - rendererinfo_t *skip = newr.renderer; + rendererinfo_t *skip = newr->renderer; - if (newr.rate != 0) + if (newr->rate != 0) { Con_Printf(CON_NOTICE "Trying default refresh rate\n"); - newr.rate = 0; - failed = !R_ApplyRenderer(&newr); + newr->rate = 0; + failed = !R_ApplyRenderer(newr); } - if (failed && newr.width != DEFAULT_WIDTH && newr.height != DEFAULT_HEIGHT) + if (failed && newr->width != DEFAULT_WIDTH && newr->height != DEFAULT_HEIGHT) { Con_Printf(CON_NOTICE "Trying %i*%i\n", DEFAULT_WIDTH, DEFAULT_HEIGHT); - newr.width = DEFAULT_WIDTH; - newr.height = DEFAULT_HEIGHT; - failed = !R_ApplyRenderer(&newr); + newr->width = DEFAULT_WIDTH; + newr->height = DEFAULT_HEIGHT; + failed = !R_ApplyRenderer(newr); } for (i = 0; failed && i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) { - newr.renderer = rendererinfo[i]; - if (newr.renderer && newr.renderer != skip) + newr->renderer = rendererinfo[i]; + if (newr->renderer && newr->renderer != skip) { - Con_Printf(CON_NOTICE "Trying %s\n", newr.renderer->description); - failed = !R_ApplyRenderer(&newr); + Con_Printf(CON_NOTICE "Trying %s\n", newr->renderer->description); + failed = !R_ApplyRenderer(newr); } } //if we ended up resorting to our last choice (dedicated) then print some informative message about it //fixme: on unixy systems, we should make sure we're actually printing to something (ie: that we're not running via some x11 shortcut with our stdout redirected to /dev/nul - if (!failed && newr.renderer == &dedicatedrendererinfo) + if (!failed && newr->renderer == &dedicatedrendererinfo) { Con_Printf(CON_ERROR "Video mode switch failed. Console forced.\n\nPlease change the following vars to something useable, and then use the setrenderer command.\n"); Con_Printf("%s: %s\n", vid_width.name, vid_width.string); @@ -1593,6 +1581,23 @@ TRACE(("dbg: R_RestartRenderer_f\n")); M_Reinit(); } +void R_RestartRenderer_f (void) +{ + rendererstate_t newr; + + Cvar_ApplyLatches(CVAR_RENDERERLATCH); + if (!R_BuildRenderstate(&newr, vid_renderer.string)) + { + Con_Printf("vid_renderer \"%s\" unsupported. Using default.\n", vid_renderer.string); + + //gotta do this after main hunk is saved off. + Cmd_ExecuteString("setrenderer \"\"\n", RESTRICT_LOCAL); + return; + } + + R_RestartRenderer(&newr); +} + void R_SetRenderer_f (void) { int i; @@ -1621,10 +1626,11 @@ void R_SetRenderer_f (void) Cvar_Set(&vid_bpp, Cmd_Argv(2)); } - Cvar_Set(&vid_renderer, param); + if (newr.renderer->rtype != QR_HEADLESS) //don't save headless in the vid_renderer cvar via the setrenderer command. 'setrenderer headless;vid_restart' can then do what is most sane. + Cvar_Set(&vid_renderer, param); if (!r_blockvidrestart) - R_RestartRenderer_f(); + R_RestartRenderer(&newr); } diff --git a/engine/client/vid_headless.c b/engine/client/vid_headless.c index 397047ce..d27faf7f 100644 --- a/engine/client/vid_headless.c +++ b/engine/client/vid_headless.c @@ -75,6 +75,7 @@ static void Headless_R_PreNewMap (void) //tray icon crap, so the user can still restore the game. LRESULT CALLBACK HeadlessWndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) { + extern cvar_t vid_renderer; switch(msg) { case WM_USER: @@ -83,7 +84,10 @@ LRESULT CALLBACK HeadlessWndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lpara case WM_CONTEXTMENU: case WM_USER+0: case WM_RBUTTONUP: - Cbuf_AddText("vid_renderer \"\";vid_restart\n", RESTRICT_LOCAL); + if (!Q_strcasecmp(vid_renderer.string, "headless")) + Cbuf_AddText("vid_renderer \"\";vid_restart\n", RESTRICT_LOCAL); + else + Cbuf_AddText("vid_restart\n", RESTRICT_LOCAL); break; default: break; diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 8d904f52..bb5d462b 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1530,6 +1530,7 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL qglGetShaderParameteriv_(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); if(!compiled) { + char *typedesc; char str[8192]; qglGetShaderInfoLog_(shader, sizeof(str), NULL, str); @@ -1538,15 +1539,21 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL switch (shadertype) { case GL_FRAGMENT_SHADER_ARB: - Con_Printf("Fragment shader (%s) compilation error:\n----------\n%s----------\n", name, str); + typedesc = "Fragment"; break; case GL_VERTEX_SHADER_ARB: - Con_Printf("Vertex shader (%s) compilation error:\n----------\n%s----------\n", name, str); + typedesc = "Vertex"; break; default: - Con_Printf("Shader_CreateShader: This shouldn't happen ever\n"); + typedesc = "???"; break; } + Con_Printf("%s shader (%s) compilation error:\n----------\n%s----------\n", typedesc, name, str); + + //if there's no fixed function then failure to compile the default2d shader should be considered fatal. this should help avoid black screens on android. + if (gl_config.nofixedfunc && !strcmp(name, "default2d")) + Sys_Error("%s shader (%s) compilation error:\n----------\n%s----------\n", typedesc, name, str); + if (developer.ival) { qglGetShaderSource(shader, sizeof(str), NULL, str);