void R_DrawLightningBeams(void) { int i; beam_t *b; if (!cl_beams_polygons.integer) return; beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value; for (i = 0, b = cl.beams;i < cl.num_beams;i++, b++) { if (b->model && b->lightning) { vec3_t org, start, end, dir; vec_t dist; CL_Beam_CalculatePositions(b, start, end); // calculate the nearest point on the line (beam) for depth sorting VectorSubtract(end, start, dir); dist = (DotProduct(r_refdef.view.origin, dir) - DotProduct(start, dir)) / (DotProduct(end, dir) - DotProduct(start, dir)); dist = bound(0, dist, 1); VectorLerp(start, dist, end, org); // now we have the nearest point on the line, so sort with it R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, org, R_DrawLightningBeam_TransparentCallback, NULL, i, NULL); } } }
static void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { int surfacelistindex; float vertex3f[12*3]; float texcoord2f[12*2]; RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1, 12, vertex3f, texcoord2f, NULL, NULL, NULL, NULL, 6, r_lightningbeamelement3i, r_lightningbeamelement3s, false, false); if (r_lightningbeam_qmbtexture.integer && r_lightningbeamqmbtexture == NULL) r_lightningbeams_setupqmbtexture(); if (!r_lightningbeam_qmbtexture.integer && r_lightningbeamtexture == NULL) r_lightningbeams_setuptexture(); for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { const beam_t *b = cl.beams + surfacelist[surfacelistindex]; vec3_t beamdir, right, up, offset, start, end; float length, t1, t2; CL_Beam_CalculatePositions(b, start, end); // calculate beam direction (beamdir) vector and beam length // get difference vector VectorSubtract(end, start, beamdir); // find length of difference vector length = sqrt(DotProduct(beamdir, beamdir)); // calculate scale to make beamdir a unit vector (normalized) t1 = 1.0f / length; // scale beamdir so it is now normalized VectorScale(beamdir, t1, beamdir); // calculate up vector such that it points toward viewer, and rotates around the beamdir // get direction from start of beam to viewer VectorSubtract(r_refdef.view.origin, start, up); // remove the portion of the vector that moves along the beam // (this leaves only a vector pointing directly away from the beam) t1 = -DotProduct(up, beamdir); VectorMA(up, t1, beamdir, up); // generate right vector from forward and up, the result is unnormalized CrossProduct(beamdir, up, right); // now normalize the right vector and up vector VectorNormalize(right); VectorNormalize(up); // calculate T coordinate scrolling (start and end texcoord along the beam) t1 = r_refdef.scene.time * -r_lightningbeam_scroll.value;// + beamrepeatscale * DotProduct(start, beamdir); t1 = t1 - (int) t1; t2 = t1 + beamrepeatscale * length; // the beam is 3 polygons in this configuration: // * 2 // * * // 1****** // * * // * 3 // they are showing different portions of the beam texture, creating an // illusion of a beam that appears to curl around in 3D space // (and realize that the whole polygon assembly orients itself to face // the viewer) // polygon 1, verts 0-3 VectorScale(right, r_lightningbeam_thickness.value, offset); R_CalcLightningBeamPolygonVertex3f(vertex3f + 0, start, end, offset); // polygon 2, verts 4-7 VectorAdd(right, up, offset); VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset); R_CalcLightningBeamPolygonVertex3f(vertex3f + 12, start, end, offset); // polygon 3, verts 8-11 VectorSubtract(right, up, offset); VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset); R_CalcLightningBeamPolygonVertex3f(vertex3f + 24, start, end, offset); R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 0, t1, t2); R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 8, t1 + 0.33, t2 + 0.33); R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 16, t1 + 0.66, t2 + 0.66); // draw the 3 polygons as one batch of 6 triangles using the 12 vertices R_DrawCustomSurface(r_lightningbeam_qmbtexture.integer ? r_lightningbeamqmbtexture : r_lightningbeamtexture, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 12, 0, 6, false, false); } }
void CL_Beam_AddPolygons(const beam_t *b) { vec3_t beamdir, right, up, offset, start, end; vec_t beamscroll = r_refdef.scene.time * -r_lightningbeam_scroll.value; vec_t beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value; float length, t1, t2; dp_model_t *mod; msurface_t *surf; if (r_lightningbeam_qmbtexture.integer && cl_beams_externaltexture.currentskinframe == NULL) CL_Beams_SetupExternalTexture(); if (!r_lightningbeam_qmbtexture.integer && cl_beams_builtintexture.currentskinframe == NULL) CL_Beams_SetupBuiltinTexture(); // calculate beam direction (beamdir) vector and beam length // get difference vector CL_Beam_CalculatePositions(b, start, end); VectorSubtract(end, start, beamdir); // find length of difference vector length = sqrt(DotProduct(beamdir, beamdir)); // calculate scale to make beamdir a unit vector (normalized) t1 = 1.0f / length; // scale beamdir so it is now normalized VectorScale(beamdir, t1, beamdir); // calculate up vector such that it points toward viewer, and rotates around the beamdir // get direction from start of beam to viewer VectorSubtract(r_refdef.view.origin, start, up); // remove the portion of the vector that moves along the beam // (this leaves only a vector pointing directly away from the beam) t1 = -DotProduct(up, beamdir); VectorMA(up, t1, beamdir, up); // generate right vector from forward and up, the result is unnormalized CrossProduct(beamdir, up, right); // now normalize the right vector and up vector VectorNormalize(right); VectorNormalize(up); // calculate T coordinate scrolling (start and end texcoord along the beam) t1 = beamscroll; t1 = t1 - (int)t1; t2 = t1 + beamrepeatscale * length; // the beam is 3 polygons in this configuration: // * 2 // * * // 1***** // * * // * 3 // they are showing different portions of the beam texture, creating an // illusion of a beam that appears to curl around in 3D space // (and realize that the whole polygon assembly orients itself to face // the viewer) mod = &cl_meshentitymodels[MESH_PARTICLES]; surf = Mod_Mesh_AddSurface(mod, r_lightningbeam_qmbtexture.integer ? &cl_beams_externaltexture : &cl_beams_builtintexture, false); // polygon 1 VectorM(r_lightningbeam_thickness.value, right, offset); CL_Beam_AddQuad(mod, surf, start, end, offset, t1, t2); // polygon 2 VectorMAM(r_lightningbeam_thickness.value * 0.70710681f, right, r_lightningbeam_thickness.value * 0.70710681f, up, offset); CL_Beam_AddQuad(mod, surf, start, end, offset, t1 + 0.33f, t2 + 0.33f); // polygon 3 VectorMAM(r_lightningbeam_thickness.value * 0.70710681f, right, r_lightningbeam_thickness.value * -0.70710681f, up, offset); CL_Beam_AddQuad(mod, surf, start, end, offset, t1 + 0.66f, t2 + 0.66f); }