+ // if this is a worldmodel and has no BSP tree, create a fake one for the purpose
+ loadmodel->brush.num_visleafs = 1;
+ loadmodel->brush.num_leafs = 1;
+ loadmodel->brush.num_nodes = 0;
+ loadmodel->brush.num_leafsurfaces = loadmodel->num_surfaces;
+ loadmodel->brush.data_leafs = (mleaf_t *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_leafs * sizeof(mleaf_t));
+ loadmodel->brush.data_nodes = (mnode_t *)loadmodel->brush.data_leafs;
+ loadmodel->brush.num_pvsclusters = 1;
+ loadmodel->brush.num_pvsclusterbytes = 1;
+ loadmodel->brush.data_pvsclusters = nobsp_pvs;
+ //if (loadmodel->num_nodes) loadmodel->data_nodes = (mnode_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_nodes * sizeof(mnode_t));
+ //loadmodel->data_leafsurfaces = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->num_leafsurfaces * sizeof(int));
+ loadmodel->brush.data_leafsurfaces = loadmodel->sortedmodelsurfaces;
+ VectorCopy(loadmodel->normalmins, loadmodel->brush.data_leafs->mins);
+ VectorCopy(loadmodel->normalmaxs, loadmodel->brush.data_leafs->maxs);
+ loadmodel->brush.data_leafs->combinedsupercontents = 0; // FIXME?
+ loadmodel->brush.data_leafs->clusterindex = 0;
+ loadmodel->brush.data_leafs->areaindex = 0;
+ loadmodel->brush.data_leafs->numleafsurfaces = loadmodel->brush.num_leafsurfaces;
+ loadmodel->brush.data_leafs->firstleafsurface = loadmodel->brush.data_leafsurfaces;
+ loadmodel->brush.data_leafs->numleafbrushes = 0;
+ loadmodel->brush.data_leafs->firstleafbrush = NULL;
+ loadmodel->brush.supportwateralpha = true;
+
+ if (loadmodel->brush.numsubmodels)
+ loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *));
+
+ mod = loadmodel;
+ for (i = 0;i < loadmodel->brush.numsubmodels;i++)
+ {
+ if (i > 0)
+ {
+ char name[10];
+ // duplicate the basic information
+ dpsnprintf(name, sizeof(name), "*%i", i);
+ mod = Mod_FindName(name, loadmodel->name);
+ // copy the base model to this one
+ *mod = *loadmodel;
+ // rename the clone back to its proper name
+ strlcpy(mod->name, name, sizeof(mod->name));
+ mod->brush.parentmodel = loadmodel;
+ // textures and memory belong to the main model
+ mod->texturepool = NULL;
+ mod->mempool = NULL;
+ mod->brush.GetPVS = NULL;
+ mod->brush.FatPVS = NULL;
+ mod->brush.BoxTouchingPVS = NULL;
+ mod->brush.BoxTouchingLeafPVS = NULL;
+ mod->brush.BoxTouchingVisibleLeafs = NULL;
+ mod->brush.FindBoxClusters = NULL;
+ mod->brush.LightPoint = NULL;
+ mod->brush.AmbientSoundLevelsForPoint = NULL;
+ }
+ mod->brush.submodel = i;
+ if (loadmodel->brush.submodels)
+ loadmodel->brush.submodels[i] = mod;
+
+ // make the model surface list (used by shadowing/lighting)
+ mod->firstmodelsurface = submodelfirstsurface[i];
+ mod->nummodelsurfaces = submodelfirstsurface[i+1] - submodelfirstsurface[i];
+ mod->firstmodelbrush = 0;
+ mod->nummodelbrushes = 0;
+ mod->sortedmodelsurfaces = loadmodel->sortedmodelsurfaces + mod->firstmodelsurface;
+ Mod_MakeSortedSurfaces(mod);
+
+ VectorClear(mod->normalmins);
+ VectorClear(mod->normalmaxs);
+ l = false;
+ for (j = 0;j < mod->nummodelsurfaces;j++)
+ {
+ const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
+ const float *v = mod->surfmesh.data_vertex3f + 3 * surface->num_firstvertex;
+ int k;
+ if (!surface->num_vertices)
+ continue;
+ if (!l)
+ {
+ l = true;
+ VectorCopy(v, mod->normalmins);
+ VectorCopy(v, mod->normalmaxs);
+ }
+ for (k = 0;k < surface->num_vertices;k++, v += 3)
+ {
+ mod->normalmins[0] = min(mod->normalmins[0], v[0]);
+ mod->normalmins[1] = min(mod->normalmins[1], v[1]);
+ mod->normalmins[2] = min(mod->normalmins[2], v[2]);
+ mod->normalmaxs[0] = max(mod->normalmaxs[0], v[0]);
+ mod->normalmaxs[1] = max(mod->normalmaxs[1], v[1]);
+ mod->normalmaxs[2] = max(mod->normalmaxs[2], v[2]);
+ }
+ }
+ corner[0] = max(fabs(mod->normalmins[0]), fabs(mod->normalmaxs[0]));
+ corner[1] = max(fabs(mod->normalmins[1]), fabs(mod->normalmaxs[1]));
+ corner[2] = max(fabs(mod->normalmins[2]), fabs(mod->normalmaxs[2]));
+ modelradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]+corner[2]*corner[2]);
+ yawradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
+ mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
+ mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
+ mod->yawmaxs[0] = mod->yawmaxs[1] = yawradius;
+ mod->yawmins[0] = mod->yawmins[1] = -yawradius;
+ mod->yawmins[2] = mod->normalmins[2];
+ mod->yawmaxs[2] = mod->normalmaxs[2];
+ mod->radius = modelradius;
+ mod->radius2 = modelradius * modelradius;
+
+ // this gets altered below if sky or water is used
+ mod->DrawSky = NULL;
+ mod->DrawAddWaterPlanes = NULL;
+
+ for (j = 0;j < mod->nummodelsurfaces;j++)
+ if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & MATERIALFLAG_SKY)
+ break;
+ if (j < mod->nummodelsurfaces)
+ mod->DrawSky = R_Q1BSP_DrawSky;
+
+ for (j = 0;j < mod->nummodelsurfaces;j++)
+ if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
+ break;
+ if (j < mod->nummodelsurfaces)
+ mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
+
+ Mod_MakeCollisionBIH(mod, true, &mod->collision_bih);
+ mod->render_bih = mod->collision_bih;
+
+ // generate VBOs and other shared data before cloning submodels
+ if (i == 0)
+ Mod_BuildVBOs();
+ }
+ mod = loadmodel;
+ Mem_Free(submodelfirstsurface);
+
+ Con_DPrintf("Stats for obj model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces);