/* * Copyright (C) 1997-2001 Id Software, Inc. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "r_local.h" #ifdef FLARES #define MAX_FLARES 256 #define FLARE_STYLES 6 int numflares; flare_t flares[MAX_FLARES]; trace_t CL_Trace(vec3_t start, vec3_t end, float size, int contentmask); void R_ClearFlares(void) { memset(flares, 0, sizeof(flares)); numflares = 0; } qboolean IsVisible(vec3_t org1, vec3_t org2) { trace_t trace; trace = CL_Trace(org1, org2, 0, MASK_SOLID); if (trace.fraction != 1) return (false); else return (true); } void R_RenderFlares(void) { int i; flare_t *light; if (r_flares->value == 0) return; qglDepthMask(0); qglDisable(GL_TEXTURE_2D); qglShadeModel(GL_SMOOTH); qglEnable(GL_BLEND); /* Fog bug fix by Kirk Barnes. */ qglBlendFunc(GL_SRC_ALPHA, GL_ONE); light = flares; for (i = 0; i < numflares; i++, light++) if (IsVisible(r_origin, light->origin)) R_RenderFlare(light); qglColor3f(1, 1, 1); qglDisable(GL_BLEND); qglEnable(GL_TEXTURE_2D); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglDepthMask(1); } void R_RenderFlare(flare_t *light) { char pathname[MAX_QPATH]; /* Flare image path. */ int size; /* Flare size. */ int style; /* Flare style. */ float dist; /* Distance to flare. */ image_t *flare; /* Flare image. */ vec3_t color; /* Flare color. */ vec3_t vec; /* Vector distance to flare. */ vec3_t point; /* For flare coordinates. */ /* Check for flare style override. */ if (r_flare_force_style->value > 0 && r_flare_force_style->value <= FLARE_STYLES) style = r_flare_force_style->value; else style = light->style; /* Check if style is valid. */ if (style > 0 && style <= FLARE_STYLES) Com_sprintf(pathname, sizeof(pathname), "gfx/flare%d.png", style); else Sys_Error("R_RenderFlare: invalid flare style: %d", style); flare = GL_FindImage(pathname, it_sprite); if (flare == NULL) /* Sys_Error("R_RenderFlare: flare image '%s'not found", pathname); */ flare = r_notexture; /* Check for flare size override. */ if (r_flare_force_size->value != 0) size = r_flare_force_size->value; else size = light->size * r_flare_scale->value; /* Adjust flare intensity. */ VectorScale(light->color, r_flare_intensity->value, color); /* Calculate size based on distance. */ VectorSubtract(light->origin, r_origin, vec); dist = VectorLength(vec) * (size * 0.01); /* Limit flare size. */ if (r_flare_maxdist->value != 0) if (dist > r_flare_maxdist->value) dist = r_flare_maxdist->value; qglDisable(GL_DEPTH_TEST); qglEnable(GL_TEXTURE_2D); qglColor4f(color[0] / 2, color[1] / 2, color[2] / 2, 1); GL_Bind(flare->texnum); GL_TexEnv(GL_MODULATE); qglBegin(GL_QUADS); #if 0 /* Shorter, but expensive (needs more calculations). */ for (i = 0; i < 2; i++) for (i ? (j = 0) : (j = 1); i ? (j < 2) : (j >= 0); i ? (j++) : (j--)) { qglTexCoord2f(i, j); VectorMA(light->origin, i ? (1 + dist) : (-1 - dist), vup, point); VectorMA(point, j ? (1 + dist) : (-1 - dist), vright, point); qglVertex3fv(point); } #endif qglTexCoord2f(0, 1); VectorMA(light->origin, -1-dist, vup, point); VectorMA(point, 1+dist, vright, point); qglVertex3fv(point); qglTexCoord2f(0, 0); VectorMA(light->origin, -1-dist, vup, point); VectorMA(point, -1-dist, vright, point); qglVertex3fv (point); qglTexCoord2f(1, 0); VectorMA(light->origin, 1+dist, vup, point); VectorMA(point, -1-dist, vright, point); qglVertex3fv(point); qglTexCoord2f(1, 1); VectorMA(light->origin, 1+dist, vup, point); VectorMA(point, 1+dist, vright, point); qglVertex3fv(point); qglEnd(); GL_TexEnv(GL_REPLACE); qglEnable(GL_DEPTH_TEST); qglDisable(GL_TEXTURE_2D); qglColor3f(0, 0, 0); } void GL_AddFlareSurface(msurface_t * surf) { byte *lightmap; int i; int intens; /* Light intensity. */ int maps; flare_t *light; /* New flare. */ vec3_t origin; /* Center of surface. */ vec3_t color; /* Flare color. */ vec3_t normal; /* Normal vector. */ vec3_t scale; /* Check for free flares. */ if (numflares >= MAX_FLARES) return; /* Initialization. */ VectorClear(origin); VectorSet(color, 0, 0, 0); intens = surf->texinfo->value; /* Skip very small or null lights. */ if (intens <= 1000) return; /* Create new flare. */ light = &flares[numflares++]; VectorCopy(surf->center, origin); /* Calculate color. */ lightmap = surf->samples; if (lightmap) { for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { for (i = 0; i < 3; i++) { scale[i] = gl_modulate->value * r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; color[i] += lightmap[i] * scale[i] * (1.0 / 255); } lightmap += 3 * ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1); } } else VectorSet(color, 1.0, 1.0, 1.0); VectorCopy(color, light->color); /* Move flare 2 units far from the surface. */ if (surf->flags & SURF_PLANEBACK) VectorNegate(surf->plane->normal, normal); else VectorCopy(surf->plane->normal, normal); VectorMA(origin, 2, normal, origin); VectorCopy(origin, light->origin); light->style = numflares % FLARE_STYLES + 1; /* Pseudo-random. */ light->size = intens / 1000; } #endif