2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #define MAX_DECALS 2048
25 typedef struct decal_s
38 static decal_t *cl_decals;
39 static int cl_currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
41 static renderdecal_t *cl_renderdecals;
43 static mempool_t *cl_decal_mempool;
45 void CL_Decals_Clear(void)
47 memset(cl_decals, 0, MAX_DECALS * sizeof(decal_t));
51 void CL_Decals_Init(void)
53 cl_decal_mempool = Mem_AllocPool("CL_Decals");
54 cl_decals = (decal_t *) Mem_Alloc(cl_decal_mempool, MAX_DECALS * sizeof(decal_t));
55 memset(cl_decals, 0, MAX_DECALS * sizeof(decal_t));
58 // FIXME: r_refdef stuff should be allocated somewhere else?
59 r_refdef.decals = cl_renderdecals = Mem_Alloc(cl_refdef_mempool, MAX_DECALS * sizeof(renderdecal_t));
63 // these are static globals only to avoid putting unnecessary things on the stack
64 static vec3_t decalorg, decalbestorg;
65 static float decalbestdist;
66 static msurface_t *decalbestsurf;
67 static entity_render_t *decalbestent, *decalent;
68 static model_t *decalmodel;
69 void CL_RecursiveDecalSurface (mnode_t *node)
71 // these are static because only one occurance of them need exist at once, so avoid putting them on the stack
72 static float ndist, dist;
73 static msurface_t *surf, *endsurf;
78 if (node->contents < 0)
81 ndist = PlaneDiff(decalorg, node->plane);
85 node = node->children[0];
90 node = node->children[1];
95 surf = decalmodel->surfaces + node->firstsurface;
96 endsurf = surf + node->numsurfaces;
97 for (;surf < endsurf;surf++)
99 if (!(surf->flags & SURF_LIGHTMAP))
102 dist = PlaneDiff(decalorg, surf->plane);
103 if (surf->flags & SURF_PLANEBACK)
107 if (dist >= decalbestdist)
110 impact[0] = decalorg[0] - surf->plane->normal[0] * dist;
111 impact[1] = decalorg[1] - surf->plane->normal[1] * dist;
112 impact[2] = decalorg[2] - surf->plane->normal[2] * dist;
114 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
115 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
117 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
120 VectorCopy(decalorg, decalbestorg);
121 decalbestent = decalent;
122 decalbestsurf = surf;
123 decalbestdist = dist;
126 if (node->children[0]->contents >= 0)
128 if (node->children[1]->contents >= 0)
130 CL_RecursiveDecalSurface (node->children[0]);
131 node = node->children[1];
136 node = node->children[0];
140 else if (node->children[1]->contents >= 0)
142 node = node->children[1];
147 void CL_Decal(vec3_t origin, int tex, float scale, float red, float green, float blue, float alpha)
152 if (alpha < (1.0f / 255.0f))
155 // find the best surface to place the decal on
157 decalbestsurf = NULL;
161 decalmodel = cl.worldmodel;
162 Mod_CheckLoaded(decalmodel);
163 VectorCopy(origin, decalorg);
164 CL_RecursiveDecalSurface (decalmodel->nodes);
166 for (i = 1;i < MAX_EDICTS;i++)
168 decalent = &cl_entities[i].render;
169 decalmodel = decalent->model;
170 if (decalmodel && decalmodel->name[0])
172 Mod_CheckLoaded(decalmodel);
173 if (decalmodel->type == mod_brush)
175 softwaretransformforentity(decalent);
176 softwareuntransform(origin, decalorg);
177 CL_RecursiveDecalSurface (decalmodel->nodes);
182 // abort if no suitable surface was found
183 if (decalbestsurf == NULL)
186 // grab a decal from the array and advance to the next decal to replace, wrapping to replace an old decal if necessary
187 decal = &cl_decals[cl_currentdecal++];
188 if (cl_currentdecal >= MAX_DECALS)
190 memset(decal, 0, sizeof(*decal));
192 decal->ent = decalbestent;
194 decal->model = decal->ent->model;
196 decal->model = cl.worldmodel;
198 decal->tex = tex + 1; // our texture numbers are +1 to make 0 mean invisible
199 VectorNegate(decalbestsurf->plane->normal, decal->dir);
200 if (decalbestsurf->flags & SURF_PLANEBACK)
201 VectorNegate(decal->dir, decal->dir);
202 // 0.25 to push it off the surface a bit
203 decalbestdist -= 0.25f;
204 decal->org[0] = decalbestorg[0] + decal->dir[0] * decalbestdist;
205 decal->org[1] = decalbestorg[1] + decal->dir[1] * decalbestdist;
206 decal->org[2] = decalbestorg[2] + decal->dir[2] * decalbestdist;
207 decal->scale = scale * 0.5f;
209 decal->color[0] = red;
210 decal->color[1] = green;
211 decal->color[2] = blue;
212 decal->color[3] = alpha;
213 // store the surface information
214 decal->surface = decalbestsurf - decal->model->surfaces;
217 void CL_UpdateDecals (void)
223 for (i = 0, p = cl_decals, r = r_refdef.decals;i < MAX_DECALS;i++, p++)
228 if (p->ent && p->ent->visframe == r_framecount && (p->ent->model != p->model || p->ent->model->type != mod_brush))
235 r->tex = p->tex - 1; // our texture numbers are +1 to make 0 mean invisible
236 r->surface = p->surface;
238 VectorCopy(p->org, r->org);
239 VectorCopy(p->dir, r->dir);
240 VectorCopy4(p->color, r->color);
243 r_refdef.numdecals = r - r_refdef.decals;