X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=model_brush.c;h=e3919a63ff8f587002a65158c286b88780956f10;hb=28b0a330e246a39640743688f0f8ad1fb2c4d247;hp=f923c3fbaa8f13a0ed2d1fd682a32306d415d854;hpb=406feaa034d99f0c62f15a7d015724ab55ab876c;p=xonotic%2Fdarkplaces.git diff --git a/model_brush.c b/model_brush.c index f923c3fb..e3919a63 100644 --- a/model_brush.c +++ b/model_brush.c @@ -34,7 +34,14 @@ 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_nosurftextures = {0, "r_nosurftextures", "0"}; -cvar_t mod_q3bsp_curves_subdivide_level = {0, "mod_q3bsp_curves_subdivide_level", "2"}; +cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4"}; +cvar_t r_subdivisions_minlevel = {0, "r_subdivisions_minlevel", "0"}; +cvar_t r_subdivisions_maxlevel = {0, "r_subdivisions_maxlevel", "10"}; +cvar_t r_subdivisions_maxvertices = {0, "r_subdivisions_maxvertices", "65536"}; +cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolerance", "15"}; +cvar_t r_subdivisions_collision_minlevel = {0, "r_subdivisions_collision_minlevel", "0"}; +cvar_t r_subdivisions_collision_maxlevel = {0, "r_subdivisions_collision_maxlevel", "10"}; +cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225"}; cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1"}; cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1"}; cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0"}; @@ -48,7 +55,14 @@ void Mod_BrushInit(void) Cvar_RegisterVariable(&r_miplightmaps); Cvar_RegisterVariable(&r_lightmaprgba); Cvar_RegisterVariable(&r_nosurftextures); - Cvar_RegisterVariable(&mod_q3bsp_curves_subdivide_level); + Cvar_RegisterVariable(&r_subdivisions_tolerance); + Cvar_RegisterVariable(&r_subdivisions_minlevel); + Cvar_RegisterVariable(&r_subdivisions_maxlevel); + Cvar_RegisterVariable(&r_subdivisions_maxvertices); + Cvar_RegisterVariable(&r_subdivisions_collision_tolerance); + Cvar_RegisterVariable(&r_subdivisions_collision_minlevel); + Cvar_RegisterVariable(&r_subdivisions_collision_maxlevel); + Cvar_RegisterVariable(&r_subdivisions_collision_maxvertices); Cvar_RegisterVariable(&mod_q3bsp_curves_collisions); Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline); Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush); @@ -427,7 +441,7 @@ loc0: if (t->trace->allsolid) t->trace->startsolid = true; #if COLLISIONPARANOID >= 3 - Con_Printf("S"); + Con_Print("S"); #endif return HULLCHECKSTATE_SOLID; } @@ -435,7 +449,7 @@ loc0: { t->trace->allsolid = false; #if COLLISIONPARANOID >= 3 - Con_Printf("E"); + Con_Print("E"); #endif return HULLCHECKSTATE_EMPTY; } @@ -461,7 +475,7 @@ loc0: if (t2 < 0) { #if COLLISIONPARANOID >= 3 - Con_Printf("<"); + Con_Print("<"); #endif num = node->children[1]; goto loc0; @@ -473,7 +487,7 @@ loc0: if (t2 >= 0) { #if COLLISIONPARANOID >= 3 - Con_Printf(">"); + Con_Print(">"); #endif num = node->children[0]; goto loc0; @@ -484,7 +498,7 @@ loc0: // the line intersects, find intersection point // LordHavoc: this uses the original trace for maximum accuracy #if COLLISIONPARANOID >= 3 - Con_Printf("M"); + Con_Print("M"); #endif if (plane->type < 3) { @@ -535,7 +549,7 @@ loc0: t->trace->fraction = bound(0, midf, 1); #if COLLISIONPARANOID >= 3 - Con_Printf("D"); + Con_Print("D"); #endif return HULLCHECKSTATE_DONE; } @@ -609,7 +623,7 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, #if COLLISIONPARANOID >= 2 Con_Printf("t(%f %f %f,%f %f %f,%i %f %f %f)", rhc.start[0], rhc.start[1], rhc.start[2], rhc.end[0], rhc.end[1], rhc.end[2], rhc.hull - model->brushq1.hulls, rhc.hull->clip_mins[0], rhc.hull->clip_mins[1], rhc.hull->clip_mins[2]); Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); - Con_Printf("\n"); + Con_Print("\n"); #else if (DotProduct(rhc.dist, rhc.dist)) Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); @@ -925,13 +939,10 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) tx->width = 16; tx->height = 16; tx->skin.base = r_notexture; - tx->shader = &Cshader_wall_lightmap; - tx->flags = SURF_SOLIDCLIP; if (i == loadmodel->brushq1.numtextures - 1) - { - tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES; - tx->shader = &Cshader_water; - } + tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES; + else + tx->flags = SURF_LIGHTMAP | SURF_SOLIDCLIP; tx->currentframe = tx; } @@ -969,7 +980,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) } if ((mtwidth & 15) || (mtheight & 15)) - Con_Printf("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name); + Con_Printf("warning: texture \"%s\" in \"%s\" is not 16 aligned\n", dmiptex->name, loadmodel->name); // LordHavoc: force all names to lowercase for (j = 0;name[j];j++) @@ -1063,8 +1074,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) if (tx->name[0] == '*') { // turb does not block movement - tx->flags &= ~SURF_SOLIDCLIP; - 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) @@ -1072,20 +1082,11 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) 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; - tx->shader = &Cshader_sky; - } + tx->flags = SURF_DRAWSKY | SURF_SOLIDCLIP; else - { - tx->flags |= SURF_LIGHTMAP; - if (!tx->skin.fog) - tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT; - tx->shader = &Cshader_wall_lightmap; - } + tx->flags = SURF_LIGHTMAP | SURF_SOLIDCLIP; // start out with no animation tx->currentframe = tx; @@ -1233,9 +1234,9 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) else { if (fs_filesize == 8) - Con_Printf("Empty .lit file, ignoring\n"); + Con_Print("Empty .lit file, ignoring\n"); else - Con_Printf("Corrupt .lit file (old version?), ignoring\n"); + Con_Print("Corrupt .lit file (old version?), ignoring\n"); Mem_Free(data); } } @@ -1512,7 +1513,7 @@ static void Mod_Q1BSP_LoadTexinfo(lump_t *l) { // 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) + if (out->texture == NULL || out->texture->flags & SURF_LIGHTMAP) out->texture = loadmodel->brushq1.textures + (loadmodel->brushq1.numtextures - 1); } else @@ -1628,7 +1629,7 @@ static void SubdividePolygon(int numverts, float *verts) { if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES) { - Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n"); + Con_Print("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n"); return; } @@ -1818,7 +1819,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) else // LordHavoc: white lighting (bsp version 29) surf->samples = loadmodel->brushq1.lightdata + (i * 3); - if (surf->texinfo->texture->shader == &Cshader_wall_lightmap) + if (surf->texinfo->texture->flags & SURF_LIGHTMAP) { if ((surf->extents[0] >> 4) + 1 > (256) || (surf->extents[1] >> 4) + 1 > (256)) Host_Error("Bad surface extents"); @@ -1876,7 +1877,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles); Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, mesh->data_vertex3f, mesh->data_texcoordtexture2f, mesh->data_element3i, mesh->data_svector3f, mesh->data_tvector3f, mesh->data_normal3f); - if (surf->texinfo->texture->shader == &Cshader_wall_lightmap) + if (surf->texinfo->texture->flags & SURF_LIGHTMAP) { int i, iu, iv, smax, tmax; float u, v, ubase, vbase, uscale, vscale; @@ -1884,7 +1885,6 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) smax = surf->extents[0] >> 4; tmax = surf->extents[1] >> 4; - surf->flags |= SURF_LIGHTMAP; if (r_miplightmaps.integer) { surf->lightmaptexturestride = smax+1; @@ -2015,7 +2015,7 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l) if (p >= 0 && out->clusterindex >= 0) { if (p >= loadmodel->brushq1.num_compressedpvs) - Con_Printf("Mod_Q1BSP_LoadLeafs: invalid visofs\n"); + Con_Print("Mod_Q1BSP_LoadLeafs: invalid visofs\n"); else Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, loadmodel->brush.data_pvsclusters + out->clusterindex * loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.data_pvsclusters + (out->clusterindex + 1) * loadmodel->brush.num_pvsclusterbytes); } @@ -2508,7 +2508,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node) nodeportalwinding = Winding_Clip(nodeportalwinding, clipplane.normal[0], clipplane.normal[1], clipplane.normal[2], clipplane.dist, true); if (!nodeportalwinding) { - Con_Printf("Mod_Q1BSP_RecursiveNodePortals: WARNING: new portal was clipped away\n"); + Con_Print("Mod_Q1BSP_RecursiveNodePortals: WARNING: new portal was clipped away\n"); break; } } @@ -2724,6 +2724,21 @@ static void Mod_Q1BSP_BuildPVSTextureChains(model_t *model) } } +//Returns PVS data for a given point +//(note: can return NULL) +static qbyte *Mod_Q1BSP_GetPVS(model_t *model, const vec3_t p) +{ + mnode_t *node; + Mod_CheckLoaded(model); + node = model->brushq1.nodes; + while (node->plane) + node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist]; + if (((mleaf_t *)node)->clusterindex >= 0) + return model->brush.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brush.num_pvsclusterbytes; + else + return NULL; +} + static void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, mnode_t *node) { while (node->plane) @@ -2756,7 +2771,7 @@ static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyt { int bytes = ((model->brushq1.num_leafs - 1) + 7) >> 3; bytes = min(bytes, pvsbufferlength); - if (r_novis.integer) + if (r_novis.integer || !Mod_Q1BSP_GetPVS(model, org)) { memset(pvsbuffer, 0xFF, bytes); return bytes; @@ -2766,21 +2781,6 @@ static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyt return bytes; } -//Returns PVS data for a given point -//(note: can return NULL) -static qbyte *Mod_Q1BSP_GetPVS(model_t *model, const vec3_t p) -{ - mnode_t *node; - Mod_CheckLoaded(model); - node = model->brushq1.nodes; - while (node->plane) - node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist]; - if (((mleaf_t *)node)->clusterindex >= 0) - return model->brush.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brush.num_pvsclusterbytes; - else - return NULL; -} - static void Mod_Q1BSP_RoundUpToHullSize(model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs) { vec3_t size; @@ -2864,8 +2864,9 @@ void Mod_Q1BSP_GetVisible(model_t *model, const vec3_t point, const vec3_t mins, 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, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap); +extern void R_Model_Brush_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer); +extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist); +extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, int numsurfaces, const int *surfacelist); void Mod_Q1BSP_Load(model_t *mod, void *buffer) { int i, j, k; @@ -2982,9 +2983,16 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) mod->brushq1.firstmodelsurface = bm->firstface; mod->brushq1.nummodelsurfaces = bm->numfaces; + // make the model surface list (used by shadowing/lighting) + mod->numsurfaces = mod->brushq1.nummodelsurfaces; + mod->surfacelist = Mem_Alloc(originalloadmodel->mempool, mod->numsurfaces * sizeof(*mod->surfacelist)); + for (j = 0;j < mod->numsurfaces;j++) + mod->surfacelist[j] = mod->brushq1.firstmodelsurface + j; + // this gets altered below if sky is used mod->DrawSky = NULL; mod->Draw = R_Model_Brush_Draw; + mod->GetLightInfo = R_Model_Brush_GetLightInfo; mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume; mod->DrawLight = R_Model_Brush_DrawLight; if (i != 0) @@ -3010,7 +3018,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) for (j = 0, surf = &mod->brushq1.surfaces[mod->brushq1.firstmodelsurface];j < mod->brushq1.nummodelsurfaces;j++, surf++) { // we only need to have a drawsky function if it is used(usually only on world model) - if (surf->texinfo->texture->shader == &Cshader_sky) + if (surf->texinfo->texture->flags & SURF_DRAWSKY) mod->DrawSky = R_Model_Brush_DrawSky; // LordHavoc: submodels always clip, even if water if (mod->brush.numsubmodels - 1) @@ -3559,6 +3567,7 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l) const char *text; int flags; char shadername[Q3PATHLENGTH]; + char sky[Q3PATHLENGTH]; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -3590,8 +3599,9 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l) text = f; while (COM_ParseToken(&text, false)) { - snprintf(shadername, sizeof(shadername), "%s", com_token); + strncpy(shadername, com_token, sizeof(shadername)); flags = 0; + sky[0] = 0; if (COM_ParseToken(&text, false) && !strcasecmp(com_token, "{")) { while (COM_ParseToken(&text, false)) @@ -3676,6 +3686,22 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l) goto parseerror; } } + else if (!strcasecmp(com_token, "sky")) + { + if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n")) + if (strlen(com_token) < sizeof(sky)) + strcpy(sky, com_token); + } + else if (!strcasecmp(com_token, "skyparms")) + { + if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n")) + { + if (strlen(com_token) < sizeof(sky) && !atoi(com_token) && strcasecmp(com_token, "-")) + strcpy(sky, com_token); + if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n")) + COM_ParseToken(&text, true); + } + } else { // look for linebreak or } @@ -3688,8 +3714,14 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l) // add shader to list (shadername and flags) // actually here we just poke into the texture settings for (j = 0, out = loadmodel->brushq3.data_textures;j < loadmodel->brushq3.num_textures;j++, out++) + { if (!strcasecmp(out->name, shadername)) + { out->surfaceparms = flags; + if ((flags & Q3SURFACEPARM_SKY) && sky[0]) + strcpy(loadmodel->brush.skybox, sky); + } + } } else { @@ -4079,13 +4111,6 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) out->type = 0; // error continue; } - // convert patch to Q3FACETYPE_MESH - xlevel = mod_q3bsp_curves_subdivide_level.integer; - ylevel = mod_q3bsp_curves_subdivide_level.integer; - finalwidth = ((patchsize[0] - 1) << xlevel) + 1; - finalheight = ((patchsize[1] - 1) << ylevel) + 1; - finalvertices = finalwidth * finalheight; - finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2; originalvertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3; //originalsvector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3; //originaltvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3; @@ -4106,6 +4131,27 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) //originalelement3i = out->data_element3i; //originalneighbor3i = out->data_neighbor3i; */ + // convert patch to Q3FACETYPE_MESH + xlevel = QuadraticSplinePatchSubdivisionLevelOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value, 10); + ylevel = QuadraticSplinePatchSubdivisionLevelOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value, 10); + // bound to user settings + xlevel = bound(r_subdivisions_minlevel.integer, xlevel, r_subdivisions_maxlevel.integer); + ylevel = bound(r_subdivisions_minlevel.integer, ylevel, r_subdivisions_maxlevel.integer); + // bound to sanity settings + xlevel = bound(0, xlevel, 10); + ylevel = bound(0, ylevel, 10); + // bound to user limit on vertices + while ((xlevel > 0 || ylevel > 0) && (((patchsize[0] - 1) << xlevel) + 1) * (((patchsize[1] - 1) << ylevel) + 1) > min(r_subdivisions_maxvertices.integer, 262144)) + { + if (xlevel > ylevel) + xlevel--; + else + ylevel--; + } + finalwidth = ((patchsize[0] - 1) << xlevel) + 1; + finalheight = ((patchsize[1] - 1) << ylevel) + 1; + finalvertices = finalwidth * finalheight; + finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2; out->data_vertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[20]) * finalvertices); out->data_svector3f = out->data_vertex3f + finalvertices * 3; out->data_tvector3f = out->data_svector3f + finalvertices * 3; @@ -4153,7 +4199,59 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_vertices, out->num_triangles); } // q3map does not put in collision brushes for curves... ugh + // build the lower quality collision geometry out->collisions = true; + xlevel = QuadraticSplinePatchSubdivisionLevelOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10); + ylevel = QuadraticSplinePatchSubdivisionLevelOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10); + // bound to user settings + xlevel = bound(r_subdivisions_collision_minlevel.integer, xlevel, r_subdivisions_collision_maxlevel.integer); + ylevel = bound(r_subdivisions_collision_minlevel.integer, ylevel, r_subdivisions_collision_maxlevel.integer); + // bound to sanity settings + xlevel = bound(0, xlevel, 10); + ylevel = bound(0, ylevel, 10); + // bound to user limit on vertices + while ((xlevel > 0 || ylevel > 0) && (((patchsize[0] - 1) << xlevel) + 1) * (((patchsize[1] - 1) << ylevel) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144)) + { + if (xlevel > ylevel) + xlevel--; + else + ylevel--; + } + finalwidth = ((patchsize[0] - 1) << xlevel) + 1; + finalheight = ((patchsize[1] - 1) << ylevel) + 1; + finalvertices = finalwidth * finalheight; + finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2; + out->data_collisionvertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices); + out->data_collisionelement3i = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles); + out->num_collisionvertices = finalvertices; + out->num_collisiontriangles = finaltriangles; + QuadraticSplinePatchSubdivideFloatBuffer(patchsize[0], patchsize[1], xlevel, ylevel, 3, originalvertex3f, out->data_collisionvertex3f); + // generate elements + e = out->data_collisionelement3i; + for (y = 0;y < finalheight - 1;y++) + { + row0 = (y + 0) * finalwidth; + row1 = (y + 1) * finalwidth; + for (x = 0;x < finalwidth - 1;x++) + { + *e++ = row0; + *e++ = row1; + *e++ = row0 + 1; + *e++ = row1; + *e++ = row1 + 1; + *e++ = row0 + 1; + row0++; + row1++; + } + } + out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f); + if (developer.integer) + { + if (out->num_collisiontriangles < finaltriangles) + Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided for collisions to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_collisionvertices, finaltriangles, finaltriangles - out->num_collisiontriangles, out->num_collisiontriangles); + else + Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided for collisions to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_collisionvertices, out->num_collisiontriangles); + } break; case Q3FACETYPE_FLARE: Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name); @@ -4175,7 +4273,7 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) if (out->data_element3i[j] < 0 || out->data_element3i[j] >= out->num_vertices) out->data_element3i[j] = 0; } - Con_Printf("\n"); + Con_Print("\n"); } // for shadow volumes Mod_BuildTriangleNeighbors(out->data_neighbor3i, out->data_element3i, out->num_triangles); @@ -4742,7 +4840,7 @@ static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, q3mnode_t *node if (face->collisions && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs)) { face->collisionmarkframe = markframe; - Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs); + Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); if (startfrac > trace->realfraction) return; } @@ -5122,7 +5220,7 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *nod if (face->collisions && face->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs)) { face->markframe = markframe; - Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs); + Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); } } } @@ -5176,7 +5274,7 @@ static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const { face = model->brushq3.data_thismodel->firstface + i; if (face->collisions) - Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs); + Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); } } } @@ -5200,7 +5298,7 @@ static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const { face = model->brushq3.data_thismodel->firstface + i; if (face->collisions) - Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs); + Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs); } } } @@ -5310,7 +5408,7 @@ static int Mod_Q3BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyt { int bytes = model->brush.num_pvsclusterbytes; bytes = min(bytes, pvsbufferlength); - if (r_novis.integer || !loadmodel->brush.num_pvsclusters) + if (r_novis.integer || !loadmodel->brush.num_pvsclusters || !Mod_Q3BSP_GetPVS(model, org)) { memset(pvsbuffer, 0xFF, bytes); return bytes; @@ -5414,8 +5512,9 @@ void Mod_Q3BSP_GetVisible(model_t *model, const vec3_t point, const vec3_t mins, extern void R_Q3BSP_DrawSky(struct entity_render_s *ent); extern void R_Q3BSP_Draw(struct entity_render_s *ent); -extern void R_Q3BSP_DrawShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius); -extern void R_Q3BSP_DrawLight(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap); +extern void R_Q3BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer); +extern void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist); +extern void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, int numsurfaces, const int *surfacelist); void Mod_Q3BSP_Load(model_t *mod, void *buffer) { int i, j, numshadowmeshtriangles; @@ -5450,6 +5549,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) mod->brush.FindNonSolidLocation = Mod_Q3BSP_FindNonSolidLocation; //mod->DrawSky = R_Q3BSP_DrawSky; mod->Draw = R_Q3BSP_Draw; + mod->GetLightInfo = R_Q3BSP_GetLightInfo; mod->DrawShadowVolume = R_Q3BSP_DrawShadowVolume; mod->DrawLight = R_Q3BSP_DrawLight; @@ -5519,6 +5619,12 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) mod->brushq3.data_thismodel = loadmodel->brushq3.data_models + i; mod->brushq3.submodel = i; + // make the model surface list (used by shadowing/lighting) + mod->numsurfaces = mod->brushq3.data_thismodel->numfaces; + mod->surfacelist = Mem_Alloc(loadmodel->mempool, mod->numsurfaces * sizeof(*mod->surfacelist)); + for (j = 0;j < mod->numsurfaces;j++) + mod->surfacelist[j] = (mod->brushq3.data_thismodel->firstface - mod->brushq3.data_faces) + j; + VectorCopy(mod->brushq3.data_thismodel->mins, mod->normalmins); VectorCopy(mod->brushq3.data_thismodel->maxs, mod->normalmaxs); corner[0] = max(fabs(mod->normalmins[0]), fabs(mod->normalmaxs[0]));