#include "quakedef.h"
#include "image.h"
+#include "r_shadow.h"
// note: model_shared.c sets up r_notexture, and r_surf_notexture
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
-#define NUM_DETAILTEXTURES 1
-static rtexture_t *detailtextures[NUM_DETAILTEXTURES];
-static rtexturepool_t *detailtexturepool;
-
/*
===============
Mod_BrushInit
memset(mod_novis, 0xff, sizeof(mod_novis));
}
-void Mod_BrushStartup (void)
-{
- int i, x, y, light;
- float vc[3], vx[3], vy[3], vn[3], lightdir[3];
-#define DETAILRESOLUTION 256
- qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
- detailtexturepool = R_AllocTexturePool();
- lightdir[0] = 0.5;
- lightdir[1] = 1;
- lightdir[2] = -0.25;
- VectorNormalize(lightdir);
- for (i = 0;i < NUM_DETAILTEXTURES;i++)
- {
- fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
- for (y = 0;y < DETAILRESOLUTION;y++)
- {
- for (x = 0;x < DETAILRESOLUTION;x++)
- {
- vc[0] = x;
- vc[1] = y;
- vc[2] = noise[y][x] * (1.0f / 32.0f);
- vx[0] = x + 1;
- vx[1] = y;
- vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
- vy[0] = x;
- vy[1] = y + 1;
- vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
- VectorSubtract(vx, vc, vx);
- VectorSubtract(vy, vc, vy);
- CrossProduct(vx, vy, vn);
- VectorNormalize(vn);
- light = 128 - DotProduct(vn, lightdir) * 128;
- light = bound(0, light, 255);
- data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
- data[y][x][3] = 255;
- }
- }
- detailtextures[i] = R_LoadTexture2D(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
- }
-}
-
-void Mod_BrushShutdown (void)
-{
- int i;
- for (i = 0;i < NUM_DETAILTEXTURES;i++)
- R_FreeTexture(detailtextures[i]);
- R_FreeTexturePool(&detailtexturepool);
-}
-
/*
===============
Mod_PointInLeaf
dmiptexlump_t *m;
qbyte *data, *mtdata;
char name[256];
- qbyte *basepixels, *bumppixels, *nmappixels, *glosspixels, *glowpixels, *maskpixels;
- int basepixels_width, basepixels_height, bumppixels_width, bumppixels_height;
- int nmappixels_width, nmappixels_height, glosspixels_width, glosspixels_height;
- int glowpixels_width, glowpixels_height, maskpixels_width, maskpixels_height;
- rtexture_t *detailtexture;
loadmodel->textures = NULL;
for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
{
tx->number = i;
+ strcpy(tx->name, "NO TEXTURE FOUND");
tx->width = 16;
tx->height = 16;
- tx->texture = r_notexture;
+ tx->skin.base = r_notexture;
tx->shader = &Cshader_wall_lightmap;
+ tx->flags = SURF_SOLIDCLIP;
if (i == loadmodel->numtextures - 1)
{
- tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
+ tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
tx->shader = &Cshader_water;
}
tx->currentframe = tx;
Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
}
- basepixels = NULL;basepixels_width = 0;basepixels_height = 0;
- bumppixels = NULL;bumppixels_width = 0;bumppixels_height = 0;
- nmappixels = NULL;nmappixels_width = 0;nmappixels_height = 0;
- glosspixels = NULL;glosspixels_width = 0;glosspixels_height = 0;
- glowpixels = NULL;glowpixels_width = 0;glowpixels_height = 0;
- maskpixels = NULL;maskpixels_width = 0;maskpixels_height = 0;
- detailtexture = NULL;
-
// LordHavoc: HL sky textures are entirely different than quake
if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
{
}
else
{
- if ((basepixels = loadimagepixels(tx->name, false, 0, 0)) != NULL)
- {
- basepixels_width = image_width;
- basepixels_height = image_height;
- }
- // _luma is supported for tenebrae compatibility
- // (I think it's a very stupid name, but oh well)
- if ((glowpixels = loadimagepixels(va("%s_glow", tx->name), false, 0, 0)) != NULL
- || (glowpixels = loadimagepixels(va("%s_luma", tx->name), false, 0, 0)) != NULL)
- {
- glowpixels_width = image_width;
- glowpixels_height = image_height;
- }
- if ((bumppixels = loadimagepixels(va("%s_bump", tx->name), false, 0, 0)) != NULL)
- {
- bumppixels_width = image_width;
- bumppixels_height = image_height;
- }
- if ((glosspixels = loadimagepixels(va("%s_gloss", tx->name), false, 0, 0)) != NULL)
- {
- glosspixels_width = image_width;
- glosspixels_height = image_height;
- }
- if (!basepixels)
+ if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true))
{
+ // did not find external texture, load it from the bsp or wad3
if (loadmodel->ishlbsp)
{
// internal texture overrides wad
- if (mtdata && (basepixels = W_ConvertWAD3Texture(dmiptex)) != NULL)
+ qbyte *pixels, *freepixels;
+ pixels = freepixels = NULL;
+ if (mtdata)
+ pixels = W_ConvertWAD3Texture(dmiptex);
+ if (pixels == NULL)
+ pixels = freepixels = W_GetTexture(tx->name);
+ if (pixels != NULL)
{
- basepixels_width = image_width;
- basepixels_height = image_height;
+ tx->width = image_width;
+ tx->height = image_height;
+ tx->skin.base = tx->skin.merged = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
}
- else if ((basepixels = W_GetTexture(tx->name)) != NULL)
- {
- // get the size from the wad texture
- tx->width = basepixels_width = image_width;
- tx->height = basepixels_height = image_height;
- }
- }
- else
- {
- if (mtdata) // texture included
- {
- if (r_fullbrights.integer && tx->name[0] != '*')
- {
- basepixels_width = tx->width;
- basepixels_height = tx->height;
- basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
- Image_Copy8bitRGBA(mtdata, basepixels, basepixels_width * basepixels_height, palette_nofullbrights);
- if (!glowpixels)
- {
- for (j = 0;j < (int)(tx->width*tx->height);j++)
- if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright
- break;
- if (j < (int)(tx->width * tx->height))
- {
- glowpixels_width = tx->width;
- glowpixels_height = tx->height;
- glowpixels = Mem_Alloc(loadmodel->mempool, glowpixels_width * glowpixels_height * 4);
- Image_Copy8bitRGBA(mtdata, glowpixels, glowpixels_width * glowpixels_height, palette_onlyfullbrights);
- }
- }
- }
- else
- {
- basepixels_width = tx->width;
- basepixels_height = tx->height;
- basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
- Image_Copy8bitRGBA(mtdata, basepixels, tx->width * tx->height, palette_complete);
- }
- }
- }
- }
- }
-
- if (basepixels)
- {
- for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
- if (basepixels[j] < 255)
- break;
- if (j < basepixels_width * basepixels_height * 4)
- {
- maskpixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
- maskpixels_width = basepixels_width;
- maskpixels_height = basepixels_height;
- for (j = 0;j < basepixels_width * basepixels_height * 4;j += 4)
- {
- maskpixels[j+0] = 255;
- maskpixels[j+1] = 255;
- maskpixels[j+2] = 255;
- maskpixels[j+3] = basepixels[j+3];
+ if (freepixels)
+ Mem_Free(freepixels);
}
- }
-
- if (!bumppixels)
- {
- bumppixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
- bumppixels_width = basepixels_width;
- bumppixels_height = basepixels_height;
- memcpy(bumppixels, basepixels, bumppixels_width * bumppixels_height * 4);
- }
-
- if (!nmappixels && bumppixels)
- {
- nmappixels = Mem_Alloc(loadmodel->mempool, bumppixels_width * bumppixels_height * 4);
- nmappixels_width = bumppixels_width;
- nmappixels_height = bumppixels_height;
- Image_HeightmapToNormalmap(bumppixels, nmappixels, nmappixels_width, nmappixels_height, false, 1);
+ else if (mtdata) // texture included
+ Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
}
}
-
- if (!detailtexture)
- detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
-
- if (basepixels)
- {
- tx->texture = R_LoadTexture2D (loadmodel->texturepool, tx->name, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
- if (nmappixels)
- tx->nmaptexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_nmap", tx->name), basepixels_width, basepixels_height, nmappixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
- if (glosspixels)
- tx->glosstexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_gloss", tx->name), glosspixels_width, glosspixels_height, glosspixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
- if (glowpixels)
- tx->glowtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_glow", tx->name), glowpixels_width, glowpixels_height, glowpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
- if (maskpixels)
- tx->fogtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_mask", tx->name), maskpixels_width, maskpixels_height, maskpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
- tx->detailtexture = detailtexture;
- }
- else
+ if (tx->skin.base == NULL)
{
// no texture found
tx->width = 16;
tx->height = 16;
- tx->texture = r_notexture;
- tx->nmaptexture = NULL;
- tx->glosstexture = NULL;
- tx->glowtexture = NULL;
- tx->fogtexture = NULL;
- tx->detailtexture = NULL;
- }
-
- if (basepixels)
- Mem_Free(basepixels);
- if (bumppixels)
- Mem_Free(bumppixels);
- if (nmappixels)
- Mem_Free(nmappixels);
- if (glosspixels)
- Mem_Free(glosspixels);
- if (glowpixels)
- Mem_Free(glowpixels);
- if (maskpixels)
- Mem_Free(maskpixels);
+ tx->skin.base = r_notexture;
+ }
if (tx->name[0] == '*')
{
+ // turb does not block movement
+ tx->flags &= ~SURF_SOLIDCLIP;
tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
// LordHavoc: some turbulent textures should be fullbright and solid
if (!strncmp(tx->name,"*lava",5)
else
{
tx->flags |= SURF_LIGHTMAP;
- if (!tx->fogtexture)
+ if (!tx->skin.fog)
tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
tx->shader = &Cshader_wall_lightmap;
}
i = LittleLong(((int *)data)[1]);
if (i == 1)
{
- Con_DPrintf("%s loaded", litfilename);
+ Con_DPrintf("loaded %s\n", litfilename);
loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
Mem_Free(data);
}
}
-/*
-================
-CalcSurfaceExtents
-
-Fills in s->texturemins[] and s->extents[]
-================
-*/
-static void CalcSurfaceExtents (msurface_t *s)
-{
- float mins[2], maxs[2], val;
- int i,j, e;
- mvertex_t *v;
- mtexinfo_t *tex;
- int bmins[2], bmaxs[2];
-
- mins[0] = mins[1] = 999999999;
- maxs[0] = maxs[1] = -999999999;
-
- tex = s->texinfo;
-
- for (i=0 ; i<s->numedges ; i++)
- {
- e = loadmodel->surfedges[s->firstedge+i];
- if (e >= 0)
- v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
- else
- v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
-
- for (j=0 ; j<2 ; j++)
- {
- val = v->position[0] * tex->vecs[j][0] +
- v->position[1] * tex->vecs[j][1] +
- v->position[2] * tex->vecs[j][2] +
- tex->vecs[j][3];
- if (val < mins[j])
- mins[j] = val;
- if (val > maxs[j])
- maxs[j] = val;
- }
- }
-
- for (i=0 ; i<2 ; i++)
- {
- bmins[i] = floor(mins[i]/16);
- bmaxs[i] = ceil(maxs[i]/16);
-
- s->texturemins[i] = bmins[i] * 16;
- s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
- }
-}
-
-
void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
{
int i, j;
Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
}
-void Mod_GenerateSurfacePolygon (msurface_t *surf)
+void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
{
- int i, lindex;
- float *vec, *vert, mins[3], maxs[3];
+ int i, lindex, j;
+ float *vec, *vert, mins[3], maxs[3], val, *v;
+ mtexinfo_t *tex;
// convert edges back to a normal polygon
- surf->poly_numverts = surf->numedges;
- vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
- for (i = 0;i < surf->numedges;i++)
+ surf->poly_numverts = numedges;
+ vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
+ for (i = 0;i < numedges;i++)
{
- lindex = loadmodel->surfedges[surf->firstedge + i];
+ lindex = loadmodel->surfedges[firstedge + i];
if (lindex > 0)
vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
else
VectorCopy (vec, vert);
vert += 3;
}
+
+ // calculate polygon bounding box and center
vert = surf->poly_verts;
VectorCopy(vert, mins);
VectorCopy(vert, maxs);
surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
+
+ // generate surface extents information
+ tex = surf->texinfo;
+ mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
+ mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
+ for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
+ {
+ for (j = 0;j < 2;j++)
+ {
+ val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
+ if (mins[j] > val)
+ mins[j] = val;
+ if (maxs[j] < val)
+ maxs[j] = val;
+ }
+ }
+ for (i = 0;i < 2;i++)
+ {
+ surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
+ surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
+ }
}
/*
{
dface_t *in;
msurface_t *out;
- int i, count, surfnum, planenum, ssize, tsize;
+ int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
{
out->number = surfnum;
// FIXME: validate edges, texinfo, etc?
- out->firstedge = LittleLong(in->firstedge);
- out->numedges = LittleShort(in->numedges);
- if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
- Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
+ firstedge = LittleLong(in->firstedge);
+ numedges = LittleShort(in->numedges);
+ if ((unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
+ Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
i = LittleShort (in->texinfo);
if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
// force lightmap upload on first time seeing the surface
out->cached_dlight = true;
- CalcSurfaceExtents (out);
+ Mod_GenerateSurfacePolygon(out, firstedge, numedges);
ssize = (out->extents[0] >> 4) + 1;
tsize = (out->extents[1] >> 4) + 1;
else // LordHavoc: white lighting (bsp version 29)
out->samples = loadmodel->lightdata + (i * 3);
- Mod_GenerateSurfacePolygon(out);
if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
{
if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
extern void R_Model_Brush_DrawSky(entity_render_t *ent);
extern void R_Model_Brush_Draw(entity_render_t *ent);
extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
+extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
void Mod_LoadBrushModel (model_t *mod, void *buffer)
{
- int i, j;
- dheader_t *header;
- dmodel_t *bm;
- mempool_t *mainmempool;
- char *loadname;
- model_t *originalloadmodel;
+ int i, j, k;
+ dheader_t *header;
+ dmodel_t *bm;
+ mempool_t *mainmempool;
+ char *loadname;
+ model_t *originalloadmodel;
+ float dist, modelyawradius, modelradius, *vec;
+ msurface_t *surf;
+ surfmesh_t *mesh;
mod->type = mod_brush;
//
for (i = 0;i < mod->numsubmodels;i++)
{
- int k, l;
- float dist, modelyawradius, modelradius, *vec;
- msurface_t *surf;
-
bm = &mod->submodels[i];
mod->hulls[0].firstclipnode = bm->headnode[0];
// we only need to have a drawsky function if it is used (usually only on world model)
if (surf->texinfo->texture->shader == &Cshader_sky)
mod->DrawSky = R_Model_Brush_DrawSky;
+ // LordHavoc: submodels always clip, even if water
+ if (mod->numsubmodels - 1)
+ surf->flags |= SURF_SOLIDCLIP;
// calculate bounding shapes
- for (k = 0;k < surf->numedges;k++)
+ for (mesh = surf->mesh;mesh;mesh = mesh->chain)
{
- l = mod->surfedges[k + surf->firstedge];
- if (l > 0)
- vec = mod->vertexes[mod->edges[l].v[0]].position;
- else
- vec = mod->vertexes[mod->edges[-l].v[1]].position;
- if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
- if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
- if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
- if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
- if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
- if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
- dist = vec[0]*vec[0]+vec[1]*vec[1];
- if (modelyawradius < dist)
- modelyawradius = dist;
- dist += vec[2]*vec[2];
- if (modelradius < dist)
- modelradius = dist;
+ for (k = 0, vec = mesh->verts;k < mesh->numverts;k++, vec += 4)
+ {
+ if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
+ if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
+ if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
+ if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
+ if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
+ if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
+ dist = vec[0]*vec[0]+vec[1]*vec[1];
+ if (modelyawradius < dist)
+ modelyawradius = dist;
+ dist += vec[2]*vec[2];
+ if (modelradius < dist)
+ modelradius = dist;
+ }
}
}
modelyawradius = sqrt(modelyawradius);