mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 16:21:04 +02:00
652 lines
18 KiB
C++
652 lines
18 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
IceTech GPL Source Code
|
|
Copyright (C) 2026 Justin Marshall
|
|
|
|
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
|
|
|
IceTech Source Code 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
IceTech Source Code 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "../renderer/tr_local.h"
|
|
#include "Model_local.h"
|
|
|
|
// decalFade filter 5 0.1
|
|
// polygonOffset
|
|
// {
|
|
// map invertColor( textures/splat )
|
|
// blend GL_ZERO GL_ONE_MINUS_SRC
|
|
// vertexColor
|
|
// clamp
|
|
// }
|
|
|
|
#ifdef QUAKE4
|
|
int idRenderModelDecal::allocatedDecalCount = 0;
|
|
#endif
|
|
|
|
/*
|
|
==================
|
|
idRenderModelDecal::idRenderModelDecal
|
|
==================
|
|
*/
|
|
idRenderModelDecal::idRenderModelDecal(void) {
|
|
memset(&tri, 0, sizeof(tri));
|
|
tri.verts = verts;
|
|
tri.indexes = indexes;
|
|
material = NULL;
|
|
nextDecal = NULL;
|
|
#ifdef QUAKE4
|
|
memset(vertLifeSpan, 0, sizeof(vertLifeSpan));
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idRenderModelDecal::~idRenderModelDecal
|
|
==================
|
|
*/
|
|
idRenderModelDecal::~idRenderModelDecal(void) {
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idRenderModelDecal::Alloc
|
|
==================
|
|
*/
|
|
idRenderModelDecal* idRenderModelDecal::Alloc(void) {
|
|
#ifdef QUAKE4
|
|
allocatedDecalCount++;
|
|
#endif
|
|
return new idRenderModelDecal;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idRenderModelDecal::Free
|
|
==================
|
|
*/
|
|
void idRenderModelDecal::Free(idRenderModelDecal* decal) {
|
|
if (decal == NULL) {
|
|
return;
|
|
}
|
|
#ifdef QUAKE4
|
|
allocatedDecalCount--;
|
|
#endif
|
|
delete decal;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idRenderModelDecal::CreateProjectionInfo
|
|
=================
|
|
*/
|
|
bool idRenderModelDecal::CreateProjectionInfo(decalProjectionInfo_t& info, const idFixedWinding& winding, const idVec3& projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial* material, const int startTime) {
|
|
|
|
if (winding.GetNumPoints() != NUM_DECAL_BOUNDING_PLANES - 2) {
|
|
common->Printf("idRenderModelDecal::CreateProjectionInfo: winding must have %d points\n", NUM_DECAL_BOUNDING_PLANES - 2);
|
|
return false;
|
|
}
|
|
|
|
assert(material != NULL);
|
|
|
|
info.projectionOrigin = projectionOrigin;
|
|
info.material = material;
|
|
info.parallel = parallel;
|
|
info.fadeDepth = fadeDepth;
|
|
info.startTime = startTime;
|
|
#ifdef QUAKE4
|
|
info.maxAngle = material->GetDecalInfo().maxAngle;
|
|
#endif
|
|
info.force = false;
|
|
|
|
// get the winding plane and the depth of the projection volume
|
|
idPlane windingPlane;
|
|
winding.GetPlane(windingPlane);
|
|
float depth = windingPlane.Distance(projectionOrigin);
|
|
|
|
// find the bounds for the projection
|
|
winding.GetBounds(info.projectionBounds);
|
|
#ifdef QUAKE4
|
|
if (parallel) {
|
|
const idVec3 depthOffset = windingPlane.Normal() * depth;
|
|
const idVec3 fadeOffset = windingPlane.Normal() * fadeDepth;
|
|
for (int i = 0; i < winding.GetNumPoints(); i++) {
|
|
const idVec3 p = winding[i].ToVec3();
|
|
info.projectionBounds.AddPoint(p + depthOffset);
|
|
info.projectionBounds.AddPoint(p - fadeOffset);
|
|
}
|
|
}
|
|
else {
|
|
info.projectionBounds.AddPoint(projectionOrigin);
|
|
}
|
|
#else
|
|
if (parallel) {
|
|
info.projectionBounds.ExpandSelf(depth);
|
|
}
|
|
else {
|
|
info.projectionBounds.AddPoint(projectionOrigin);
|
|
}
|
|
#endif
|
|
|
|
// calculate the world space projection volume bounding planes, positive sides face outside the decal
|
|
if (parallel) {
|
|
for (int i = 0; i < winding.GetNumPoints(); i++) {
|
|
idVec3 edge = winding[(i + 1) % winding.GetNumPoints()].ToVec3() - winding[i].ToVec3();
|
|
info.boundingPlanes[i].Normal().Cross(windingPlane.Normal(), edge);
|
|
info.boundingPlanes[i].Normalize();
|
|
info.boundingPlanes[i].FitThroughPoint(winding[i].ToVec3());
|
|
}
|
|
}
|
|
else {
|
|
for (int i = 0; i < winding.GetNumPoints(); i++) {
|
|
info.boundingPlanes[i].FromPoints(projectionOrigin, winding[i].ToVec3(), winding[(i + 1) % winding.GetNumPoints()].ToVec3());
|
|
}
|
|
}
|
|
info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2] = windingPlane;
|
|
info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2][3] -= depth;
|
|
info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1] = -windingPlane;
|
|
|
|
// fades will be from these plane
|
|
info.fadePlanes[0] = windingPlane;
|
|
info.fadePlanes[0][3] -= fadeDepth;
|
|
info.fadePlanes[1] = -windingPlane;
|
|
info.fadePlanes[1][3] += depth - fadeDepth;
|
|
|
|
// calculate the texture vectors for the winding
|
|
float len, texArea, inva;
|
|
idVec3 temp;
|
|
idVec5 d0, d1;
|
|
|
|
const idVec5& a = winding[0];
|
|
const idVec5& b = winding[1];
|
|
const idVec5& c = winding[2];
|
|
|
|
d0 = b.ToVec3() - a.ToVec3();
|
|
d0.s = b.s - a.s;
|
|
d0.t = b.t - a.t;
|
|
d1 = c.ToVec3() - a.ToVec3();
|
|
d1.s = c.s - a.s;
|
|
d1.t = c.t - a.t;
|
|
|
|
texArea = (d0[3] * d1[4]) - (d0[4] * d1[3]);
|
|
if (texArea == 0.0f) {
|
|
return false;
|
|
}
|
|
inva = 1.0f / texArea;
|
|
|
|
temp[0] = (d0[0] * d1[4] - d0[4] * d1[0]) * inva;
|
|
temp[1] = (d0[1] * d1[4] - d0[4] * d1[1]) * inva;
|
|
temp[2] = (d0[2] * d1[4] - d0[4] * d1[2]) * inva;
|
|
len = temp.Normalize();
|
|
if (len == 0.0f) {
|
|
return false;
|
|
}
|
|
info.textureAxis[0].Normal() = temp * (1.0f / len);
|
|
info.textureAxis[0][3] = winding[0].s - (winding[0].ToVec3() * info.textureAxis[0].Normal());
|
|
|
|
temp[0] = (d0[3] * d1[0] - d0[0] * d1[3]) * inva;
|
|
temp[1] = (d0[3] * d1[1] - d0[1] * d1[3]) * inva;
|
|
temp[2] = (d0[3] * d1[2] - d0[2] * d1[3]) * inva;
|
|
len = temp.Normalize();
|
|
if (len == 0.0f) {
|
|
return false;
|
|
}
|
|
info.textureAxis[1].Normal() = temp * (1.0f / len);
|
|
info.textureAxis[1][3] = winding[0].t - (winding[0].ToVec3() * info.textureAxis[1].Normal());
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idRenderModelDecal::GlobalProjectionInfoToLocal
|
|
=================
|
|
*/
|
|
void idRenderModelDecal::GlobalProjectionInfoToLocal(decalProjectionInfo_t& localInfo, const decalProjectionInfo_t& info, const idVec3& origin, const idMat3& axis) {
|
|
float modelMatrix[16];
|
|
|
|
R_AxisToModelMatrix(axis, origin, modelMatrix);
|
|
|
|
for (int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++) {
|
|
R_GlobalPlaneToLocal(modelMatrix, info.boundingPlanes[j], localInfo.boundingPlanes[j]);
|
|
}
|
|
R_GlobalPlaneToLocal(modelMatrix, info.fadePlanes[0], localInfo.fadePlanes[0]);
|
|
R_GlobalPlaneToLocal(modelMatrix, info.fadePlanes[1], localInfo.fadePlanes[1]);
|
|
R_GlobalPlaneToLocal(modelMatrix, info.textureAxis[0], localInfo.textureAxis[0]);
|
|
R_GlobalPlaneToLocal(modelMatrix, info.textureAxis[1], localInfo.textureAxis[1]);
|
|
R_GlobalPointToLocal(modelMatrix, info.projectionOrigin, localInfo.projectionOrigin);
|
|
localInfo.projectionBounds = info.projectionBounds;
|
|
localInfo.projectionBounds.TranslateSelf(-origin);
|
|
localInfo.projectionBounds.RotateSelf(axis.Transpose());
|
|
localInfo.material = info.material;
|
|
localInfo.parallel = info.parallel;
|
|
localInfo.fadeDepth = info.fadeDepth;
|
|
localInfo.startTime = info.startTime;
|
|
#ifdef QUAKE4
|
|
localInfo.maxAngle = info.maxAngle;
|
|
#endif
|
|
localInfo.force = info.force;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idRenderModelDecal::AddWinding
|
|
=================
|
|
*/
|
|
void idRenderModelDecal::AddWinding(const idWinding& w, const idMaterial* decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime) {
|
|
int i;
|
|
float invFadeDepth, fade;
|
|
#ifndef QUAKE4
|
|
decalInfo_t decalInfo;
|
|
#endif
|
|
|
|
if ((material == NULL || material == decalMaterial) &&
|
|
tri.numVerts + w.GetNumPoints() < MAX_DECAL_VERTS &&
|
|
tri.numIndexes + (w.GetNumPoints() - 2) * 3 < MAX_DECAL_INDEXES) {
|
|
|
|
material = decalMaterial;
|
|
|
|
// add to this decal
|
|
#ifndef QUAKE4
|
|
decalInfo = material->GetDecalInfo();
|
|
#endif
|
|
invFadeDepth = -1.0f / fadeDepth;
|
|
|
|
for (i = 0; i < w.GetNumPoints(); i++) {
|
|
fade = fadePlanes[0].Distance(w[i].ToVec3()) * invFadeDepth;
|
|
if (fade < 0.0f) {
|
|
fade = fadePlanes[1].Distance(w[i].ToVec3()) * invFadeDepth;
|
|
}
|
|
if (fade < 0.0f) {
|
|
fade = 0.0f;
|
|
}
|
|
else if (fade > 0.99f) {
|
|
fade = 1.0f;
|
|
}
|
|
fade = 1.0f - fade;
|
|
vertDepthFade[tri.numVerts + i] = fade;
|
|
#ifdef QUAKE4
|
|
vertLifeSpan[tri.numVerts + i] = 0.0f;
|
|
#endif
|
|
tri.verts[tri.numVerts + i].xyz = w[i].ToVec3();
|
|
tri.verts[tri.numVerts + i].st[0] = w[i].s;
|
|
tri.verts[tri.numVerts + i].st[1] = w[i].t;
|
|
#ifndef QUAKE4
|
|
for (int k = 0; k < 4; k++) {
|
|
int icolor = idMath::FtoiFast(decalInfo.start[k] * fade * 255.0f);
|
|
if (icolor < 0) {
|
|
icolor = 0;
|
|
}
|
|
else if (icolor > 255) {
|
|
icolor = 255;
|
|
}
|
|
tri.verts[tri.numVerts + i].color[k] = icolor;
|
|
}
|
|
#else
|
|
// Quake 4 decal color is evaluated through material stages later.
|
|
// Do not use decalInfo.start/end here because Q4 decalInfo_t does not have them.
|
|
tri.verts[tri.numVerts + i].color[0] = 255;
|
|
tri.verts[tri.numVerts + i].color[1] = 255;
|
|
tri.verts[tri.numVerts + i].color[2] = 255;
|
|
tri.verts[tri.numVerts + i].color[3] = 255;
|
|
#endif
|
|
}
|
|
for (i = 2; i < w.GetNumPoints(); i++) {
|
|
tri.indexes[tri.numIndexes + 0] = tri.numVerts;
|
|
tri.indexes[tri.numIndexes + 1] = tri.numVerts + i - 1;
|
|
tri.indexes[tri.numIndexes + 2] = tri.numVerts + i;
|
|
indexStartTime[tri.numIndexes] =
|
|
indexStartTime[tri.numIndexes + 1] =
|
|
#ifdef QUAKE4
|
|
indexStartTime[tri.numIndexes + 2] = (float)startTime;
|
|
#else
|
|
indexStartTime[tri.numIndexes + 2] = startTime;
|
|
#endif
|
|
tri.numIndexes += 3;
|
|
}
|
|
tri.numVerts += w.GetNumPoints();
|
|
return;
|
|
}
|
|
|
|
// if we are at the end of the list, create a new decal
|
|
if (!nextDecal) {
|
|
nextDecal = idRenderModelDecal::Alloc();
|
|
}
|
|
// let the next decal on the chain take a look
|
|
nextDecal->AddWinding(w, decalMaterial, fadePlanes, fadeDepth, startTime);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idRenderModelDecal::AddDepthFadedWinding
|
|
=================
|
|
*/
|
|
void idRenderModelDecal::AddDepthFadedWinding(const idWinding& w, const idMaterial* decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime) {
|
|
idFixedWinding front, back;
|
|
|
|
front = w;
|
|
if (front.Split(&back, fadePlanes[0], 0.1f) == SIDE_CROSS) {
|
|
AddWinding(back, decalMaterial, fadePlanes, fadeDepth, startTime);
|
|
}
|
|
|
|
if (front.Split(&back, fadePlanes[1], 0.1f) == SIDE_CROSS) {
|
|
AddWinding(back, decalMaterial, fadePlanes, fadeDepth, startTime);
|
|
}
|
|
|
|
AddWinding(front, decalMaterial, fadePlanes, fadeDepth, startTime);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idRenderModelDecal::CreateDecal
|
|
=================
|
|
*/
|
|
void idRenderModelDecal::CreateDecal(const idRenderModel* model, const decalProjectionInfo_t& localInfo) {
|
|
|
|
// check all model surfaces
|
|
for (int surfNum = 0; surfNum < model->NumSurfaces(); surfNum++) {
|
|
const modelSurface_t* surf = model->Surface(surfNum);
|
|
|
|
// if no geometry or no shader
|
|
if (!surf->geometry || !surf->shader) {
|
|
continue;
|
|
}
|
|
|
|
// decals and overlays use the same rules
|
|
if (!localInfo.force && !surf->shader->AllowOverlays()) {
|
|
continue;
|
|
}
|
|
|
|
srfTriangles_t* stri = surf->geometry;
|
|
|
|
// if the triangle bounds do not overlap with projection bounds
|
|
if (!localInfo.projectionBounds.IntersectsBounds(stri->bounds)) {
|
|
continue;
|
|
}
|
|
|
|
// allocate memory for the cull bits
|
|
byte* cullBits = (byte*)_alloca16(stri->numVerts * sizeof(cullBits[0]));
|
|
|
|
// categorize all points by the planes
|
|
SIMDProcessor->DecalPointCull(cullBits, localInfo.boundingPlanes, stri->verts, stri->numVerts);
|
|
|
|
// find triangles inside the projection volume
|
|
for (int triNum = 0, index = 0; index < stri->numIndexes; index += 3, triNum++) {
|
|
int v1 = stri->indexes[index + 0];
|
|
int v2 = stri->indexes[index + 1];
|
|
int v3 = stri->indexes[index + 2];
|
|
|
|
// skip triangles completely off one side
|
|
if (cullBits[v1] & cullBits[v2] & cullBits[v3]) {
|
|
continue;
|
|
}
|
|
|
|
// skip back facing triangles
|
|
if (stri->facePlanes && stri->facePlanesCalculated) {
|
|
#ifdef QUAKE4
|
|
if (stri->facePlanes[triNum].Normal() * localInfo.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2].Normal() < localInfo.maxAngle) {
|
|
continue;
|
|
}
|
|
#else
|
|
if (stri->facePlanes[triNum].Normal() * localInfo.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2].Normal() < -0.1f) {
|
|
continue;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// create a winding with texture coordinates for the triangle
|
|
idFixedWinding fw;
|
|
fw.SetNumPoints(3);
|
|
if (localInfo.parallel) {
|
|
for (int j = 0; j < 3; j++) {
|
|
fw[j] = stri->verts[stri->indexes[index + j]].xyz;
|
|
fw[j].s = localInfo.textureAxis[0].Distance(fw[j].ToVec3());
|
|
fw[j].t = localInfo.textureAxis[1].Distance(fw[j].ToVec3());
|
|
}
|
|
}
|
|
else {
|
|
for (int j = 0; j < 3; j++) {
|
|
idVec3 dir;
|
|
float scale;
|
|
|
|
fw[j] = stri->verts[stri->indexes[index + j]].xyz;
|
|
dir = fw[j].ToVec3() - localInfo.projectionOrigin;
|
|
localInfo.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1].RayIntersection(fw[j].ToVec3(), dir, scale);
|
|
dir = fw[j].ToVec3() + scale * dir;
|
|
fw[j].s = localInfo.textureAxis[0].Distance(dir);
|
|
fw[j].t = localInfo.textureAxis[1].Distance(dir);
|
|
}
|
|
}
|
|
|
|
int orBits = cullBits[v1] | cullBits[v2] | cullBits[v3];
|
|
|
|
// clip the exact surface triangle to the projection volume
|
|
for (int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++) {
|
|
if (orBits & (1 << j)) {
|
|
if (!fw.ClipInPlace(-localInfo.boundingPlanes[j])) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fw.GetNumPoints() == 0) {
|
|
continue;
|
|
}
|
|
|
|
AddDepthFadedWinding(fw, localInfo.material, localInfo.fadePlanes, localInfo.fadeDepth, localInfo.startTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idRenderModelDecal::RemoveFadedDecals
|
|
=====================
|
|
*/
|
|
idRenderModelDecal* idRenderModelDecal::RemoveFadedDecals(idRenderModelDecal* decals, int time) {
|
|
int i, j, newNumIndexes, newNumVerts;
|
|
int inUse[MAX_DECAL_VERTS];
|
|
decalInfo_t decalInfo;
|
|
idRenderModelDecal* nextDecal;
|
|
|
|
if (decals == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// recursively free any next decals
|
|
decals->nextDecal = RemoveFadedDecals(decals->nextDecal, time);
|
|
|
|
// free the decals if no material set
|
|
if (decals->material == NULL) {
|
|
nextDecal = decals->nextDecal;
|
|
Free(decals);
|
|
return nextDecal;
|
|
}
|
|
|
|
decalInfo = decals->material->GetDecalInfo();
|
|
|
|
#ifdef QUAKE4
|
|
const float minTime = (float)(time - decalInfo.stayTime);
|
|
#else
|
|
const int minTime = time - (decalInfo.stayTime + decalInfo.fadeTime);
|
|
#endif
|
|
|
|
newNumIndexes = 0;
|
|
for (i = 0; i < decals->tri.numIndexes; i += 3) {
|
|
if (decals->indexStartTime[i] > minTime) {
|
|
// keep this triangle
|
|
if (newNumIndexes != i) {
|
|
for (j = 0; j < 3; j++) {
|
|
decals->tri.indexes[newNumIndexes + j] = decals->tri.indexes[i + j];
|
|
decals->indexStartTime[newNumIndexes + j] = decals->indexStartTime[i + j];
|
|
}
|
|
}
|
|
newNumIndexes += 3;
|
|
}
|
|
}
|
|
|
|
// free the decals if all triangles faded away
|
|
if (newNumIndexes == 0) {
|
|
nextDecal = decals->nextDecal;
|
|
Free(decals);
|
|
return nextDecal;
|
|
}
|
|
|
|
decals->tri.numIndexes = newNumIndexes;
|
|
|
|
memset(inUse, 0, sizeof(inUse));
|
|
for (i = 0; i < decals->tri.numIndexes; i++) {
|
|
inUse[decals->tri.indexes[i]] = 1;
|
|
}
|
|
|
|
newNumVerts = 0;
|
|
for (i = 0; i < decals->tri.numVerts; i++) {
|
|
if (!inUse[i]) {
|
|
continue;
|
|
}
|
|
decals->tri.verts[newNumVerts] = decals->tri.verts[i];
|
|
decals->vertDepthFade[newNumVerts] = decals->vertDepthFade[i];
|
|
#ifdef QUAKE4
|
|
decals->vertLifeSpan[newNumVerts] = decals->vertLifeSpan[i];
|
|
#endif
|
|
inUse[i] = newNumVerts;
|
|
newNumVerts++;
|
|
}
|
|
decals->tri.numVerts = newNumVerts;
|
|
|
|
for (i = 0; i < decals->tri.numIndexes; i++) {
|
|
decals->tri.indexes[i] = inUse[decals->tri.indexes[i]];
|
|
}
|
|
|
|
return decals;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idRenderModelDecal::AddDecalDrawSurf
|
|
=====================
|
|
*/
|
|
void idRenderModelDecal::AddDecalDrawSurf(viewEntity_t* space) {
|
|
int i, j, maxTime;
|
|
float f;
|
|
decalInfo_t decalInfo;
|
|
|
|
|
|
if (tri.numIndexes == 0) {
|
|
return;
|
|
}
|
|
|
|
// fade down all the verts with time
|
|
decalInfo = material->GetDecalInfo();
|
|
#ifdef QUAKE4
|
|
maxTime = decalInfo.stayTime;
|
|
#else
|
|
maxTime = decalInfo.stayTime + decalInfo.fadeTime;
|
|
#endif
|
|
|
|
// set vertex colors and remove faded triangles
|
|
for (i = 0; i < tri.numIndexes; i += 3) {
|
|
#ifdef QUAKE4
|
|
float deltaTime = (float)tr.viewDef->renderView.time - indexStartTime[i];
|
|
|
|
if (deltaTime > maxTime) {
|
|
continue;
|
|
}
|
|
if (deltaTime < 0.0f) {
|
|
deltaTime = 0.0f;
|
|
}
|
|
|
|
f = (maxTime > 0) ? deltaTime / (float)maxTime : 1.0f;
|
|
for (j = 0; j < 3; j++) {
|
|
vertLifeSpan[tri.indexes[i + j]] = f;
|
|
}
|
|
#else
|
|
int deltaTime = tr.viewDef->renderView.time - indexStartTime[i];
|
|
|
|
if (deltaTime > maxTime) {
|
|
continue;
|
|
}
|
|
|
|
if (deltaTime <= decalInfo.stayTime) {
|
|
continue;
|
|
}
|
|
|
|
deltaTime -= decalInfo.stayTime;
|
|
f = (float)deltaTime / decalInfo.fadeTime;
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
int ind = tri.indexes[i + j];
|
|
|
|
for (int k = 0; k < 4; k++) {
|
|
float fcolor = decalInfo.start[k] + (decalInfo.end[k] - decalInfo.start[k]) * f;
|
|
int icolor = idMath::FtoiFast(fcolor * vertDepthFade[ind] * 255.0f);
|
|
if (icolor < 0) {
|
|
icolor = 0;
|
|
}
|
|
else if (icolor > 255) {
|
|
icolor = 255;
|
|
}
|
|
tri.verts[ind].color[k] = icolor;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
// Q4 stores decal age in vertLifeSpan. The material stage path can consume that
|
|
// when you wire Q4's stage-register/color-cache code in. Do not reference
|
|
// decalInfo.start/end here; Q4 decalInfo_t does not define those members.
|
|
#endif
|
|
|
|
// copy the tri and indexes to temp heap memory,
|
|
// because if we are running multi-threaded, we wouldn't
|
|
// be able to reorganize the index list
|
|
srfTriangles_t* newTri = (srfTriangles_t*)R_FrameAlloc(sizeof(*newTri));
|
|
*newTri = tri;
|
|
|
|
// copy the current vertexes to temp vertex cache
|
|
newTri->ambientCache = vertexCache.AllocFrameTemp(tri.verts, tri.numVerts * sizeof(idDrawVert));
|
|
|
|
// create the drawsurf
|
|
R_AddDrawSurf(newTri, space, &space->entityDef->parms, material, space->scissorRect);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idRenderModelDecal::ReadFromDemoFile
|
|
====================
|
|
*/
|
|
void idRenderModelDecal::ReadFromDemoFile(idDemoFile* f) {
|
|
// FIXME: implement
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idRenderModelDecal::WriteToDemoFile
|
|
====================
|
|
*/
|
|
void idRenderModelDecal::WriteToDemoFile(idDemoFile* f) const {
|
|
// FIXME: implement
|
|
}
|