/* ================== R_AllocDecal ================== */ static decal_t *R_AllocDecal (){ decal_t *decal; // Allocate a slot, freeing the oldest if necessary if (!r_freeDecals) R_FreeDecal(r_activeDecals.prev); decal = r_freeDecals; // Link r_freeDecals = r_freeDecals->next; Mem_Fill(decal, 0, sizeof(decal_t)); decal->next = r_activeDecals.next; decal->prev = &r_activeDecals; r_activeDecals.next->prev = decal; r_activeDecals.next = decal; return decal; }
/* ================= R_DrawDecals Draws all decals on the decal list ================= */ void R_DrawDecals (void) { cdecal_t *dl, *next, *active; float mindist, time; int r_numdecals = 0; vec3_t v; vec4_t color; if (!gl_decals->value) return; if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) return; active = &active_decals; mindist = DotProduct(r_origin, vpn) + 4.0; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-2, -2); GL_Enable(BLEND_BIT | DEPTHTEST_BIT); GL_UseProgram(gl_decalprog); glProgramUniformMatrix4fv (gl_decalprog, gl_decalmvpMatrix, 1, GL_FALSE, r_mvpmatrix.m[0]); for (dl = active->next; dl != active; dl = next) { next = dl->next; if (dl->node == NULL || dl->node->visframe != r_visframecount) continue; // check type if (dl->type < 0 || dl->type > MAX_DECAL_TEX) { R_FreeDecal (dl); continue; } // have we faded out yet? if (dl->time + gl_decalsTime->value <= r_newrefdef.time) { R_FreeDecal (dl); continue; } // do not render if the decal is behind the view if (DotProduct(dl->org, vpn) < mindist) continue; // do not render if the view origin is behind the decal VectorSubtract(dl->org, r_origin, v); if (DotProduct(dl->direction, v) < 0) continue; Vector4Copy(dl->color, color); time = dl->time + gl_decalsTime->value - r_newrefdef.time; if (time < 1.5) color[3] *= time / 1.5; // bind texture GL_BindTexture(GL_TEXTURE0, GL_TEXTURE_2D, r_drawnearestclampsampler, r_decalImages[dl->type]); // bind data into vbo glBindBuffer(GL_ARRAY_BUFFER, gl_decalvbo); glBufferData(GL_ARRAY_BUFFER, sizeof(dl->verts) + sizeof(dl->stcoords) + sizeof(color), NULL, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(dl->verts), dl->verts); glBufferSubData(GL_ARRAY_BUFFER, sizeof(dl->verts), sizeof(dl->stcoords), dl->stcoords); glBufferSubData(GL_ARRAY_BUFFER, sizeof(dl->verts) + sizeof(dl->stcoords), sizeof(color), color); // bind vao GL_BindVertexArray(gl_decalvao); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void *)sizeof(dl->verts)); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (void *)(sizeof(dl->verts) + sizeof(dl->stcoords))); // draw glDrawArrays(GL_TRIANGLE_FAN, 0, dl->numverts); r_numdecals++; if (r_numdecals >= MAX_DECALS) break; } glDisable(GL_POLYGON_OFFSET_FILL); }