int CStudioModelRenderer::StudioDrawModel(int flags) { m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); IEngineStudio.GetTimes(&m_nFrameCount, &m_clTime, &m_clOldTime); IEngineStudio.GetViewInfo(m_vRenderOrigin, m_vUp, m_vRight, m_vNormal); IEngineStudio.GetAliasScale(&m_fSoftwareXScale, &m_fSoftwareYScale); if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) { entity_state_t deadplayer; int result; int save_interp; if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients()) return 0; deadplayer = *(IEngineStudio.GetPlayerState(m_pCurrentEntity->curstate.renderamt - 1)); deadplayer.number = m_pCurrentEntity->curstate.renderamt; deadplayer.weaponmodel = 0; deadplayer.gaitsequence = 0; deadplayer.movetype = MOVETYPE_NONE; VectorCopy(m_pCurrentEntity->curstate.angles, deadplayer.angles); VectorCopy(m_pCurrentEntity->curstate.origin, deadplayer.origin); save_interp = m_fDoInterp; m_fDoInterp = 0; result = StudioDrawPlayer(flags, &deadplayer); m_fDoInterp = save_interp; return result; } m_pRenderModel = m_pCurrentEntity->model; m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata(m_pRenderModel); IEngineStudio.StudioSetHeader(m_pStudioHeader); IEngineStudio.SetRenderModel(m_pRenderModel); StudioSetUpTransform(0); if(m_pCurrentEntity == gEngfuncs.GetViewModel() && (gHUD.cl_righthand->value)) { (*m_protationmatrix)[0][1] *= -1; (*m_protationmatrix)[1][1] *= -1; (*m_protationmatrix)[2][1] *= -1; //IEngineStudio.StudioSetCullState(true); } if (flags & STUDIO_RENDER) { if (!IEngineStudio.StudioCheckBBox()) return 0; (*m_pModelsDrawn)++; (*m_pStudioModelCount)++; if (m_pStudioHeader->numbodyparts == 0) return 1; } if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) StudioMergeBones(m_pRenderModel); else StudioSetupBones(); StudioSaveBones(); if (flags & STUDIO_EVENTS) { StudioCalcAttachments(); IEngineStudio.StudioClientEvents(); if (m_pCurrentEntity->index > 0) { cl_entity_t *ent = gEngfuncs.GetEntityByIndex(m_pCurrentEntity->index); memcpy(ent->attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * 4); } } if (flags & STUDIO_RENDER) { alight_t lighting; vec3_t dir; lighting.plightvec = dir; IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting); IEngineStudio.StudioEntityLight(&lighting); IEngineStudio.StudioSetupLighting(&lighting); m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; IEngineStudio.StudioSetRemapColors(m_nTopColor, m_nBottomColor); StudioRenderModel(dir); }
void CStudioModelRenderer::StudioSetupBones(void) { int i; double f; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; static float pos[MAXSTUDIOBONES][3]; static vec4_t q[MAXSTUDIOBONES]; float bonematrix[3][4]; static float pos2[MAXSTUDIOBONES][3]; static vec4_t q2[MAXSTUDIOBONES]; static float pos3[MAXSTUDIOBONES][3]; static vec4_t q3[MAXSTUDIOBONES]; static float pos4[MAXSTUDIOBONES][3]; static vec4_t q4[MAXSTUDIOBONES]; if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) m_pCurrentEntity->curstate.sequence = 0; pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; f = StudioEstimateFrame(pseqdesc); panim = StudioGetAnim(m_pRenderModel, pseqdesc); StudioCalcRotations(pos, q, pseqdesc, panim, f); if (pseqdesc->numblends > 1) { float s; float dadt; panim += m_pStudioHeader->numbones; StudioCalcRotations(pos2, q2, pseqdesc, panim, f); dadt = StudioEstimateInterpolant(); s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; StudioSlerpBones(q, pos, q2, pos2, s); if (pseqdesc->numblends == 4) { panim += m_pStudioHeader->numbones; StudioCalcRotations(pos3, q3, pseqdesc, panim, f); panim += m_pStudioHeader->numbones; StudioCalcRotations(pos4, q4, pseqdesc, panim, f); s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; StudioSlerpBones(q3, pos3, q4, pos4, s); s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; StudioSlerpBones(q, pos, q3, pos3, s); } } if (m_fDoInterp && m_pCurrentEntity->latched.sequencetime && (m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime) && (m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq)) { static float pos1b[MAXSTUDIOBONES][3]; static vec4_t q1b[MAXSTUDIOBONES]; float s; pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; panim = StudioGetAnim(m_pRenderModel, pseqdesc); StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); if (pseqdesc->numblends > 1) { panim += m_pStudioHeader->numbones; StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; StudioSlerpBones(q1b, pos1b, q2, pos2, s); if (pseqdesc->numblends == 4) { panim += m_pStudioHeader->numbones; StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); panim += m_pStudioHeader->numbones; StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe); s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; StudioSlerpBones(q3, pos3, q4, pos4, s); s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; StudioSlerpBones(q1b, pos1b, q3, pos3, s); } } s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; StudioSlerpBones(q, pos, q1b, pos1b, s); } else { m_pCurrentEntity->latched.prevframe = f; } pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) { pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; panim = StudioGetAnim(m_pRenderModel, pseqdesc); StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe); for (i = 0; i < m_pStudioHeader->numbones; i++) { if (strcmp(pbones[i].name, "Bip01 Spine") == 0) break; memcpy(pos[i], pos2[i], sizeof( pos[i])); memcpy(q[i], q2[i], sizeof( q[i])); } } for (i = 0; i < m_pStudioHeader->numbones; i++) { QuaternionMatrix(q[i], bonematrix); bonematrix[0][3] = pos[i][0]; bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; if (pbones[i].parent == -1) { if (IEngineStudio.IsHardware()) { ConcatTransforms((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); MatrixCopy((*m_pbonetransform)[i], (*m_plighttransform)[i]); } else { ConcatTransforms((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); } StudioFxTransform(m_pCurrentEntity, (*m_pbonetransform)[i]); } else { ConcatTransforms((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); } } }
void CStudioModelRenderer::StudioMergeBones(model_t *m_pSubModel) { int i, j; double f; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; static float pos[MAXSTUDIOBONES][3]; float bonematrix[3][4]; static vec4_t q[MAXSTUDIOBONES]; if( !m_pStudioHeader || !m_pCurrentEntity ) return; if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) m_pCurrentEntity->curstate.sequence = 0; pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; f = StudioEstimateFrame(pseqdesc); /*if (m_pCurrentEntity->latched.prevframe > f) { }*/ panim = StudioGetAnim(m_pSubModel, pseqdesc); StudioCalcRotations(pos, q, pseqdesc, panim, f); pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); for (i = 0; i < m_pStudioHeader->numbones; i++) { for (j = 0; j < m_nCachedBones; j++) { if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) { MatrixCopy(m_rgCachedBoneTransform[j], (*m_pbonetransform)[i]); MatrixCopy(m_rgCachedLightTransform[j], (*m_plighttransform)[i]); break; } } if (j >= m_nCachedBones) { QuaternionMatrix(q[i], bonematrix); bonematrix[0][3] = pos[i][0]; bonematrix[1][3] = pos[i][1]; bonematrix[2][3] = pos[i][2]; if (pbones[i].parent == -1) { if (IEngineStudio.IsHardware()) { ConcatTransforms((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); MatrixCopy((*m_pbonetransform)[i], (*m_plighttransform)[i]); } else { ConcatTransforms((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); } StudioFxTransform(m_pCurrentEntity, (*m_pbonetransform)[i]); } else { ConcatTransforms((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); ConcatTransforms((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); } } } }
void CStudioModelRenderer::StudioSetUpTransform(int trivial_accept) { int i; vec3_t angles; vec3_t modelpos; VectorCopy(m_pCurrentEntity->origin, modelpos); angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL]; angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) { float f = 0; float d; if ((m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f) && (m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime)) f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); if (m_fDoInterp) f = f - 1.0; else f = 0; for (i = 0; i < 3; i++) modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; for (i = 0; i < 3; i++) { float ang1, ang2; ang1 = m_pCurrentEntity->angles[i]; ang2 = m_pCurrentEntity->latched.prevangles[i]; d = ang1 - ang2; if (d > 180) d -= 360; else if (d < -180) d += 360; angles[i] += d * f; } } else if (m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE) { VectorCopy(m_pCurrentEntity->angles, angles); } angles[PITCH] = -angles[PITCH]; AngleMatrix(angles, (*m_protationmatrix)); if (!IEngineStudio.IsHardware()) { static float viewmatrix[3][4]; VectorCopy(m_vRight, viewmatrix[0]); VectorCopy(m_vUp, viewmatrix[1]); VectorInverse(viewmatrix[1]); VectorCopy(m_vNormal, viewmatrix[2]); (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; ConcatTransforms(viewmatrix, (*m_protationmatrix), (*m_paliastransform)); if (trivial_accept) { for (i = 0; i < 4; i++) { (*m_paliastransform)[0][i] *= m_fSoftwareXScale * (1.0 / (ZISCALE * 0x10000)); (*m_paliastransform)[1][i] *= m_fSoftwareYScale * (1.0 / (ZISCALE * 0x10000)); (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); } } } (*m_protationmatrix)[0][3] = modelpos[0]; (*m_protationmatrix)[1][3] = modelpos[1]; (*m_protationmatrix)[2][3] = modelpos[2]; }
void AvHSpriteDraw(int spriteHandle, int frame, float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2) { gEngfuncs.pTriAPI->RenderMode(gRenderMode); gEngfuncs.pTriAPI->CullFace(TRI_NONE); struct model_s* spritePtr = (struct model_s*)(gEngfuncs.GetSpritePointer(spriteHandle)); ASSERT(spritePtr); if (!gEngfuncs.pTriAPI->SpriteTexture(spritePtr, frame)) { return; } Vertex vertex[8]; vertex[0].x = x1; vertex[0].y = y1; vertex[0].u = u1; vertex[0].v = v1; vertex[1].x = x2; vertex[1].y = y1; vertex[1].u = u2; vertex[1].v = v1; vertex[2].x = x2; vertex[2].y = y2; vertex[2].u = u2; vertex[2].v = v2; vertex[3].x = x1; vertex[3].y = y2; vertex[3].u = u1; vertex[3].v = v2; int numVertices = 4; float pw = SPR_Width(spriteHandle, frame); float ph = SPR_Height(spriteHandle, frame); float uOffset = 0; float vOffset = 0; if (IEngineStudio.IsHardware() == 2) { // Direct3D addresses textures differently than OpenGL so compensate // for that here. uOffset = 0.5 / pw; vOffset = 0.5 / ph; } // Apply the transformation to the vertices. for (int i = 0; i < numVertices; ++i) { if (vertex[i].u < 0.25 / pw) { vertex[i].u = 0.25 / pw; } if (vertex[i].v < 0.25 / ph) { vertex[i].v = 0.25 / ph; } if (vertex[i].u > 1 - 0.25 / pw) { vertex[i].u = 1 - 0.25 / pw; } if (vertex[i].v > 1 - 0.25 / ph) { vertex[i].v = 1 - 0.25 / ph; } vertex[i].u += uOffset; vertex[i].v += vOffset; float x = vertex[i].x; float y = vertex[i].y; vertex[i].x = x * gTransform[0][0] + y * gTransform[0][1] + gTransform[0][2]; vertex[i].y = x * gTransform[1][0] + y * gTransform[1][1] + gTransform[1][2]; } if (gClippingEnabled) { // Clip the polygon to each side of the clipping rectangle. This isn't the // fastest way to clip a polygon against a rectangle, but it's probably the // simplest. ClipPolygon(vertex, numVertices, 1, 0, -gClipRectX1); ClipPolygon(vertex, numVertices, -1, 0, gClipRectX2); ClipPolygon(vertex, numVertices, 0, 1, -gClipRectY1); ClipPolygon(vertex, numVertices, 0, -1, gClipRectY2); } // Compensate for the overbrightening effect. float gammaScale = 1.0f / gHUD.GetGammaSlope(); gEngfuncs.pTriAPI->Color4f(gammaScale * gColor[0], gammaScale * gColor[1], gammaScale * gColor[2], gColor[3]); // Output the vertices. if (gDrawMode == kSpriteDrawModeFilled) { gEngfuncs.pTriAPI->Begin(TRI_TRIANGLE_FAN); for (int j = 0; j < numVertices; ++j) { Vector worldPoint; if (gVGUIEnabled) { worldPoint.x = (vertex[j].x - gVGUIOffsetX) * gViewportXScale + gViewportXOffset; worldPoint.y = (vertex[j].y - gVGUIOffsetY) * gViewportYScale + gViewportYOffset; worldPoint.z = 1; } else { worldPoint = gViewOrigin + gViewXAxis * vertex[j].x + gViewYAxis * vertex[j].y + gViewZAxis * (gDepth + gDepthOffset); } gEngfuncs.pTriAPI->TexCoord2f(vertex[j].u, vertex[j].v); gEngfuncs.pTriAPI->Vertex3fv((float*)&worldPoint); } gEngfuncs.pTriAPI->End(); } else if (gDrawMode == kSpriteDrawModeBorder) { gEngfuncs.pTriAPI->Begin(TRI_LINES); for (int j = 0; j < numVertices; ++j) { int k = (j + 1) % numVertices; Vector worldPoint1; Vector worldPoint2; if (gVGUIEnabled) { worldPoint1.x = vertex[j].x - gVGUIOffsetX; worldPoint1.y = vertex[j].y - gVGUIOffsetY; worldPoint1.z = 1; worldPoint2.x = vertex[k].x - gVGUIOffsetX; worldPoint2.y = vertex[k].y - gVGUIOffsetY; worldPoint2.z = 1; } else { worldPoint1 = gViewOrigin + gViewXAxis * vertex[j].x + gViewYAxis * vertex[j].y + gViewZAxis * (gDepth + gDepthOffset); worldPoint2 = gViewOrigin + gViewXAxis * vertex[k].x + gViewYAxis * vertex[k].y + gViewZAxis * (gDepth + gDepthOffset); } gEngfuncs.pTriAPI->TexCoord2f(vertex[j].u, vertex[j].v); gEngfuncs.pTriAPI->Vertex3fv((float*)&worldPoint1); gEngfuncs.pTriAPI->TexCoord2f(vertex[k].u, vertex[k].v); gEngfuncs.pTriAPI->Vertex3fv((float*)&worldPoint2); } gEngfuncs.pTriAPI->End(); } gDepth += kDepthIncrement; }
/* ================== V_CalcSpectatorRefdef ================== */ void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) { static vec3_t velocity ( 0.0f, 0.0f, 0.0f); static int lastWeaponModelIndex = 0; static int lastViewModelIndex = 0; cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); pparams->onlyClientDraw = false; // refresh position VectorCopy ( pparams->simorg, v_sim_org ); // get old values VectorCopy ( pparams->cl_viewangles, v_cl_angles ); VectorCopy ( pparams->viewangles, v_angles ); VectorCopy ( pparams->vieworg, v_origin ); if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent ) { // calculate player velocity float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; if ( timeDiff > 0 ) { vec3_t distance; VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); VectorScale(distance, 1/timeDiff, distance ); velocity[0] = velocity[0]*0.9f + distance[0]*0.1f; velocity[1] = velocity[1]*0.9f + distance[1]*0.1f; velocity[2] = velocity[2]*0.9f + distance[2]*0.1f; VectorCopy(velocity, pparams->simvel); } // predict missing client data and set weapon model ( in HLTV mode or inset in eye mode ) // if ( gEngfuncs.IsSpectateOnly() ) // { V_GetInEyePos( g_iUser2, pparams->simorg, pparams->cl_viewangles ); pparams->health = 1.0; g_flHealth = MAX_HEALTH; cl_entity_t * gunModel = gEngfuncs.GetViewModel(); if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) { // weapon model changed lastWeaponModelIndex = ent->curstate.weaponmodel; lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); if ( lastViewModelIndex ) { gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation } else { // model not found gunModel->model = NULL; // disable weapon model lastWeaponModelIndex = lastViewModelIndex = 0; } } if ( lastViewModelIndex ) { gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); gunModel->curstate.modelindex = lastViewModelIndex; gunModel->curstate.frame = 0; gunModel->curstate.colormap = 0; gunModel->index = g_iUser2; } else { gunModel->model = NULL; // disable weaopn model } // } // else // {9 // only get viewangles from entity VectorCopy ( ent->angles, pparams->cl_viewangles ); gEngfuncs.SetViewAngles( ent->angles ); pparams->cl_viewangles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() // } } v_frametime = pparams->frametime; if ( pparams->nextView == 0 ) { // first renderer cycle, full screen switch ( g_iUser1 ) { case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); break; case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); break; case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); VectorCopy (v_sim_org, v_origin); break; case OBS_IN_EYE : V_CalcNormalRefdef ( pparams ); break; case OBS_MAP_FREE : pparams->onlyClientDraw = true; V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); break; case OBS_MAP_CHASE : pparams->onlyClientDraw = true; V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); break; } if ( gHUD.m_Spectator.m_pip->value ) pparams->nextView = 1; // force a second renderer view gHUD.m_Spectator.m_iDrawCycle = 0; } else { // second renderer cycle, inset window // set inset parameters pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); pparams->nextView = 0; // on further view // override some settings in certain modes switch ( (int)gHUD.m_Spectator.m_pip->value ) { case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); break; case INSET_IN_EYE : V_CalcNormalRefdef ( pparams ); break; case INSET_MAP_FREE : pparams->onlyClientDraw = true; V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); break; case INSET_MAP_CHASE : pparams->onlyClientDraw = true; if ( g_iUser1 == OBS_ROAMING ) V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); else V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); break; } gHUD.m_Spectator.m_iDrawCycle = 1; } // write back new values into pparams VectorCopy ( v_cl_angles, pparams->cl_viewangles ); VectorCopy ( v_angles, pparams->viewangles ) VectorCopy ( v_origin, pparams->vieworg ); }
int V_FindViewModelByWeaponModel(int weaponindex) { //TODO: this shouldn't be hardcoded. - Solokiller static const char* const modelmap[][2] = { # ifdef _TFC // TFC models override HL models { "models/p_mini.mdl", "models/v_tfac.mdl" }, { "models/p_sniper.mdl", "models/v_tfc_sniper.mdl" }, { "models/p_umbrella.mdl", "models/v_umbrella.mdl" }, { "models/p_crowbar.mdl", "models/v_tfc_crowbar.mdl" }, { "models/p_spanner.mdl", "models/v_tfc_spanner.mdl" }, { "models/p_knife.mdl", "models/v_tfc_knife.mdl" }, { "models/p_medkit.mdl", "models/v_tfc_medkit.mdl" }, { "models/p_egon.mdl", "models/v_flame.mdl" }, { "models/p_glauncher.mdl", "models/v_tfgl.mdl" }, { "models/p_rpg.mdl", "models/v_tfc_rpg.mdl" }, { "models/p_nailgun.mdl", "models/v_tfc_nailgun.mdl" }, { "models/p_snailgun.mdl", "models/v_tfc_supernailgun.mdl" }, { "models/p_9mmhandgun.mdl", "models/v_tfc_railgun.mdl" }, { "models/p_srpg.mdl", "models/v_tfc_rpg.mdl" }, { "models/p_smallshotgun.mdl", "models/v_tfc_12gauge.mdl" }, { "models/p_shotgun.mdl", "models/v_tfc_shotgun.mdl" }, { "models/p_spygun.mdl", "models/v_tfc_pistol.mdl" }, #endif { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, { "models/p_egon.mdl", "models/v_egon.mdl" }, { "models/p_gauss.mdl", "models/v_gauss.mdl" }, { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, { "models/p_grenade.mdl", "models/v_grenade.mdl" }, { "models/p_hgun.mdl", "models/v_hgun.mdl" }, { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, { "models/p_357.mdl", "models/v_357.mdl" }, { "models/p_rpg.mdl", "models/v_rpg.mdl" }, { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, { "models/p_squeak.mdl", "models/v_squeak.mdl" }, { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl"}, { "models/p_satchel.mdl", "models/v_satchel.mdl" }, #if USE_OPFOR { "models/p_pipe_wrench.mdl", "models/v_pipe_wrench.mdl" }, { "models/p_m40a1.mdl", "models/v_m40a1.mdl" }, #endif { nullptr, nullptr } }; model_t * weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); if ( weaponModel ) { int len = strlen( weaponModel->name ); int i = 0; while ( modelmap[i] != NULL ) { if ( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) { return gEngfuncs.pEventAPI->EV_FindModelIndex( modelmap[i][1] ); } i++; } return 0; } else return 0; }
/* ================== V_CalcSpectatorRefdef ================== */ void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) { vec3_t angles; static viewinterp_t ViewInterp; static float bob = 0.0f; static vec3_t velocity ( 0.0f, 0.0f, 0.0f); static int lastWeaponModelIndex = 0; static int lastViewModelIndex = 0; cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); cl_entity_t * gunModel = gEngfuncs.GetViewModel(); static float lasttime; static float lastang[3]; static float lastorg[3]; vec3_t delta; pparams->onlyClientDraw = false; // refresh position VectorCopy ( pparams->simorg, v_sim_org ); // get old values VectorCopy ( pparams->cl_viewangles, v_cl_angles ); VectorCopy ( pparams->viewangles, v_angles ); VectorCopy ( pparams->vieworg, v_origin ); v_frametime = pparams->frametime; if ( pparams->nextView == 0 ) { // first renderer cycle, full screen switch ( g_iUser1 ) { case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); break; case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); break; case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); VectorCopy (v_sim_org, v_origin); break; case OBS_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); break; case OBS_MAP_FREE : pparams->onlyClientDraw = true; V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); break; case OBS_MAP_CHASE : pparams->onlyClientDraw = true; V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); break; } if ( gHUD.m_Spectator.m_pip->value ) pparams->nextView = 1; // force a second renderer view gHUD.m_Spectator.m_iDrawCycle = 0; } else { // second renderer cycle, inset window // set inset parameters pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); pparams->nextView = 0; // on further view pparams->onlyClientDraw = false; // override some settings in certain modes switch ( (int)gHUD.m_Spectator.m_pip->value ) { case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); break; case INSET_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); break; case INSET_MAP_FREE : pparams->onlyClientDraw = true; V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); break; case INSET_MAP_CHASE : pparams->onlyClientDraw = true; if ( g_iUser1 == OBS_ROAMING ) V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); else V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); break; } gHUD.m_Spectator.m_iDrawCycle = 1; } // do the smoothing only once per frame, not in roaming or map mode if ( (gHUD.m_Spectator.m_iDrawCycle == 0) && (g_iUser1 == OBS_IN_EYE) ) { // smooth angles VectorSubtract( v_angles, lastang, delta ); if ( Length( delta ) != 0.0f ) { VectorCopy( v_angles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; ViewInterp.CurrentAngle++; VectorCopy( v_angles, lastang ); } if ( cl_vsmoothing && cl_vsmoothing->value ) { int foundidx; int i; float t; t = pparams->time - cl_vsmoothing->value; for ( i = 1; i < ORIGIN_MASK; i++ ) { foundidx = ViewInterp.CurrentAngle - 1 - i; if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) break; } if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) { // Interpolate double dt; float da; vec3_t v1,v2; AngleVectors( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], v1, NULL, NULL ); AngleVectors( ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v2, NULL, NULL ); da = AngleBetweenVectors( v1, v2 ); dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; if ( dt > 0.0 && ( da < 22.5f) ) { double frac; frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; frac = min( 1.0, frac ); // interpolate angles InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v_angles, frac ); } } } // smooth origin VectorSubtract( v_origin, lastorg, delta ); if ( Length( delta ) != 0.0 ) { VectorCopy( v_origin, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; ViewInterp.CurrentOrigin++; VectorCopy( v_origin, lastorg ); } // don't smooth in roaming (already smoothd), if ( cl_vsmoothing && cl_vsmoothing->value ) { int foundidx; int i; float t; t = pparams->time - cl_vsmoothing->value; for ( i = 1; i < ORIGIN_MASK; i++ ) { foundidx = ViewInterp.CurrentOrigin - 1 - i; if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) break; } if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) { // Interpolate vec3_t delta; double frac; double dt; vec3_t neworg; dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; if ( dt > 0.0 ) { frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; frac = min( 1.0, frac ); VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); // Dont interpolate large changes if ( Length( delta ) < 64 ) { VectorCopy( neworg, v_origin ); } } } } } // Hack in weapon model: if ( (g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE) && ent && g_iUser2 ) { // get position for weapon model VectorCopy( v_origin, gunModel->origin); VectorCopy( v_angles, gunModel->angles); // add idle tremble gunModel->angles[PITCH]*=-1; // calculate player velocity float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; if ( timeDiff > 0 ) { vec3_t distance; VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); VectorScale(distance, 1/timeDiff, distance ); velocity[0] = velocity[0]*0.66f + distance[0]*0.33f; velocity[1] = velocity[1]*0.66f + distance[1]*0.33f; velocity[2] = velocity[2]*0.66f + distance[2]*0.33f; VectorCopy(velocity, pparams->simvel); pparams->onground = 1; bob = V_CalcBob( pparams ); } vec3_t forward; AngleVectors(v_angles, forward, NULL, NULL ); for ( int i = 0; i < 3; i++ ) { gunModel->origin[ i ] += bob * 0.4 * forward[ i ]; } // throw in a little tilt. gunModel->angles[YAW] -= bob * 0.5; gunModel->angles[ROLL] -= bob * 1; gunModel->angles[PITCH] -= bob * 0.3; VectorCopy( gunModel->angles, gunModel->curstate.angles ); VectorCopy( gunModel->angles, gunModel->latched.prevangles ); if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) { // weapon model changed lastWeaponModelIndex = ent->curstate.weaponmodel; lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); if ( lastViewModelIndex ) { gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation } else { // model not found gunModel->model = NULL; // disable weaopn model lastWeaponModelIndex = lastViewModelIndex = 0; } } if ( lastViewModelIndex ) { gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); gunModel->curstate.modelindex = lastViewModelIndex; gunModel->curstate.frame = 0; gunModel->curstate.colormap = 0; gunModel->index = g_iUser2; } else { gunModel->model = NULL; // disable weaopn model } } else { gunModel->model = NULL; // disable weaopn model lastWeaponModelIndex = lastViewModelIndex = 0; } lasttime = pparams->time; // write back new values into pparams VectorCopy ( v_angles, pparams->viewangles ) VectorCopy ( v_origin, pparams->vieworg ); }