#include "qbsp.h"
int32_t nummiptex;
textureref_t textureref[MAX_MAP_TEXTURES];
int32_t FindMiptex(char *name) {
int32_t i, mod_fail;
char path[1080];
char pakpath[56];
miptex_t *mt;
for (i = 0; i < nummiptex; i++)
if (!strcmp(name, textureref[i].name)) {
return i;
}
if (nummiptex == MAX_MAP_TEXTURES)
Error("MAX_MAP_TEXTURES");
strcpy(textureref[i].name, name);
mod_fail = true;
sprintf(pakpath, "textures/%s.wal", name);
if (moddir[0] != 0) {
sprintf(path, "%s%s", moddir, pakpath);
if (TryLoadFile(path, (void **)&mt, false) != -1 ||
TryLoadFileFromPak(pakpath, (void **)&mt, moddir) != -1) {
textureref[i].value = LittleLong(mt->value);
textureref[i].flags = LittleLong(mt->flags);
textureref[i].contents = LittleLong(mt->contents);
strcpy(textureref[i].animname, mt->animname);
free(mt);
mod_fail = false;
}
}
if (mod_fail) {
sprintf(path, "%s%s", basedir, pakpath);
if (TryLoadFile(path, (void **)&mt, false) != -1 ||
TryLoadFileFromPak(pakpath, (void **)&mt, basedir) != -1) {
textureref[i].value = LittleLong(mt->value);
textureref[i].flags = LittleLong(mt->flags);
textureref[i].contents = LittleLong(mt->contents);
strcpy(textureref[i].animname, mt->animname);
free(mt);
mod_fail = false;
}
}
if (mod_fail)
printf("WARNING: couldn't locate texture %s\n", name);
nummiptex++;
if (textureref[i].animname[0])
FindMiptex(textureref[i].animname);
return i;
}
vec3_t baseaxis[18] =
{
{0, 0, 1}, {1, 0, 0}, {0, -1, 0}, {0, 0, -1},
{1, 0, 0},
{0, -1, 0}, {1, 0, 0},
{0, 1, 0},
{0, 0, -1}, {-1, 0, 0},
{0, 1, 0},
{0, 0, -1}, {0, 1, 0},
{1, 0, 0},
{0, 0, -1}, {0, -1, 0},
{1, 0, 0},
{0, 0, -1} };
void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) {
int32_t bestaxis;
vec_t dot, best;
int32_t i;
best = 0;
bestaxis = 0;
for (i = 0; i < 6; i++) {
dot = DotProduct(pln->normal, baseaxis[i * 3]);
if (dot > best) {
best = dot;
bestaxis = i;
}
}
VectorCopy(baseaxis[bestaxis * 3 + 1], xv);
VectorCopy(baseaxis[bestaxis * 3 + 2], yv);
}
static inline void CheckTexinfoCount() {
if (use_qbsp) {
if (numtexinfo == MAX_MAP_TEXINFO_QBSP)
printf("WARNING: texinfo count exceeds qbsp limit (%i).\n", MAX_MAP_TEXINFO_QBSP);
} else if (numtexinfo == DEFAULT_MAP_TEXINFO)
printf("WARNING: texinfo count exceeds vanilla limit (%i).\n", DEFAULT_MAP_TEXINFO);
else if (numtexinfo >= MAX_MAP_TEXINFO)
Error("ERROR: texinfo count exceeds extended limit (%i).\n", MAX_MAP_TEXINFO);
}
qboolean TexinfosMatch(texinfo_t t1, texinfo_t t2) {
if (t1.flags != t2.flags || t1.value != t2.value || strcmp(t1.texture, t2.texture))
return false;
for (int32_t j = 0; j < 2; j++)
for (int32_t k = 0; k < 4; k++)
if ((int32_t)(t1.vecs[j][k] * 100) != (int32_t)(t2.vecs[j][k] * 100)) return false;
return true;
}
int32_t ApplyTexinfoOffset_UV(int32_t texinfoindex, const brush_texture_t *bt, const vec3_t origin) {
if ((!origin[0] && !origin[1] && !origin[2]) || texinfoindex < 0)
return texinfoindex;
const texinfo_t otx = texinfo[texinfoindex];
texinfo_t tx;
memcpy(&tx, &otx, sizeof(tx));
tx.vecs[0][3] += origin[0] * tx.vecs[0][0] + origin[1] * tx.vecs[0][1] + origin[2] * tx.vecs[0][2];
tx.vecs[1][3] += origin[0] * tx.vecs[1][0] + origin[1] * tx.vecs[1][1] + origin[2] * tx.vecs[1][2];
texinfo_t *tc = texinfo;
for (texinfoindex = 0; texinfoindex < numtexinfo; texinfoindex++, tc++)
if (TexinfosMatch(*tc, tx))
return texinfoindex;
*tc = tx;
numtexinfo++;
CheckTexinfoCount();
const int32_t mt = FindMiptex(tx.texture);
if (textureref[mt].animname[0]) {
brush_texture_t anim = *bt;
strcpy(anim.name, textureref[mt].animname);
tc->nexttexinfo = ApplyTexinfoOffset_UV(tc->nexttexinfo, &anim, origin);
} else {
tc->nexttexinfo = -1;
}
return texinfoindex;
}
int32_t TexinfoForBrushTexture_UV(brush_texture_t *bt, vec_t *UVaxis) {
if (!bt->name[0])
return 0;
texinfo_t tx;
memset(&tx, 0, sizeof(tx));
strcpy(tx.texture, bt->name);
if (!bt->scale[0])
bt->scale[0] = 1;
if (!bt->scale[1])
bt->scale[1] = 1;
for (int32_t i = 0; i < 2; i++)
for (int32_t j = 0; j < 3; j++)
tx.vecs[i][j] = UVaxis[i * 3 + j] / bt->scale[i];
tx.vecs[0][3] = bt->shift[0];
tx.vecs[1][3] = bt->shift[1];
tx.flags = bt->flags;
tx.value = bt->value;
int32_t texinfoindex;
texinfo_t *tc = texinfo;
for (texinfoindex = 0; texinfoindex < numtexinfo; texinfoindex++, tc++)
if (TexinfosMatch(*tc, tx))
return texinfoindex;
*tc = tx;
numtexinfo++;
CheckTexinfoCount();
const int32_t mt = FindMiptex(bt->name);
if (textureref[mt].animname[0]) {
brush_texture_t anim = *bt;
strcpy(anim.name, textureref[mt].animname);
tc->nexttexinfo = TexinfoForBrushTexture_UV(&anim, UVaxis);
} else
tc->nexttexinfo = -1;
return texinfoindex;
}
extern qboolean origfix;
int32_t TexinfoForBrushTexture(plane_t *plane, brush_texture_t *bt, vec3_t origin) {
if (!bt->name[0])
return 0;
texinfo_t tx;
memset(&tx, 0, sizeof(tx));
strcpy(tx.texture, bt->name);
vec3_t vecs[2];
TextureAxisFromPlane(plane, vecs[0], vecs[1]);
if (!bt->scale[0])
bt->scale[0] = 1;
if (!bt->scale[1])
bt->scale[1] = 1;
float shift[2];
vec3_t scaled_origin;
if (origfix) {
VectorScale(origin, 1.0 / bt->scale[0], scaled_origin);
shift[0] = DotProduct(scaled_origin, vecs[0]);
VectorScale(origin, 1.0 / bt->scale[1], scaled_origin);
shift[1] = DotProduct(scaled_origin, vecs[1]);
} else {
shift[0] = DotProduct(origin, vecs[0]);
shift[1] = DotProduct(origin, vecs[1]);
}
vec_t sinv, cosv;
if (bt->rotate == 0) {
sinv = 0;
cosv = 1;
} else if (bt->rotate == 90) {
sinv = 1;
cosv = 0;
} else if (bt->rotate == 180) {
sinv = 0;
cosv = -1;
} else if (bt->rotate == 270) {
sinv = -1;
cosv = 0;
} else {
const vec_t ang = bt->rotate / 180 * Q_PI;
sinv = sin(ang);
cosv = cos(ang);
}
if (origfix) {
const vec_t ns = cosv * shift[0] - sinv * shift[1];
const vec_t nt = sinv * shift[0] + cosv * shift[1];
shift[0] = ns;
shift[1] = nt;
}
int32_t sv, tv;
if (vecs[0][0])
sv = 0;
else if (vecs[0][1])
sv = 1;
else
sv = 2;
if (vecs[1][0])
tv = 0;
else if (vecs[1][1])
tv = 1;
else
tv = 2;
for (int32_t i = 0; i < 2; i++) {
const vec_t ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
const vec_t nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
vecs[i][sv] = ns;
vecs[i][tv] = nt;
}
for (int32_t i = 0; i < 2; i++)
for (int32_t j = 0; j < 3; j++)
tx.vecs[i][j] = vecs[i][j] / bt->scale[i];
tx.vecs[0][3] = bt->shift[0] + shift[0];
tx.vecs[1][3] = bt->shift[1] + shift[1];
tx.flags = bt->flags;
tx.value = bt->value;
int32_t texinfoindex;
texinfo_t *tc = texinfo;
for (texinfoindex = 0; texinfoindex < numtexinfo; texinfoindex++, tc++)
if (TexinfosMatch(*tc, tx))
return texinfoindex;
*tc = tx;
numtexinfo++;
CheckTexinfoCount();
const int32_t mt = FindMiptex(bt->name);
if (textureref[mt].animname[0]) {
brush_texture_t anim = *bt;
strcpy(anim.name, textureref[mt].animname);
tc->nexttexinfo = TexinfoForBrushTexture(plane, &anim, origin);
} else
tc->nexttexinfo = -1;
return texinfoindex;
}