X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=model_brush.c;h=c003fb2c5f3228311ab9979b0d87a34cf6361836;hb=01179863ff1eb63c5ff88c7019f9b3869ecbf2ff;hp=feab7d7e0e7817821874eb211da7e09e99047b46;hpb=a2e8c929d9b76eef30ee136154bbdadbe504092c;p=xonotic%2Fdarkplaces.git diff --git a/model_brush.c b/model_brush.c index feab7d7e..c003fb2c 100644 --- a/model_brush.c +++ b/model_brush.c @@ -19,18 +19,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "image.h" // note: model_shared.c sets up r_notexture, and r_surf_notexture qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8]; -cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"}; +//cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"}; cvar_t halflifebsp = {0, "halflifebsp", "0"}; cvar_t r_novis = {0, "r_novis", "0"}; cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"}; cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"}; -cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "0"}; 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; /* =============== @@ -39,19 +44,63 @@ Mod_BrushInit */ void Mod_BrushInit (void) { - Cvar_RegisterVariable(&r_subdivide_size); +// Cvar_RegisterVariable(&r_subdivide_size); Cvar_RegisterVariable(&halflifebsp); Cvar_RegisterVariable(&r_novis); Cvar_RegisterVariable(&r_miplightmaps); Cvar_RegisterVariable(&r_lightmaprgba); - Cvar_RegisterVariable(&r_vertexsurfacesthreshold); Cvar_RegisterVariable(&r_nosurftextures); + Cvar_RegisterVariable(&r_sortsurfaces); memset(mod_novis, 0xff, sizeof(mod_novis)); } -void Mod_Brush_SERAddEntity(void) +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) { - R_Clip_AddBox(currentrenderentity->mins, currentrenderentity->maxs, R_Entity_Callback, currentrenderentity, NULL); + int i; + for (i = 0;i < NUM_DETAILTEXTURES;i++) + R_FreeTexture(detailtextures[i]); + R_FreeTexturePool(&detailtexturepool); } /* @@ -59,9 +108,12 @@ void Mod_Brush_SERAddEntity(void) Mod_PointInLeaf =============== */ -mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) { - mnode_t *node; + mnode_t *node; + + if (model == NULL) + return NULL; Mod_CheckLoaded(model); @@ -74,17 +126,35 @@ mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) return (mleaf_t *)node; } +int Mod_PointContents (const vec3_t p, model_t *model) +{ + mnode_t *node; + + if (model == NULL) + return CONTENTS_EMPTY; + + Mod_CheckLoaded(model); + + // LordHavoc: modified to start at first clip node, + // in other words: first node of the (sub)model + node = model->nodes + model->hulls[0].firstclipnode; + while (node->contents == 0) + node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist]; + + return ((mleaf_t *)node)->contents; +} + void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod) { - if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[0]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[0]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; + if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; + pos[0]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; + pos[0]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; pos[0]-=1; - pos[1]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[1]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; + pos[1]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; + pos[1]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; pos[1]-=1; - pos[2]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[2]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; + pos[2]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; + pos[2]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; pos[2]-=1; } @@ -142,8 +212,13 @@ static void Mod_LoadTextures (lump_t *l) miptex_t *dmiptex; texture_t *tx, *tx2, *anims[10], *altanims[10]; dmiptexlump_t *m; - qbyte *data, *mtdata, *data2; + 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; @@ -156,17 +231,20 @@ static void Mod_LoadTextures (lump_t *l) // add two slots for notexture walls and notexture liquids loadmodel->numtextures = m->nummiptex + 2; - loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(*loadmodel->textures)); + loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t)); // fill out all slots with notexture - for (i = 0;i < loadmodel->numtextures;i++) + for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++) { - loadmodel->textures[i] = tx = Mem_Alloc(loadmodel->mempool, sizeof(texture_t)); tx->width = 16; tx->height = 16; tx->texture = r_notexture; + tx->shader = &Cshader_wall_lightmap; if (i == loadmodel->numtextures - 1) - tx->flags = SURF_DRAWTURB | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID; + { + tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES; + tx->shader = &Cshader_water; + } } // just to work around bounds checking when debugging with it (array index out of bounds error thing) @@ -207,13 +285,10 @@ static void Mod_LoadTextures (lump_t *l) if (name[j] >= 'A' && name[j] <= 'Z') name[j] += 'a' - 'A'; - tx = loadmodel->textures[i]; + tx = loadmodel->textures + i; strcpy(tx->name, name); tx->width = mtwidth; tx->height = mtheight; - tx->texture = NULL; - tx->glowtexture = NULL; - tx->fogtexture = NULL; if (!tx->name[0]) { @@ -221,6 +296,14 @@ static void Mod_LoadTextures (lump_t *l) 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) { @@ -246,122 +329,195 @@ static void Mod_LoadTextures (lump_t *l) R_InitSky (mtdata, 1); } } - else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true))) - { - tx->fogtexture = image_masktex; - strcpy(name, tx->name); - strcat(name, "_glow"); - tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true); - } else { - if (loadmodel->ishlbsp) + 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) { - if (mtdata && (data = W_ConvertWAD3Texture(dmiptex))) + 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 (loadmodel->ishlbsp) { - // texture included - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); - if (R_TextureHasAlpha(tx->texture)) + // internal texture overrides wad + if (mtdata && (basepixels = W_ConvertWAD3Texture(dmiptex)) != NULL) { - // make mask texture - for (j = 0;j < image_width * image_height;j++) - data[j*4+0] = data[j*4+1] = data[j*4+2] = 255; - strcpy(name, tx->name); - strcat(name, "_fog"); - tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); + basepixels_width = image_width; + basepixels_height = image_height; } - Mem_Free(data); - } - else if ((data = W_GetTexture(tx->name))) - { - // get the size from the wad texture - tx->width = image_width; - tx->height = image_height; - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); - if (R_TextureHasAlpha(tx->texture)) + else if ((basepixels = W_GetTexture(tx->name)) != NULL) { - // make mask texture - for (j = 0;j < image_width * image_height;j++) - data[j*4+0] = data[j*4+1] = data[j*4+2] = 255; - strcpy(name, tx->name); - strcat(name, "_fog"); - tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); + // get the size from the wad texture + tx->width = basepixels_width = image_width; + tx->height = basepixels_height = image_height; } - Mem_Free(data); } else { - tx->width = 16; - tx->height = 16; - tx->texture = r_notexture; - } - } - else - { - if (mtdata) // texture included - { - int fullbrights; - data = mtdata; - fullbrights = false; - if (r_fullbrights.value && tx->name[0] != '*') + if (mtdata) // texture included { - for (j = 0;j < tx->width*tx->height;j++) + if (r_fullbrights.integer && tx->name[0] != '*') { - if (data[j] >= 224) // fullbright + 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) { - fullbrights = true; - break; + 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 (fullbrights) - { - data2 = Mem_Alloc(loadmodel->mempool, tx->width*tx->height); - for (j = 0;j < tx->width*tx->height;j++) - data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE); - strcpy(name, tx->name); - strcat(name, "_glow"); - for (j = 0;j < tx->width*tx->height;j++) - data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights - tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE); - Mem_Free(data2); - } - else - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE); } - else // no texture, and no external replacement texture was found + } + } + + 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) { - tx->width = 16; - tx->height = 16; - tx->texture = r_notexture; + maskpixels[j+0] = 255; + maskpixels[j+1] = 255; + maskpixels[j+2] = 255; + maskpixels[j+3] = basepixels[j+3]; } } + + 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); + } } + 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 + { + // 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); + if (tx->name[0] == '*') { - tx->flags |= (SURF_DRAWTURB | SURF_LIGHTBOTHSIDES); + tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES; // LordHavoc: some turbulent textures should be fullbright and solid if (!strncmp(tx->name,"*lava",5) || !strncmp(tx->name,"*teleport",9) || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture - tx->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID); + tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA; + else + tx->flags |= SURF_WATERALPHA; + tx->shader = &Cshader_water; } else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y') - tx->flags |= (SURF_DRAWSKY | SURF_CLIPSOLID); + { + tx->flags |= SURF_DRAWSKY; + tx->shader = &Cshader_sky; + } else { tx->flags |= SURF_LIGHTMAP; - if (!R_TextureHasAlpha(tx->texture)) - tx->flags |= SURF_CLIPSOLID; + if (!tx->fogtexture) + tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT; + tx->shader = &Cshader_wall_lightmap; } + + // start out with no animation + tx->currentframe = tx; } // sequence the animations for (i = 0;i < m->nummiptex;i++) { - tx = loadmodel->textures[i]; + tx = loadmodel->textures + i; if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0) continue; if (tx->anim_total[0] || tx->anim_total[1]) @@ -373,7 +529,7 @@ static void Mod_LoadTextures (lump_t *l) for (j = i;j < m->nummiptex;j++) { - tx2 = loadmodel->textures[j]; + tx2 = loadmodel->textures + j; if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2)) continue; @@ -573,7 +729,7 @@ void Mod_LoadLightList(void) if (a != 14) { Mem_Free(lightsstring); - Host_Error("invalid lights file, found %d parameters on line %i, should be 13 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone style)\n", a, n + 1); + Host_Error("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1); } s++; n++; @@ -588,6 +744,264 @@ void Mod_LoadLightList(void) } } +/* +static int castshadowcount = 0; +void Mod_ProcessLightList(void) +{ + int j, k, l, *mark, lnum; + mlight_t *e; + msurface_t *surf; + float dist; + mleaf_t *leaf; + qbyte *pvs; + vec3_t temp; + float *v, radius2; + for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++) + { + e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f; + if (e->cullradius2 > 4096.0f * 4096.0f) + e->cullradius2 = 4096.0f * 4096.0f; + e->cullradius = e->lightradius = sqrt(e->cullradius2); + leaf = Mod_PointInLeaf(e->origin, loadmodel); + if (leaf->compressed_vis) + pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel); + else + pvs = mod_novis; + for (j = 0;j < loadmodel->numsurfaces;j++) + loadmodel->surfacevisframes[j] = -1; + for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++) + { + if (pvs[j >> 3] & (1 << (j & 7))) + { + for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++) + { + surf = loadmodel->surfaces + *mark; + if (surf->number != *mark) + Con_Printf("%d != %d\n", surf->number, *mark); + dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + dist = -dist; + if (dist > 0 && dist < e->cullradius) + { + temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0]; + temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1]; + temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2]; + if (DotProduct(temp, temp) < lightradius2) + loadmodel->surfacevisframes[*mark] = -2; + } + } + } + } + // build list of light receiving surfaces + e->numsurfaces = 0; + for (j = 0;j < loadmodel->numsurfaces;j++) + if (loadmodel->surfacevisframes[j] == -2) + e->numsurfaces++; + e->surfaces = NULL; + if (e->numsurfaces > 0) + { + e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces); + e->numsurfaces = 0; + for (j = 0;j < loadmodel->numsurfaces;j++) + if (loadmodel->surfacevisframes[j] == -2) + e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j; + } + // find bounding box and sphere of lit surfaces + // (these will be used for creating a shape to clip the light) + radius2 = 0; + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (j == 0) + { + VectorCopy(surf->poly_verts, e->mins); + VectorCopy(surf->poly_verts, e->maxs); + } + for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3) + { + if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0]; + if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1]; + if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2]; + VectorSubtract(v, e->origin, temp); + dist = DotProduct(temp, temp); + if (radius2 < dist) + radius2 = dist; + } + } + if (e->cullradius2 > radius2) + { + e->cullradius2 = radius2; + e->cullradius = sqrt(e->cullradius2); + } + if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius; + if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius; + if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius; + if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius; + if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius; + if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius; + // clip shadow volumes against eachother to remove unnecessary + // polygons (and sections of polygons) + { + //vec3_t polymins, polymaxs; + int maxverts = 4; + float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + float f, *v0, *v1, projectdistance; + + e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024); +#if 0 + { + vec3_t outermins, outermaxs, innermins, innermaxs; + innermins[0] = e->mins[0] - 1; + innermins[1] = e->mins[1] - 1; + innermins[2] = e->mins[2] - 1; + innermaxs[0] = e->maxs[0] + 1; + innermaxs[1] = e->maxs[1] + 1; + innermaxs[2] = e->maxs[2] + 1; + outermins[0] = loadmodel->normalmins[0] - 1; + outermins[1] = loadmodel->normalmins[1] - 1; + outermins[2] = loadmodel->normalmins[2] - 1; + outermaxs[0] = loadmodel->normalmaxs[0] + 1; + outermaxs[1] = loadmodel->normalmaxs[1] + 1; + outermaxs[2] = loadmodel->normalmaxs[2] + 1; + // add bounding box around the whole shadow volume set, + // facing inward to limit light area, with an outer bounding box + // facing outward (this is needed by the shadow rendering method) + // X major + verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; + verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; + verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // X minor + verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Y major + verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Y minor + verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Z major + verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2]; + verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2]; + verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2]; + verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2]; + verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Z minor + verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + } +#endif + castshadowcount++; + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (surf->flags & SURF_SHADOWCAST) + surf->castshadow = castshadowcount; + } + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (surf->castshadow != castshadowcount) + continue; + f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + f = -f; + projectdistance = e->lightradius; + if (maxverts < surf->poly_numverts) + { + maxverts = surf->poly_numverts; + if (verts) + Mem_Free(verts); + verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + } + // copy the original polygon, for the front cap of the volume + for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3) + VectorCopy(v0, v1); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts); + // project the original polygon, reversed, for the back cap of the volume + for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3) + { + VectorSubtract(v0, e->origin, temp); + VectorNormalize(temp); + VectorMA(v0, projectdistance, temp, v1); + } + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts); + // project the shadow volume sides + for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3) + { + if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount) + { + VectorCopy(v1, &verts[0]); + VectorCopy(v0, &verts[3]); + VectorCopy(v0, &verts[6]); + VectorCopy(v1, &verts[9]); + VectorSubtract(&verts[6], e->origin, temp); + VectorNormalize(temp); + VectorMA(&verts[6], projectdistance, temp, &verts[6]); + VectorSubtract(&verts[9], e->origin, temp); + VectorNormalize(temp); + VectorMA(&verts[9], projectdistance, temp, &verts[9]); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + } + } + } + // build the triangle mesh + e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume); + { + shadowmesh_t *mesh; + l = 0; + for (mesh = e->shadowvolume;mesh;mesh = mesh->next) + l += mesh->numtriangles; + Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l); + } + } + } +} +*/ + /* ================= @@ -604,22 +1018,20 @@ static void Mod_LoadVisibility (lump_t *l) } // used only for HalfLife maps -void Mod_ParseWadsFromEntityLump(char *data) +void Mod_ParseWadsFromEntityLump(const char *data) { char key[128], value[4096]; char wadname[128]; int i, j, k; if (!data) return; - data = COM_Parse(data); - if (!data) + if (!COM_ParseToken(&data)) return; // error if (com_token[0] != '{') return; // error while (1) { - data = COM_Parse(data); - if (!data) + if (!COM_ParseToken(&data)) return; // error if (com_token[0] == '}') break; // end of worldspawn @@ -629,8 +1041,7 @@ void Mod_ParseWadsFromEntityLump(char *data) strcpy(key, com_token); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; - data = COM_Parse(data); - if (!data) + if (!COM_ParseToken(&data)) return; // error strcpy(value, com_token); if (!strcmp("wad", key)) // for HalfLife maps @@ -810,15 +1221,20 @@ static void Mod_LoadTexinfo (lump_t *l) if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures) Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures); else - out->texture = loadmodel->textures[miptex]; + out->texture = loadmodel->textures + miptex; } - if (out->texture == NULL) + if (out->flags & TEX_SPECIAL) { - // choose either the liquid notexture, or the normal notexture - if (out->flags & TEX_SPECIAL) - out->texture = loadmodel->textures[loadmodel->numtextures - 1]; - else - out->texture = loadmodel->textures[loadmodel->numtextures - 2]; + // if texture chosen is NULL or the shader needs a lightmap, + // force to notexture water shader + if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP) + out->texture = loadmodel->textures + (loadmodel->numtextures - 1); + } + else + { + // if texture chosen is NULL, force to notexture + if (out->texture == NULL) + out->texture = loadmodel->textures + (loadmodel->numtextures - 2); } } } @@ -895,6 +1311,7 @@ void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) } } +#if 0 #define MAX_SUBDIVPOLYTRIANGLES 4096 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3) @@ -1030,90 +1447,64 @@ void Mod_GenerateWarpMesh (msurface_t *surf) v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]); } } +#endif -void Mod_GenerateVertexLitMesh (msurface_t *surf) +surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles) { - int i, is, it, *index, smax, tmax; - float *in, s, t; - surfvertex_t *out; - surfmesh_t *mesh; - - smax = surf->extents[0] >> 4; - tmax = surf->extents[1] >> 4; - surf->lightmaptexturestride = 0; - surf->lightmaptexture = NULL; - - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->vertex = (surfvertex_t *)(mesh + 1); - mesh->index = (int *)(mesh->vertex + mesh->numverts); - memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t)); - - index = mesh->index; - for (i = 0;i < mesh->numtriangles;i++) - { - *index++ = 0; - *index++ = i + 1; - *index++ = i + 2; - } - - for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++) - { - VectorCopy (in, out->v); - - s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; - t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]; - - out->st[0] = s / surf->texinfo->texture->width; - out->st[1] = t / surf->texinfo->texture->height; - - s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0); - t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0); - - // lightmap coordinates - out->uv[0] = 0; - out->uv[1] = 0; - - // LordHavoc: calc lightmap data offset for vertex lighting to use - is = (int) s; - it = (int) t; - is = bound(0, is, smax); - it = bound(0, it, tmax); - out->lightmapoffset = ((it * (smax+1) + is) * 3); - } + surfmesh_t *mesh; + mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float)); + mesh->numverts = numverts; + mesh->numtriangles = numtriangles; + mesh->verts = (float *)(mesh + 1); + mesh->str = mesh->verts + mesh->numverts * 4; + mesh->uvw = mesh->str + mesh->numverts * 4; + mesh->abc = mesh->uvw + mesh->numverts * 4; + mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4); + mesh->tvectors = mesh->svectors + mesh->numverts * 4; + mesh->normals = mesh->tvectors + mesh->numverts * 4; + mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4); + mesh->index = mesh->lightmapoffsets + mesh->numverts; + mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3; + return mesh; } -void Mod_GenerateLightmappedMesh (msurface_t *surf) +void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) { - int i, is, it, *index, smax, tmax; - float *in, s, t, xbase, ybase, xscale, yscale; - surfvertex_t *out; - surfmesh_t *mesh; + int i, iu, iv, *index, smax, tmax; + float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3]; + surfmesh_t *mesh; - surf->flags |= SURF_LIGHTMAP; smax = surf->extents[0] >> 4; tmax = surf->extents[1] >> 4; - if (r_miplightmaps.integer) + + if (vertexonly) { - surf->lightmaptexturestride = (surf->extents[0]>>4)+1; - surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE, NULL, NULL, 0); + surf->lightmaptexturestride = 0; + surf->lightmaptexture = NULL; + uscale = 0; + vscale = 0; + ubase = 0; + vbase = 0; } else { - surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0); - surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE, NULL, NULL, 0); + surf->flags |= SURF_LIGHTMAP; + if (r_miplightmaps.integer) + { + surf->lightmaptexturestride = (surf->extents[0]>>4)+1; + surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE, NULL); + } + else + { + surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0); + surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE, NULL); + } + R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale); + uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16); + vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16); } - R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &xbase, &ybase, &xscale, &yscale); - xscale = (xscale - xbase) * 16.0 / ((surf->extents[0] & ~15) + 16); - yscale = (yscale - ybase) * 16.0 / ((surf->extents[1] & ~15) + 16); - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->vertex = (surfvertex_t *)(mesh + 1); - mesh->index = (int *)(mesh->vertex + mesh->numverts); - memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t)); + surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2); index = mesh->index; for (i = 0;i < mesh->numtriangles;i++) @@ -1122,49 +1513,49 @@ void Mod_GenerateLightmappedMesh (msurface_t *surf) *index++ = i + 1; *index++ = i + 2; } + Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles); - for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++) + VectorCopy(surf->plane->normal, normal); + if (surf->flags & SURF_PLANEBACK) + VectorNegate(normal, normal); + for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3) { - VectorCopy (in, out->v); - - s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; - t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]; - - out->st[0] = s / surf->texinfo->texture->width; - out->st[1] = t / surf->texinfo->texture->height; - - s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0); - t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0); - - // lightmap coordinates - out->uv[0] = s * xscale + xbase; - out->uv[1] = t * yscale + ybase; - + s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; + t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]; + u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0); + v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0); // LordHavoc: calc lightmap data offset for vertex lighting to use - is = (int) s; - it = (int) t; - is = bound(0, is, smax); - it = bound(0, it, tmax); - out->lightmapoffset = ((it * (smax+1) + is) * 3); + iu = (int) u; + iv = (int) v; + iu = bound(0, iu, smax); + iv = bound(0, iv, tmax); + u = u * uscale + ubase; + v = v * vscale + vbase; + + mesh->verts[i * 4 + 0] = in[0]; + mesh->verts[i * 4 + 1] = in[1]; + mesh->verts[i * 4 + 2] = in[2]; + mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width; + mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height; + mesh->uvw[i * 4 + 0] = u; + mesh->uvw[i * 4 + 1] = v; + mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f); + mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f); + mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3); } + Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals); } void Mod_GenerateVertexMesh (msurface_t *surf) { - int i, *index; - float *in; - surfvertex_t *out; - surfmesh_t *mesh; + int i, *index; + float *in, s, t, normal[3]; + surfmesh_t *mesh; surf->lightmaptexturestride = 0; surf->lightmaptexture = NULL; - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->vertex = (surfvertex_t *)(mesh + 1); - mesh->index = (int *)(mesh->vertex + mesh->numverts); - memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t)); + surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2); index = mesh->index; for (i = 0;i < mesh->numtriangles;i++) @@ -1173,21 +1564,32 @@ void Mod_GenerateVertexMesh (msurface_t *surf) *index++ = i + 1; *index++ = i + 2; } + Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles); - for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++) + VectorCopy(surf->plane->normal, normal); + if (surf->flags & SURF_PLANEBACK) + VectorNegate(normal, normal); + for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3) { - VectorCopy (in, out->v); - out->st[0] = (DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) / surf->texinfo->texture->width; - out->st[1] = (DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) / surf->texinfo->texture->height; + s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]); + t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]); + mesh->verts[i * 4 + 0] = in[0]; + mesh->verts[i * 4 + 1] = in[1]; + mesh->verts[i * 4 + 2] = in[2]; + mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width; + mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height; + mesh->uvw[i * 4 + 0] = 0; + mesh->uvw[i * 4 + 1] = 0; + mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f); + mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f); } + Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals); } void Mod_GenerateSurfacePolygon (msurface_t *surf) { - float *vert; - int i; - int lindex; - float *vec; + int i, lindex; + float *vec, *vert, mins[3], maxs[3]; // convert edges back to a normal polygon surf->poly_numverts = surf->numedges; @@ -1202,55 +1604,21 @@ void Mod_GenerateSurfacePolygon (msurface_t *surf) VectorCopy (vec, vert); vert += 3; } -} - -static void Mod_SplitSurfMeshIfTooBig(msurface_t *s) -{ - int j, base, tricount, newvertexcount, *index, *vertexremap; - surfmesh_t *newmesh, *oldmesh, *firstmesh; - if (s->mesh->numtriangles > 1000) + vert = surf->poly_verts; + VectorCopy(vert, mins); + VectorCopy(vert, maxs); + vert += 3; + for (i = 1;i < surf->poly_numverts;i++, vert += 3) { - vertexremap = Mem_Alloc(tempmempool, s->mesh->numverts * sizeof(int)); - base = 0; - oldmesh = NULL; - firstmesh = NULL; - newmesh = NULL; - while (base < s->mesh->numtriangles) - { - tricount = s->mesh->numtriangles - base; - if (tricount > 1000) - tricount = 1000; - index = s->mesh->index + base * 3; - base += tricount; - - newvertexcount = 0; - memset(vertexremap, -1, s->mesh->numverts * sizeof(int)); - for (j = 0;j < tricount * 3;j++) - if (vertexremap[index[j]] < 0) - vertexremap[index[j]] = newvertexcount++; - - newmesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + newvertexcount * sizeof(surfvertex_t) + tricount * sizeof(int[3])); - newmesh->chain = NULL; - newmesh->numverts = newvertexcount; - newmesh->numtriangles = tricount; - newmesh->vertex = (surfvertex_t *)(newmesh + 1); - newmesh->index = (int *)(newmesh->vertex + newvertexcount); - for (j = 0;j < tricount * 3;j++) - { - newmesh->index[j] = vertexremap[index[j]]; - // yes this copies the same vertex multiple times in many cases... but that's ok... - memcpy(&newmesh->vertex[newmesh->index[j]], &s->mesh->vertex[index[j]], sizeof(surfvertex_t)); - } - if (oldmesh) - oldmesh->chain = newmesh; - else - firstmesh = newmesh; - oldmesh = newmesh; - } - Mem_Free(vertexremap); - Mem_Free(s->mesh); - s->mesh = firstmesh; + if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0]; + if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1]; + if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2]; } + VectorCopy(mins, surf->poly_mins); + VectorCopy(maxs, surf->poly_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; } /* @@ -1272,9 +1640,13 @@ static void Mod_LoadFaces (lump_t *l) loadmodel->surfaces = out; loadmodel->numsurfaces = count; + loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); + loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); + loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); for (surfnum = 0;surfnum < count;surfnum++, in++, out++) { + out->number = surfnum; // FIXME: validate edges, texinfo, etc? out->firstedge = LittleLong(in->firstedge); out->numedges = LittleShort(in->numedges); @@ -1301,8 +1673,6 @@ static void Mod_LoadFaces (lump_t *l) // force lightmap upload on first time seeing the surface out->cached_dlight = true; - out->cached_ambient = -1000; - out->cached_lightscalebit = -1000; CalcSurfaceExtents (out); @@ -1321,86 +1691,21 @@ static void Mod_LoadFaces (lump_t *l) out->samples = loadmodel->lightdata + (i * 3); Mod_GenerateSurfacePolygon(out); - - if (out->texinfo->texture->flags & SURF_DRAWSKY) + if (out->texinfo->texture->shader == &Cshader_wall_lightmap) { - out->shader = &Cshader_sky; - out->samples = NULL; - Mod_GenerateWarpMesh (out); - } - else if (out->texinfo->texture->flags & SURF_DRAWTURB) - { - out->shader = &Cshader_water; - out->samples = NULL; - Mod_GenerateWarpMesh (out); + if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256)) + Host_Error ("Bad surface extents"); + Mod_GenerateWallMesh (out, false); + // stainmap for permanent marks on walls + out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3); + // clear to white + memset(out->stainsamples, 255, ssize * tsize * 3); } else - { - if (!R_TextureHasAlpha(out->texinfo->texture->texture)) - out->flags |= SURF_CLIPSOLID; - if (out->texinfo->flags & TEX_SPECIAL) - { - // qbsp couldn't find the texture for this surface, but it was either turb or sky... assume turb - out->shader = &Cshader_water; - out->shader = &Cshader_water; - out->samples = NULL; - Mod_GenerateWarpMesh (out); - } - else if ((out->extents[0]+1) > (256*16) || (out->extents[1]+1) > (256*16)) - { - Con_Printf ("Bad surface extents, converting to fullbright polygon"); - out->shader = &Cshader_wall_fullbright; - out->samples = NULL; - Mod_GenerateVertexMesh(out); - } - else - { - // stainmap for permanent marks on walls - out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3); - // clear to white - memset(out->stainsamples, 255, ssize * tsize * 3); - if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer) - { - out->shader = &Cshader_wall_vertex; - Mod_GenerateVertexLitMesh(out); - } - else - { - out->shader = &Cshader_wall_lightmap; - Mod_GenerateLightmappedMesh(out); - } - } - } - Mod_SplitSurfMeshIfTooBig(out); + Mod_GenerateVertexMesh (out); } } -static model_t *sortmodel; - -static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb) -{ - const msurface_t *a, *b; - a = *((const msurface_t **)voida); - b = *((const msurface_t **)voidb); - if (a->shader != b->shader) - return (qbyte *) a->shader - (qbyte *) b->shader; - if (a->texinfo->texture != b->texinfo->texture); - return a->texinfo->texture - b->texinfo->texture; - return 0; -} - -static void Mod_BrushSortedSurfaces(model_t *model, mempool_t *pool) -{ - int surfnum; - sortmodel = model; - sortmodel->modelsortedsurfaces = Mem_Alloc(pool, sortmodel->nummodelsurfaces * sizeof(msurface_t *)); - for (surfnum = 0;surfnum < sortmodel->nummodelsurfaces;surfnum++) - sortmodel->modelsortedsurfaces[surfnum] = &sortmodel->surfaces[surfnum + sortmodel->firstmodelsurface]; - - qsort(sortmodel->modelsortedsurfaces, sortmodel->nummodelsurfaces, sizeof(msurface_t *), Mod_SurfaceQSortCompare); -} - - /* ================= Mod_SetParent @@ -1649,21 +1954,21 @@ Mod_LoadMarksurfaces */ static void Mod_LoadMarksurfaces (lump_t *l) { - int i, j; - short *in; + int i, j; + short *in; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); loadmodel->nummarksurfaces = l->filelen / sizeof(*in); - loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *)); + loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int)); for (i = 0;i < loadmodel->nummarksurfaces;i++) { j = (unsigned) LittleShort(in[i]); if (j >= loadmodel->numsurfaces) Host_Error ("Mod_ParseMarksurfaces: bad surface number"); - loadmodel->marksurfaces[i] = loadmodel->surfaces + j; + loadmodel->marksurfaces[i] = j; } } @@ -2386,11 +2691,61 @@ static void Mod_MakePortals(void) Mod_FinalizePortals(); } +static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool) +{ +#if 0 + int surfnum, vertnum, vertnum2, snum, vnum, vnum2; + msurface_t *surf, *s; + float *v0, *v1, *v2, *v3; + for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++) + surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *)); + for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++) + { + for (vertnum = surf->poly_numverts - 1, vertnum2 = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;vertnum2 < surf->poly_numverts;vertnum = vertnum2, vertnum2++, v0 = v1, v1 += 3) + { + if (surf->neighborsurfaces[vertnum]) + continue; + surf->neighborsurfaces[vertnum] = NULL; + for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++) + { + if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1) + || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1) + || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1) + || s == surf) + continue; + for (vnum = 0;vnum < s->poly_numverts;vnum++) + if (s->neighborsurfaces[vnum] == surf) + break; + if (vnum < s->poly_numverts) + continue; + for (vnum = s->poly_numverts - 1, vnum2 = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum2 < s->poly_numverts;vnum = vnum2, vnum2++, v2 = v3, v3 += 3) + { + if (s->neighborsurfaces[vnum] == NULL + && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2]) + || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2]))) + { + surf->neighborsurfaces[vertnum] = s; + s->neighborsurfaces[vnum] = surf; + break; + } + } + if (vnum < s->poly_numverts) + break; + } + } + } +#endif +} + /* ================= Mod_LoadBrushModel ================= */ +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); void Mod_LoadBrushModel (model_t *mod, void *buffer) { int i, j; @@ -2398,6 +2753,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) dmodel_t *bm; mempool_t *mainmempool; char *loadname; + model_t *originalloadmodel; mod->type = mod_brush; @@ -2408,12 +2764,16 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION); mod->ishlbsp = i == 30; if (loadmodel->isworldmodel) + { Cvar_SetValue("halflifebsp", mod->ishlbsp); + // until we get a texture for it... + R_ResetQuakeSky(); + } // swap all the lumps mod_base = (qbyte *)header; - for (i=0 ; iname; Mod_LoadLightList (); + originalloadmodel = loadmodel; // // set up the submodels (FIXME: this is confusing) @@ -2473,44 +2834,67 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->firstmodelsurface = bm->firstface; mod->nummodelsurfaces = bm->numfaces; + // this gets altered below if sky is used mod->DrawSky = NULL; - // LordHavoc: calculate bmodel bounding box rather than trusting what it says - for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) + mod->Draw = R_Model_Brush_Draw; + mod->DrawFakeShadow = NULL; + mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume; + mod->DrawLight = R_Model_Brush_DrawLight; + mod->texturesurfacechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t *)); + if (mod->nummodelsurfaces) { - // we only need to have a drawsky function if it is used (usually only on world model) - if (surf->shader == &Cshader_sky) - mod->DrawSky = R_DrawBrushModelSky; - for (k = 0;k < surf->numedges;k++) + // LordHavoc: calculate bmodel bounding box rather than trusting what it says + for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) { - 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; + // 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; + // link into texture chain + surf->texturechain = mod->texturesurfacechains[surf->texinfo->texture - mod->textures]; + mod->texturesurfacechains[surf->texinfo->texture - mod->textures] = surf; + // calculate bounding shapes + for (k = 0;k < surf->numedges;k++) + { + 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; + } } + modelyawradius = sqrt(modelyawradius); + modelradius = sqrt(modelradius); + mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius); + mod->yawmins[2] = mod->normalmins[2]; + mod->yawmaxs[2] = mod->normalmaxs[2]; + mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; + mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; + mod->radius = modelradius; + mod->radius2 = modelradius * modelradius; + // LordHavoc: build triangle meshs for entire model's geometry + // (only used for shadow volumes) + mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool, 1024); + for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) + if (surf->flags & SURF_SHADOWCAST) + Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts); + mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh); + Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius); } - modelyawradius = sqrt(modelyawradius); - modelradius = sqrt(modelradius); - mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius); - mod->yawmins[2] = mod->normalmins[2]; - mod->yawmaxs[2] = mod->normalmaxs[2]; - mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; - mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; - // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch) - if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2]) + else { + // LordHavoc: empty submodel (lacrima.bsp has such a glitch) Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname); VectorClear(mod->normalmins); VectorClear(mod->normalmaxs); @@ -2518,16 +2902,14 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) VectorClear(mod->yawmaxs); VectorClear(mod->rotatedmins); VectorClear(mod->rotatedmaxs); + mod->radius = 0; + mod->radius2 = 0; + mod->shadowmesh = NULL; } + Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool); mod->numleafs = bm->visleafs; - mod->SERAddEntity = Mod_Brush_SERAddEntity; - mod->Draw = R_DrawBrushModelNormal; - mod->DrawShadow = NULL; - - Mod_BrushSortedSurfaces(mod, mainmempool); - // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1)) @@ -2544,5 +2926,8 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod = loadmodel; } } + + loadmodel = originalloadmodel; + //Mod_ProcessLightList (); }