/* =============== V_ParseDamage =============== */ void V_ParseDamage (void) { int armor, blood; vec3_t from; //vec3_t forward, right; vec3_t localfrom; entity_t *ent; //float side; float count; armor = MSG_ReadByte(&cl_message); blood = MSG_ReadByte(&cl_message); MSG_ReadVector(&cl_message, from, cls.protocol); // Send the Dmg Globals to CSQC CL_VM_UpdateDmgGlobals(blood, armor, from); count = blood*0.5 + armor*0.5; if (count < 10) count = 10; cl.faceanimtime = cl.time + 0.2; // put sbar face into pain frame cl.cshifts[CSHIFT_DAMAGE].percent += 3*count; cl.cshifts[CSHIFT_DAMAGE].alphafade = 150; if (cl.cshifts[CSHIFT_DAMAGE].percent < 0) cl.cshifts[CSHIFT_DAMAGE].percent = 0; if (cl.cshifts[CSHIFT_DAMAGE].percent > 150) cl.cshifts[CSHIFT_DAMAGE].percent = 150; if (armor > blood) { cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; } else if (armor) { cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; } else { cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; } // calculate view angle kicks if (cl.entities[cl.viewentity].state_current.active) { ent = &cl.entities[cl.viewentity]; Matrix4x4_Transform(&ent->render.inversematrix, from, localfrom); VectorNormalize(localfrom); v_dmg_pitch = count * localfrom[0] * v_kickpitch.value; v_dmg_roll = count * localfrom[1] * v_kickroll.value; v_dmg_time = v_kicktime.value; } }
/** * @brief Adds new stains from the view each frame. */ void R_AddStains(void) { const r_stain_t *s = r_view.stains; for (int32_t i = 0; i < r_view.num_stains; i++, s++) { R_StainNode(s, r_model_state.world->bsp->nodes); for (uint16_t i = 0; i < cl.frame.num_entities; i++) { const uint32_t snum = (cl.frame.entity_state + i) & ENTITY_STATE_MASK; const entity_state_t *st = &cl.entity_states[snum]; if (st->solid != SOLID_BSP) { continue; } const cl_entity_t *ent = &cl.entities[st->number]; const cm_bsp_model_t *mod = cl.cm_models[st->model1]; if (mod == NULL || mod->head_node == -1) { continue; } r_bsp_node_t *node = &r_model_state.world->bsp->nodes[mod->head_node]; r_stain_t stain = *s; Matrix4x4_Transform(&ent->inverse_matrix, s->origin, stain.origin); R_StainNode(&stain, node); } } g_hash_table_foreach(r_surfs_stained, R_AddStains_UploadSurfaces, NULL); g_hash_table_remove_all(r_surfs_stained); }
/** * Transforms a point by the inverse of the world-model matrix for the * specified entity. */ void R_TransformForEntity (const entity_t* e, const vec3_t in, vec3_t out) { matrix4x4_t tmp, mat; Matrix4x4_CreateFromQuakeEntity(&tmp, e->origin[0], e->origin[1], e->origin[2], e->angles[0], e->angles[1], e->angles[2], e->getScaleX()); Matrix4x4_Invert_Simple(&mat, &tmp); Matrix4x4_Transform(&mat, in, out); }
/** * @brief Applies any configuration and tag alignment, populating the model-view * matrix for the entity in the process. */ void R_SetMatrixForEntity(r_entity_t *e) { if (e->parent) { vec3_t forward; if (!IS_MESH_MODEL(e->model)) { Com_Warn("Invalid model for linked entity\n"); return; } const r_entity_t *p = e->parent; while (p->parent) { p = p->parent; } AngleVectors(p->angles, forward, NULL, NULL); VectorClear(e->origin); VectorClear(e->angles); Matrix4x4_CreateFromEntity(&e->matrix, e->origin, e->angles, e->scale); R_ApplyMeshModelTag(e); R_ApplyMeshModelConfig(e); Matrix4x4_Invert_Simple(&e->inverse_matrix, &e->matrix); Matrix4x4_Transform(&e->matrix, vec3_origin, e->origin); Matrix4x4_Transform(&e->matrix, vec3_forward, forward); VectorAngles(forward, e->angles); return; } Matrix4x4_CreateFromEntity(&e->matrix, e->origin, e->angles, e->scale); if (IS_MESH_MODEL(e->model)) { R_ApplyMeshModelConfig(e); } Matrix4x4_Invert_Simple(&e->inverse_matrix, &e->matrix); }
/** * @brief */ void R_UseLight_default(const uint16_t light_index, const r_light_t *light) { r_default_program_t *p = &r_default_program; if (light && light->radius) { vec3_t origin; const matrix4x4_t *modelview = R_GetMatrixPtr(R_MATRIX_MODELVIEW); Matrix4x4_Transform(modelview, light->origin, origin); R_ProgramParameter3fv(&p->lights[light_index].origin, origin); R_ProgramParameter3fv(&p->lights[light_index].color, light->color); R_ProgramParameter1f(&p->lights[light_index].radius, light->radius); } else { R_ProgramParameter1f(&p->lights[light_index].radius, 0.0); } }
qboolean R_Shader_StartLightPass( unsigned int lightIndex ) { GLint valid; R_ShaderLight *light = GetLightFromIndex( lightIndex ); matrix4x4_t *worldToViewMatrix = &r_refdef.lightShader.worldToViewMatrix; vec3_t lightPosition, newcolor; float f; assert( light->active == true ); // setup cubemap texture generation if( gl_support_cubemaps ) { matrix4x4_t worldToLightMatrix; matrix4x4_t viewToWorldMatrix; matrix4x4_t viewToLightMatrix; // setup the cubemap qglSelectTextureARB( GL_TEXTURE1_ARB ); glEnable( GL_TEXTURE_CUBE_MAP_ARB ); glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, GL_LoadCubeTexImage( light->cubemapname, false, true ) ); qglSelectTextureARB( GL_TEXTURE0_ARB ); // invert worldToViewMatrix worldToLightMatrix = GetWorldToLightMatrix( light ); Matrix4x4_Invert_Simple( &viewToWorldMatrix, worldToViewMatrix ); Matrix4x4_Concat( &viewToLightMatrix, &worldToLightMatrix, &viewToWorldMatrix ); qglUniformMatrix4fvARB( r_refdef.lightShader.viewToLightMatrix, 1, true, (float *)&viewToLightMatrix.m ); } Matrix4x4_Transform( worldToViewMatrix, light->origin, lightPosition ); //Con_Printf( "Light distance to origin: %f (vs %f)\n", VectorDistance( light->origin, r_refdef.vieworg ), VectorLength( lightPosition ) ); qglUniform3fvARB( r_refdef.lightShader.lightPosition, 1, lightPosition ); f = (light->style >= 0 ? d_lightstylevalue[light->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value; VectorScale(light->color, f, newcolor); qglUniform3fvARB( r_refdef.lightShader.lightColor, 1, newcolor ); qglUniform1fARB( r_refdef.lightShader.lightMaxDistance, light->maxDistance ); qglValidateProgramARB( r_refdef.lightShader.programObject ); qglGetObjectParameterivARB( r_refdef.lightShader.programObject, GL_OBJECT_VALIDATE_STATUS_ARB, &valid ); return valid == true; }
float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent) #endif { float maxfrac, maxrealfrac; int n; entity_render_t *ent; float tracemins[3], tracemaxs[3]; trace_t trace; float tempnormal[3], starttransformed[3], endtransformed[3]; #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND vec3_t end; vec_t len = 0; if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) { // TRICK: make the trace 1 qu longer! VectorSubtract(pEnd, start, end); len = VectorNormalizeLength(end); VectorMA(pEnd, collision_endposnudge.value, end, end); } else VectorCopy(pEnd, end); #endif memset (&trace, 0 , sizeof(trace_t)); trace.fraction = 1; trace.realfraction = 1; VectorCopy (end, trace.endpos); if (hitent) *hitent = 0; if (cl.worldmodel && cl.worldmodel->TraceLine) cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, start, end, SUPERCONTENTS_SOLID); if (normal) VectorCopy(trace.plane.normal, normal); maxfrac = trace.fraction; maxrealfrac = trace.realfraction; tracemins[0] = min(start[0], end[0]); tracemaxs[0] = max(start[0], end[0]); tracemins[1] = min(start[1], end[1]); tracemaxs[1] = max(start[1], end[1]); tracemins[2] = min(start[2], end[2]); tracemaxs[2] = max(start[2], end[2]); // look for embedded bmodels for (n = 0;n < cl.num_entities;n++) { if (!cl.entities_active[n]) continue; ent = &cl.entities[n].render; if (!BoxesOverlap(ent->mins, ent->maxs, tracemins, tracemaxs)) continue; if (!ent->model || !ent->model->TraceLine) continue; if ((ent->flags & RENDER_EXTERIORMODEL) && !chase_active.integer) continue; // if transparent and not selectable, skip entity if (!(cl.entities[n].state_current.effects & EF_SELECTABLE) && (ent->alpha < 1 || (ent->effects & (EF_ADDITIVE | EF_NODEPTHTEST)))) continue; if (ent == ignoreent) continue; Matrix4x4_Transform(&ent->inversematrix, start, starttransformed); Matrix4x4_Transform(&ent->inversematrix, end, endtransformed); Collision_ClipTrace_Box(&trace, ent->model->normalmins, ent->model->normalmaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID, 0, NULL); #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) Collision_ShortenTrace(&trace, len / (len + collision_endposnudge.value), pEnd); #endif if (maxrealfrac < trace.realfraction) continue; ent->model->TraceLine(ent->model, ent->frameblend, ent->skeleton, &trace, starttransformed, endtransformed, SUPERCONTENTS_SOLID); if (maxrealfrac > trace.realfraction) { if (hitent) *hitent = n; maxfrac = trace.fraction; maxrealfrac = trace.realfraction; if (normal) { VectorCopy(trace.plane.normal, tempnormal); Matrix4x4_Transform3x3(&ent->matrix, tempnormal, normal); } } } maxfrac = bound(0, maxfrac, 1); maxrealfrac = bound(0, maxrealfrac, 1); //if (maxfrac < 0 || maxfrac > 1) Con_Printf("fraction out of bounds %f %s:%d\n", maxfrac, __FILE__, __LINE__); if (impact) VectorLerp(start, maxfrac, end, impact); return maxfrac; }
static void R_TrackSprite(const entity_render_t *ent, vec3_t origin, vec3_t left, vec3_t up, int *edge, float *dir_angle) { float distance; vec3_t bCoord; // body coordinates of object unsigned int i; // temporarily abuse bCoord as the vector player->sprite-origin VectorSubtract(origin, r_refdef.view.origin, bCoord); distance = VectorLength(bCoord); // Now get the bCoords :) Matrix4x4_Transform(&r_refdef.view.inverse_matrix, origin, bCoord); *edge = 0; // FIXME::should assume edge == 0, which is correct currently for(i = 0; i < 4; ++i) { if(PlaneDiff(origin, &r_refdef.view.frustum[i]) < -EPSILON) break; } // If it wasn't outside a plane, no tracking needed if(i < 4) { float x, y; // screen X and Y coordinates float ax, ay; // absolute coords, used for division // I divide x and y by the greater absolute value to get ranges -1.0 to +1.0 bCoord[2] *= r_refdef.view.frustum_x; bCoord[1] *= r_refdef.view.frustum_y; //Con_Printf("%f %f %f\n", bCoord[0], bCoord[1], bCoord[2]); ax = fabs(bCoord[1]); ay = fabs(bCoord[2]); // get the greater value and determine the screen edge it's on if(ax < ay) { ax = ay; // 180 or 0 degrees if(bCoord[2] < 0.0f) *edge = SIDE_BOTTOM; else *edge = SIDE_TOP; } else { if(bCoord[1] < 0.0f) *edge = SIDE_RIGHT; else *edge = SIDE_LEFT; } // umm... if(ax < MIN_EPSILON) // this was == 0.0f before --blub ax = MIN_EPSILON; // get the -1 to +1 range x = bCoord[1] / ax; y = bCoord[2] / ax; ax = (1.0f / VectorLength(left)); ay = (1.0f / VectorLength(up)); // Using the placement below the distance of a sprite is // real dist = sqrt(d*d + dfxa*dfxa + dgyb*dgyb) // d is the distance we use // f is frustum X // x is x // a is ax // g is frustum Y // y is y // b is ay // real dist (r) shall be d, so // r*r = d*d + dfxa*dfxa + dgyb*dgyb // r*r = d*d * (1 + fxa*fxa + gyb*gyb) // d*d = r*r / (1 + fxa*fxa + gyb*gyb) // d = sqrt(r*r / (1 + fxa*fxa + gyb*gyb)) // thus: distance = sqrt((distance*distance) / (1.0 + r_refdef.view.frustum_x*r_refdef.view.frustum_x * x*x * ax*ax + r_refdef.view.frustum_y*r_refdef.view.frustum_y * y*y * ay*ay)); // ^ the one we want ^ the one we have ^ our factors // Place the sprite a few units ahead of the player VectorCopy(r_refdef.view.origin, origin); VectorMA(origin, distance, r_refdef.view.forward, origin); // Move the sprite left / up the screeen height VectorMA(origin, distance * r_refdef.view.frustum_x * x * ax, left, origin); VectorMA(origin, distance * r_refdef.view.frustum_y * y * ay, up, origin); if(r_track_sprites_flags.integer & TSF_ROTATE_CONTINOUSLY) { // compute the rotation, negate y axis, we're pointing outwards *dir_angle = atan(-y / x) * 180.0f/M_PI; // we need the real, full angle if(x < 0.0f) *dir_angle += 180.0f; } left[0] *= r_track_sprites_scalew.value; left[1] *= r_track_sprites_scalew.value; left[2] *= r_track_sprites_scalew.value; up[0] *= r_track_sprites_scaleh.value; up[1] *= r_track_sprites_scaleh.value; up[2] *= r_track_sprites_scaleh.value; } }
static void R_RotateSprite(const mspriteframe_t *frame, vec3_t origin, vec3_t left, vec3_t up, int edge, float dir_angle) { if(!(r_track_sprites_flags.integer & TSF_ROTATE)) { // move down by its size if on top, otherwise it's invisible if(edge == SIDE_TOP) VectorMA(origin, -(fabs(frame->up)+fabs(frame->down)), up, origin); } else { static float rotation_angles[5] = { 0, // no edge -90.0f, //top 0.0f, // left 90.0f, // bottom 180.0f, // right }; // rotate around the hotspot according to which edge it's on // since the hotspot == the origin, only rotate the vectors matrix4x4_t rotm; vec3_t axis; vec3_t temp; vec2_t dir; float angle; if(edge < 1 || edge > 4) return; // this usually means something went wrong somewhere, there's no way to get a wrong edge value currently dir[0] = frame->right + frame->left; dir[1] = frame->down + frame->up; // only rotate when the hotspot isn't the center though. if(dir[0] < MIN_EPSILON && dir[1] < MIN_EPSILON) { return; } // Now that we've kicked center-hotspotted sprites, rotate using the appropriate matrix :) // determine the angle of a sprite, we could only do that once though and // add a `qboolean initialized' to the mspriteframe_t struct... let's get the direction vector of it :) angle = atan(dir[1] / dir[0]) * 180.0f/M_PI; // we need the real, full angle if(dir[0] < 0.0f) angle += 180.0f; // Rotate around rotation_angle - frame_angle // The axis SHOULD equal r_refdef.view.forward, but let's generalize this: CrossProduct(up, left, axis); if(r_track_sprites_flags.integer & TSF_ROTATE_CONTINOUSLY) Matrix4x4_CreateRotate(&rotm, dir_angle - angle, axis[0], axis[1], axis[2]); else Matrix4x4_CreateRotate(&rotm, rotation_angles[edge] - angle, axis[0], axis[1], axis[2]); Matrix4x4_Transform(&rotm, up, temp); VectorCopy(temp, up); Matrix4x4_Transform(&rotm, left, temp); VectorCopy(temp, left); } }