static bool R_UpdateShadowOrigin (entity_t *e) { vec3_t start, end; if (e->lighting == NULL) return false; if (e->lighting->state == LIGHTING_READY) return true; VectorCopy(e->origin, start); VectorCopy(e->origin, end); end[2] = start[2] - MESH_SHADOW_MAX_DISTANCE; /* do the trace */ R_Trace(start, end, 0.0, MASK_SOLID); /* resolve the shadow origin and direction */ if (refdef.trace.leafnum) { /* hit something */ VectorCopy(refdef.trace.endpos, e->lighting->shadowOrigin); e->lighting->state = LIGHTING_READY; return true; } return false; }
/* * Cl_LocationThere * * Returns the description of the location nearest the client's crosshair. */ const char *Cl_LocationThere(void) { vec3_t dest; // project vector from view position and angle VectorMA(r_view.origin, 8192.0, r_view.forward, dest); // and trace to world model R_Trace(r_view.origin, dest, 0, MASK_SHOT); return Cl_Location(r_view.trace.end); }
/** @todo bad implementation -- copying light pointers every frame is a very wrong idea * @brief Recalculate active lights list for the given entity; R_CalcTransform(ent) should be called before this * @note to accelerate math, the diagonal of aabb is used to approximate max distance from entity's origin to its most distant point * while this is a gross exaggeration for many models, the sole purpose of it is to be used for filtering out distant lights, * so nothing is broken by it. * @param[in] ent Entity to recalculate lights for * @sa R_AddLightToEntity */ void R_UpdateLightList (entity_t *ent) { int i; vec_t *pos; /**< Worldspace position for which lighting is calculated */ entity_t *rootEnt; /**< The root entitity of tagent tree, which holds the lighting data (af any) */ lighting_t *ltng; /**< Lighting data for the entity being processed */ vec3_t diametralVec; /** < conservative estimate of entity's bounding sphere diameter, in vector form */ float diameter; /** < value of this entity's diameter (approx) */ vec3_t fakeSunPos; /**< as if sun wasn't at infinite distance */ bool cached = false; /* Find the root of tagent tree which actually owns the lighting data; it is assumed that there is no loops, * since R_CalcTransform calls Com_Error on those */ for (rootEnt = ent; rootEnt->tagent; rootEnt = ent->tagent) ; ltng = ent->lighting = rootEnt->lighting; if (!ltng) { /* Entity got no lighting data, so substitute defaults (no dynamic lights, but exposed to sunlight) */ /** @todo Replace this hack with something more legit (hack can cause bizarre stencil shadows if enabled) */ OBJZERO(fakeLightingData); ent->lighting = &fakeLightingData; return; } if (ltng->lastLitFrame == r_locals.frame) return; /* nothing to do, already calculated lighting for this frame */ ltng->lastLitFrame = r_locals.frame; /* we have to use the offset from (accumulated) transform matrix, because entity origin is not necessarily the point where model is acually rendered */ pos = ent->transform.matrix + 12; /* type system hack, sorry */ VectorSubtract(ent->maxs, ent->mins, diametralVec); /** @todo what if origin is NOT inside aabb? then this estimate will not be conservative enough */ diameter = VectorLength(diametralVec); /** @todo clear caches when r_dynamic_lights cvar is changed OR always keep maximal # of static lights in the cache */ if (VectorDist(pos, ltng->lastCachePos) < CACHE_CLEAR_TRESHOLD) { cached = true; } else { ltng->numLights = 0; /* clear the list of lights */ ltng->numCachedLights = 0; VectorCopy(pos, ltng->lastCachePos); } /* Check if origin of this entity is hit by sunlight (not the best test, but at least fast) */ if (!cached) { if (ent->flags & RF_ACTOR) { /** @todo Hack to avoid dropships being shadowed by lightclips placed at them. Should be removed once correct global illumination model is done */ VectorMA(pos, 8192.0, refdef.sunVector, fakeSunPos); R_Trace(pos, fakeSunPos, 0, MASK_SOLID); ltng->inShadow = refdef.trace.fraction != 1.0; } else { ltng->inShadow = false; } } if (!r_dynamic_lights->integer) return; if (!cached) { /* Rebuild list of static lights */ for (i = 0; i < refdef.numStaticLights; i++) { light_t *light = &refdef.staticLights[i]; const float distSqr = VectorDistSqr(pos, light->origin); if (distSqr > (diameter + light->radius) * (diameter + light->radius)) continue; R_Trace(pos, light->origin, 0, MASK_SOLID); if (refdef.trace.fraction == 1.0) R_AddLightToEntity(pos, ltng, light, distSqr); } /* Save static lights to cache */ for (i = 0; i < ltng->numLights; i++) ltng->cachedLights[i] = ltng->lights[i]; ltng->numCachedLights = ltng->numLights; } else { /* Copy static lights from cache */ for (i = 0; i < ltng->numCachedLights; i++) ltng->lights[i] = ltng->cachedLights[i]; ltng->numLights = ltng->numCachedLights; } /* add dynamic lights, too */ for (i = 0; i < refdef.numDynamicLights; i++) { light_t *light = &refdef.dynamicLights[i]; const float distSqr = VectorDistSqr(pos, light->origin); if (distSqr > (diameter + light->radius) * (diameter + light->radius)) continue; R_Trace(pos, light->origin, 0, MASK_SOLID); if (refdef.trace.fraction == 1.0) R_AddLightToEntity(pos, ltng, light, distSqr); } }
/* ----------------------------------------------------------------------------- Function: Parameters: Returns: Notes: ----------------------------------------------------------------------------- */ PUBLIC void fire_lead( player_t *self ) { entity_t *closest; int damage; int dx, dy, dist; int d1, shot_dist, n; switch( self->weapon ) { case WEAPON_PISTOL: Sound_StartSound( NULL, 0, CHAN_WEAPON, Sound_RegisterSound( "sfx/012.wav" ), 1, ATTN_NORM, 0 ); break; case WEAPON_AUTO: Sound_StartSound( NULL, 0, CHAN_WEAPON, Sound_RegisterSound( "sfx/011.wav" ), 1, ATTN_NORM, 0 ); break; case WEAPON_CHAIN: Sound_StartSound( NULL, 0, CHAN_WEAPON, Sound_RegisterSound( "sfx/013.wav" ), 1, ATTN_NORM, 0 ); break; } self->madenoise = true; dist = 0x7fffffffl; closest = NULL; for( n = 0 ; n < NumGuards; ++n ) { if( Guards[ n ].flags & FL_SHOOTABLE ) // && Guards[n].flags&FL_VISABLE { shot_dist = Point2LineDist( Guards[ n ].x - self->position.origin[ 0 ], Guards[ n ].y - self->position.origin[ 1 ], self->position.angle ); if( shot_dist > (2 * TILEGLOBAL / 3) ) { continue; // miss } d1 = LineLen2Point( Guards[ n ].x - self->position.origin[ 0 ], Guards[ n ].y - self->position.origin[ 1 ], self->position.angle ); if( d1 < 0 || d1 > dist ) { continue; } if( ! Level_CheckLine( Guards[ n ].x, Guards[ n ].y, Player.position.origin[0], Player.position.origin[1], r_world ) ) { //if( ! CheckLine( &Guards[ n ] ) ) continue; // obscured } dist = d1; closest = &Guards[ n ]; } } if( ! closest ) // missed { r_trace_t trace; trace.a = NormalizeAngle( self->position.angle - DEG2FINE( 2 ) + rand() % (DEG2FINE( 4 ) ) ); trace.x = self->position.origin[ 0 ]; trace.y = self->position.origin[ 1 ]; trace.flags = TRACE_BULLET; trace.tile_vis = NULL; R_Trace( &trace, r_world ); if( trace.flags & TRACE_HIT_DOOR ) { Sound_StartSound( NULL, 0, CHAN_AUTO, Sound_RegisterSound( "lsfx/028.wav" ), 1, ATTN_NORM, 0 ); } return; } // hit something dx = ABS( closest->tilex - self->tilex ); dy = ABS( closest->tiley - self->tiley ); dist = max_of_2( dx, dy ); if( dist < 2 ) { damage = US_RndT() / 4; } else if( dist < 4 ) { damage = US_RndT() / 6; } else { if( US_RndT() / 12 < dist ) { return; // missed } damage = US_RndT() / 6; } A_DamageActor( closest, damage ); }
/** * @brief Flares are batched by their texture. Usually, this means one draw operation * for all flares in view. Flare visibility is calculated every few millis, and * flare alpha is ramped up or down depending on the results of the visibility * trace. Flares are also faded according to the angle of their surface to the * view origin. */ void R_DrawFlareSurfaces (const mBspSurfaces_t* surfs, glElementIndex_t* indexPtr) { const image_t* image; int i, j, k, l, m; vec3_t view, verts[4]; vec3_t right, up, upright, downright; float dot, dist, scale, alpha; bool visible; bool oldblend; if (!r_flares->integer) return; if (!surfs->count) return; oldblend = r_state.blend_enabled; R_EnableColorArray(true); R_ResetArrayState(); /** @todo better GL state handling */ glDisable(GL_DEPTH_TEST); R_EnableBlend(true); R_BlendFunc(GL_SRC_ALPHA, GL_ONE); image = r_flaretextures[0]; R_BindTexture(image->texnum); j = k = l = 0; for (i = 0; i < surfs->count; i++) { mBspSurface_t* surf = surfs->surfaces[i]; mBspFlare_t* f; if (surf->frame != r_locals.frame) continue; f = surf->flare; /* bind the flare's texture */ if (f->image != image) { R_DrawArrays(0, l / 3); j = k = l = 0; refdef.batchCount++; image = f->image; R_BindTexture(image->texnum); } /* periodically test visibility to ramp alpha */ if (refdef.time - f->time > 0.02) { if (refdef.time - f->time > 0.5) /* reset old flares */ f->alpha = 0; R_Trace(refdef.viewOrigin, f->origin, 0, MASK_SOLID); visible = refdef.trace.fraction == 1.0; f->alpha += (visible ? 0.03 : -0.15); /* ramp */ if (f->alpha > 0.75) /* clamp */ f->alpha = 0.75; else if (f->alpha < 0) f->alpha = 0.0; f->time = refdef.time; } VectorSubtract(f->origin, refdef.viewOrigin, view); dist = VectorNormalize(view); /* fade according to angle */ dot = DotProduct(surf->normal, view); if (dot > 0) continue; alpha = 0.1 + -dot * r_flares->value; if (alpha > 1.0) alpha = 1.0; alpha = f->alpha * alpha; /* scale according to distance */ scale = f->radius + (f->radius * dist * .0005); VectorScale(r_locals.right, scale, right); VectorScale(r_locals.up, scale, up); VectorAdd(up, right, upright); VectorSubtract(right, up, downright); VectorSubtract(f->origin, downright, verts[0]); VectorAdd(f->origin, upright, verts[1]); VectorAdd(f->origin, downright, verts[2]); VectorSubtract(f->origin, upright, verts[3]); for (m = 0; m < 4; m++) { /* duplicate color data to all 4 verts */ memcpy(&r_state.color_array[j], f->color, sizeof(vec3_t)); r_state.color_array[j + 3] = alpha; j += 4; } /* copy texcoord info */ memcpy(&texunit_diffuse.texcoord_array[k], default_texcoords, sizeof(vec2_t) * 4); k += sizeof(vec2_t) / sizeof(vec_t) * 4; /* and lastly copy the 4 verts */ memcpy(&r_state.vertex_array_3d[l], verts, sizeof(vec3_t) * 4); l += sizeof(vec3_t) / sizeof(vec_t) * 4; } R_DrawArrays(0, l / 3); refdef.batchCount++; R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_EnableBlend(oldblend); glEnable(GL_DEPTH_TEST); R_EnableColorArray(false); R_Color(nullptr); }