+void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, mnode_t *node)
+{
+ int i;
+ mplane_t *plane;
+ float d;
+
+ while (1)
+ {
+ // if this is a leaf, accumulate the pvs bits
+ if (node->contents < 0)
+ {
+ if (node->contents != CONTENTS_SOLID && ((mleaf_t *)node)->pvsdata)
+ for (i = 0;i < pvsbytes;i++)
+ pvsbuffer[i] |= ((mleaf_t *)node)->pvsdata[i];
+ return;
+ }
+
+ plane = node->plane;
+ d = DotProduct(org, plane->normal) - plane->dist;
+ if (d > radius)
+ node = node->children[0];
+ else if (d < -radius)
+ node = node->children[1];
+ else
+ { // go down both
+ Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, pvsbytes, node->children[0]);
+ node = node->children[1];
+ }
+ }
+}
+
+//Calculates a PVS that is the inclusive or of all leafs within radius pixels
+//of the given point.
+int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
+{
+ int bytes = ((model->brushq1.numleafs - 1) + 7) >> 3;
+ bytes = min(bytes, pvsbufferlength);
+ memset(pvsbuffer, 0, bytes);
+ Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, sv.worldmodel->brushq1.nodes);
+ return bytes;
+}
+
+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;
+ const hull_t *hull;
+
+ VectorSubtract(inmaxs, inmins, size);
+ if (cmodel->brush.ishlbsp)
+ {
+ if (size[0] < 3)
+ hull = &cmodel->brushq1.hulls[0]; // 0x0x0
+ else if (size[0] <= 32)
+ {
+ if (size[2] < 54) // pick the nearest of 36 or 72
+ hull = &cmodel->brushq1.hulls[3]; // 32x32x36
+ else
+ hull = &cmodel->brushq1.hulls[1]; // 32x32x72
+ }
+ else
+ hull = &cmodel->brushq1.hulls[2]; // 64x64x64
+ }
+ else
+ {
+ if (size[0] < 3)
+ hull = &cmodel->brushq1.hulls[0]; // 0x0x0
+ else if (size[0] <= 32)
+ hull = &cmodel->brushq1.hulls[1]; // 32x32x56
+ else
+ hull = &cmodel->brushq1.hulls[2]; // 64x64x88
+ }
+ VectorCopy(inmins, outmins);
+ VectorAdd(inmins, hull->clip_size, outmaxs);
+}
+
+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_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
+void Mod_Q1BSP_Load(model_t *mod, void *buffer)
+{
+ 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;
+
+ header = (dheader_t *)buffer;
+
+ i = LittleLong(header->version);
+ if (i != BSPVERSION && i != 30)
+ Host_Error("Mod_Q1BSP_Load: %s has wrong version number(%i should be %i(Quake) or 30(HalfLife))", mod->name, i, BSPVERSION);
+ mod->brush.ishlbsp = i == 30;
+
+ mod->brush.AmbientSoundLevelsForPoint = Mod_Q1BSP_AmbientSoundLevelsForPoint;
+ mod->brush.FatPVS = Mod_Q1BSP_FatPVS;
+ mod->brush.BoxTouchingPVS = Mod_Q1BSP_BoxTouchingPVS;
+ mod->brush.LightPoint = Mod_Q1BSP_LightPoint;
+ mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation;
+ mod->brush.TraceBox = Mod_Q1BSP_TraceBox;
+ mod->brush.RoundUpToHullSize = Mod_Q1BSP_RoundUpToHullSize;
+ mod->brushq1.PointInLeaf = Mod_Q1BSP_PointInLeaf;
+ mod->brushq1.BuildPVSTextureChains = Mod_Q1BSP_BuildPVSTextureChains;
+
+ if (loadmodel->isworldmodel)
+ {
+ Cvar_SetValue("halflifebsp", mod->brush.ishlbsp);
+ // until we get a texture for it...
+ R_ResetQuakeSky();
+ }
+
+// swap all the lumps
+ mod_base = (qbyte *)header;
+
+ for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
+ ((int *)header)[i] = LittleLong(((int *)header)[i]);
+
+// load into heap
+
+ // store which lightmap format to use
+ mod->brushq1.lightmaprgba = r_lightmaprgba.integer;
+
+ Mod_Q1BSP_LoadEntities(&header->lumps[LUMP_ENTITIES]);
+ Mod_Q1BSP_LoadVertexes(&header->lumps[LUMP_VERTEXES]);
+ Mod_Q1BSP_LoadEdges(&header->lumps[LUMP_EDGES]);
+ Mod_Q1BSP_LoadSurfedges(&header->lumps[LUMP_SURFEDGES]);
+ Mod_Q1BSP_LoadTextures(&header->lumps[LUMP_TEXTURES]);
+ Mod_Q1BSP_LoadLighting(&header->lumps[LUMP_LIGHTING]);
+ Mod_Q1BSP_LoadPlanes(&header->lumps[LUMP_PLANES]);
+ Mod_Q1BSP_LoadTexinfo(&header->lumps[LUMP_TEXINFO]);
+ Mod_Q1BSP_LoadFaces(&header->lumps[LUMP_FACES]);
+ Mod_Q1BSP_LoadMarksurfaces(&header->lumps[LUMP_MARKSURFACES]);
+ Mod_Q1BSP_LoadVisibility(&header->lumps[LUMP_VISIBILITY]);
+ Mod_Q1BSP_LoadLeafs(&header->lumps[LUMP_LEAFS]);
+ Mod_Q1BSP_LoadNodes(&header->lumps[LUMP_NODES]);
+ Mod_Q1BSP_LoadClipnodes(&header->lumps[LUMP_CLIPNODES]);
+ Mod_Q1BSP_LoadSubmodels(&header->lumps[LUMP_MODELS]);
+
+ if (mod->brushq1.data_compressedpvs)
+ Mem_Free(mod->brushq1.data_compressedpvs);
+ mod->brushq1.data_compressedpvs = NULL;
+ mod->brushq1.num_compressedpvs = 0;
+
+ Mod_Q1BSP_MakeHull0();
+ Mod_Q1BSP_MakePortals();
+
+ if (developer.integer)
+ Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->brushq1.numsurfaces, loadmodel->brushq1.numnodes, loadmodel->brushq1.numleafs, loadmodel->brushq1.numleafs - 1, loadmodel->brushq1.numportals);
+
+ mod->numframes = 2; // regular and alternate animation
+
+ mainmempool = mod->mempool;
+ loadname = mod->name;
+
+ Mod_Q1BSP_LoadLightList();
+ originalloadmodel = loadmodel;
+
+//
+// set up the submodels(FIXME: this is confusing)
+//
+ for (i = 0;i < mod->brush.numsubmodels;i++)
+ {
+ bm = &mod->brushq1.submodels[i];
+
+ mod->brushq1.hulls[0].firstclipnode = bm->headnode[0];
+ for (j=1 ; j<MAX_MAP_HULLS ; j++)
+ {
+ mod->brushq1.hulls[j].firstclipnode = bm->headnode[j];
+ mod->brushq1.hulls[j].lastclipnode = mod->brushq1.numclipnodes - 1;
+ }
+
+ mod->brushq1.firstmodelsurface = bm->firstface;
+ mod->brushq1.nummodelsurfaces = bm->numfaces;
+
+ // this gets altered below if sky is used
+ mod->DrawSky = NULL;
+ mod->Draw = R_Model_Brush_Draw;
+ mod->DrawFakeShadow = NULL;
+ mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
+ mod->DrawLight = R_Model_Brush_DrawLight;
+ mod->brushq1.pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(msurface_t **));
+ mod->brushq1.pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool,(mod->brushq1.nummodelsurfaces + mod->brushq1.numtextures) * sizeof(msurface_t *));
+ mod->brushq1.pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(int));
+ Mod_Q1BSP_BuildPVSTextureChains(mod);
+ Mod_Q1BSP_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
+ if (mod->brushq1.nummodelsurfaces)
+ {
+ // LordHavoc: calculate bmodel bounding box rather than trusting what it says
+ mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
+ mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
+ modelyawradius = 0;
+ modelradius = 0;
+ 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)
+ mod->DrawSky = R_Model_Brush_DrawSky;
+ // LordHavoc: submodels always clip, even if water
+ if (mod->brush.numsubmodels - 1)
+ surf->flags |= SURF_SOLIDCLIP;
+ // calculate bounding shapes
+ for (mesh = surf->mesh;mesh;mesh = mesh->chain)
+ {
+ for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
+ {
+ 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;
+ }
+ else
+ {
+ // LordHavoc: empty submodel(lacrima.bsp has such a glitch)
+ Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
+ }
+ Mod_Q1BSP_BuildSurfaceNeighbors(mod->brushq1.surfaces + mod->brushq1.firstmodelsurface, mod->brushq1.nummodelsurfaces, originalloadmodel->mempool);
+
+ mod->brushq1.visleafs = bm->visleafs;
+
+ // LordHavoc: only register submodels if it is the world
+ // (prevents bsp models from replacing world submodels)
+ if (loadmodel->isworldmodel && i < (mod->brush.numsubmodels - 1))
+ {
+ char name[10];
+ // duplicate the basic information
+ sprintf(name, "*%i", i+1);
+ loadmodel = Mod_FindName(name);
+ *loadmodel = *mod;
+ strcpy(loadmodel->name, name);
+ // textures and memory belong to the main model
+ loadmodel->texturepool = NULL;
+ loadmodel->mempool = NULL;
+ mod = loadmodel;
+ }
+ }
+
+ loadmodel = originalloadmodel;
+ //Mod_Q1BSP_ProcessLightList();
+}
+
+static void Mod_Q2BSP_LoadEntities(lump_t *l)
+{
+}
+
+static void Mod_Q2BSP_LoadPlanes(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadPlanes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadVertices(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadVertices: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadVisibility(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadVisibility: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadNodes(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadNodes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadTexInfo(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadTexInfo: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadFaces(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadFaces: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadLighting(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadLighting: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadLeafs(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadLeafs: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadLeafFaces(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadLeafBrushes(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadEdges(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadEdges: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadSurfEdges(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadSurfEdges: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadBrushes(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadBrushes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadBrushSides(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadBrushSides: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadAreas(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadAreas: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadAreaPortals(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadAreaPortals: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+static void Mod_Q2BSP_LoadModels(lump_t *l)
+{
+/*
+ d_t *in;
+ m_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q2BSP_LoadModels: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel-> = out;
+ loadmodel->num = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ }
+*/
+}
+
+void Mod_Q2BSP_Load(model_t *mod, void *buffer)
+{
+ int i;
+ q2dheader_t *header;
+
+ Host_Error("Mod_Q2BSP_Load: not yet implemented\n");
+
+ mod->type = mod_brushq2;
+
+ header = (q2dheader_t *)buffer;
+
+ i = LittleLong(header->version);
+ if (i != Q2BSPVERSION)
+ Host_Error("Mod_Q2BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q2BSPVERSION);
+ mod->brush.ishlbsp = false;
+ if (loadmodel->isworldmodel)
+ {
+ Cvar_SetValue("halflifebsp", mod->brush.ishlbsp);
+ // until we get a texture for it...
+ R_ResetQuakeSky();
+ }
+
+ mod_base = (qbyte *)header;
+
+ // swap all the lumps
+ for (i = 0;i < (int) sizeof(*header) / 4;i++)
+ ((int *)header)[i] = LittleLong(((int *)header)[i]);
+
+ // store which lightmap format to use
+ mod->brushq1.lightmaprgba = r_lightmaprgba.integer;
+
+ Mod_Q2BSP_LoadEntities(&header->lumps[Q2LUMP_ENTITIES]);
+ Mod_Q2BSP_LoadPlanes(&header->lumps[Q2LUMP_PLANES]);
+ Mod_Q2BSP_LoadVertices(&header->lumps[Q2LUMP_VERTEXES]);
+ Mod_Q2BSP_LoadVisibility(&header->lumps[Q2LUMP_VISIBILITY]);
+ Mod_Q2BSP_LoadNodes(&header->lumps[Q2LUMP_NODES]);
+ Mod_Q2BSP_LoadTexInfo(&header->lumps[Q2LUMP_TEXINFO]);
+ Mod_Q2BSP_LoadFaces(&header->lumps[Q2LUMP_FACES]);
+ Mod_Q2BSP_LoadLighting(&header->lumps[Q2LUMP_LIGHTING]);
+ Mod_Q2BSP_LoadLeafs(&header->lumps[Q2LUMP_LEAFS]);
+ Mod_Q2BSP_LoadLeafFaces(&header->lumps[Q2LUMP_LEAFFACES]);
+ Mod_Q2BSP_LoadLeafBrushes(&header->lumps[Q2LUMP_LEAFBRUSHES]);
+ Mod_Q2BSP_LoadEdges(&header->lumps[Q2LUMP_EDGES]);
+ Mod_Q2BSP_LoadSurfEdges(&header->lumps[Q2LUMP_SURFEDGES]);
+ Mod_Q2BSP_LoadBrushes(&header->lumps[Q2LUMP_BRUSHES]);
+ Mod_Q2BSP_LoadBrushSides(&header->lumps[Q2LUMP_BRUSHSIDES]);
+ Mod_Q2BSP_LoadAreas(&header->lumps[Q2LUMP_AREAS]);
+ Mod_Q2BSP_LoadAreaPortals(&header->lumps[Q2LUMP_AREAPORTALS]);
+ // LordHavoc: must go last because this makes the submodels
+ Mod_Q2BSP_LoadModels(&header->lumps[Q2LUMP_MODELS]);
+}
+
+
+static void Mod_Q3BSP_LoadEntities(lump_t *l)
+{
+ const char *data;
+ char key[128], value[4096];
+ float v[3];
+ loadmodel->brushq3.num_lightgrid_cellsize[0] = 64;
+ loadmodel->brushq3.num_lightgrid_cellsize[1] = 64;
+ loadmodel->brushq3.num_lightgrid_cellsize[2] = 128;
+ if (!l->filelen)
+ return;
+ loadmodel->brush.entities = Mem_Alloc(loadmodel->mempool, l->filelen);
+ memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen);
+ data = loadmodel->brush.entities;
+ // some Q3 maps override the lightgrid_cellsize with a worldspawn key
+ if (data && COM_ParseToken(&data, false) && com_token[0] == '{')
+ {
+ while (1)
+ {
+ if (!COM_ParseToken(&data, false))
+ break; // error
+ if (com_token[0] == '}')
+ break; // end of worldspawn
+ if (com_token[0] == '_')
+ strcpy(key, com_token + 1);
+ else
+ strcpy(key, com_token);
+ while (key[strlen(key)-1] == ' ') // remove trailing spaces
+ key[strlen(key)-1] = 0;
+ if (!COM_ParseToken(&data, false))
+ break; // error
+ strcpy(value, com_token);
+ if (!strcmp("gridsize", key))
+ {
+ if (sscanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3 && v[0] != 0 && v[1] != 0 && v[2] != 0)
+ VectorCopy(v, loadmodel->brushq3.num_lightgrid_cellsize);
+ }
+ }
+ }
+}
+
+static void Mod_Q3BSP_LoadTextures(lump_t *l)
+{
+ q3dtexture_t *in;
+ q3mtexture_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadTextures: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_textures = out;
+ loadmodel->brushq3.num_textures = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ strncpy(out->name, in->name, sizeof(out->name) - 1);
+ out->surfaceflags = LittleLong(in->surfaceflags);
+ out->contents = LittleLong(in->contents);
+
+ out->number = i;
+ Mod_LoadSkinFrame(&out->skin, out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true);
+ }
+}
+
+static void Mod_Q3BSP_LoadPlanes(lump_t *l)
+{
+ q3dplane_t *in;
+ mplane_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadPlanes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_planes = out;
+ loadmodel->brushq3.num_planes = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ out->normal[0] = LittleLong(in->normal[0]);
+ out->normal[1] = LittleLong(in->normal[1]);
+ out->normal[2] = LittleLong(in->normal[2]);
+ out->dist = LittleLong(in->dist);
+ PlaneClassify(out);
+ }
+}
+
+static void Mod_Q3BSP_LoadBrushSides(lump_t *l)
+{
+ q3dbrushside_t *in;
+ q3mbrushside_t *out;
+ int i, n, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadBrushSides: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_brushsides = out;
+ loadmodel->brushq3.num_brushsides = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ n = LittleLong(in->planeindex);
+ if (n < 0 || n >= loadmodel->brushq3.num_planes)
+ Host_Error("Mod_Q3BSP_LoadBrushSides: invalid planeindex %i (%i planes)\n", n, loadmodel->brushq3.num_planes);
+ out->plane = loadmodel->brushq3.data_planes + n;
+ n = LittleLong(in->textureindex);
+ if (n < 0 || n >= loadmodel->brushq3.num_textures)
+ Host_Error("Mod_Q3BSP_LoadBrushSides: invalid textureindex %i (%i textures)\n", n, loadmodel->brushq3.num_textures);
+ out->texture = loadmodel->brushq3.data_textures + n;
+ }
+}
+
+static void Mod_Q3BSP_LoadBrushes(lump_t *l)
+{
+ q3dbrush_t *in;
+ q3mbrush_t *out;
+ int i, j, k, m, n, c, count, numpoints, numplanes;
+ winding_t *w;
+ colpointf_t pointsbuf[256*3];
+ colplanef_t planesbuf[256], colplanef;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadBrushes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_brushes = out;
+ loadmodel->brushq3.num_brushes = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ n = LittleLong(in->firstbrushside);
+ c = LittleLong(in->numbrushsides);
+ if (n < 0 || n + c > loadmodel->brushq3.num_brushsides)
+ Host_Error("Mod_Q3BSP_LoadBrushes: invalid brushside range %i : %i (%i brushsides)\n", n, n + c, loadmodel->brushq3.num_brushsides);
+ out->firstbrushside = loadmodel->brushq3.data_brushsides + n;
+ out->numbrushsides = c;
+ n = LittleLong(in->textureindex);
+ if (n < 0 || n >= loadmodel->brushq3.num_textures)
+ Host_Error("Mod_Q3BSP_LoadBrushes: invalid textureindex %i (%i textures)\n", n, loadmodel->brushq3.num_textures);
+ out->texture = loadmodel->brushq3.data_textures + n;
+
+ // construct a collision brush, which needs points and planes...
+ // each point and plane should be unique, and they don't refer to
+ // eachother in any way, so keeping them unique is fairly easy
+ numpoints = 0;
+ numplanes = 0;
+ for (j = 0;j < out->numbrushsides;j++)
+ {
+ // create a huge polygon for the plane
+ w = BaseWindingForPlane(out->firstbrushside[j].plane);
+ // clip it by all other planes
+ for (k = 0;k < out->numbrushsides && w;k++)
+ if (k != j)
+ w = ClipWinding(w, out->firstbrushside[k].plane, true);
+ // if nothing is left, skip it
+ // FIXME: should keep count of how many were skipped and report
+ // it, just for sake of statistics
+ if (!w)
+ continue;
+ // add the points uniquely (no duplicates)
+ for (k = 0;k < w->numpoints;k++)
+ {
+ for (m = 0;m < numpoints;m++)
+ if (VectorDistance2(w->points[k * 3], pointsbuf[m * 3].v) < DIST_EPSILON)
+ break;
+ if (m == numpoints)
+ {
+ // check if there are too many and skip the brush
+ if (numpoints >= 256)
+ {
+ Con_Printf("Mod_Q3BSP_LoadBrushes: failed to build collision brush: too many points for buffer\n");
+ FreeWinding(w);
+ goto failedtomakecolbrush;
+ }
+ // add the new one
+ VectorCopy(w->points[k * 3], pointsbuf[numpoints * 3].v);
+ numpoints++;
+ }
+ }
+ // add the plane uniquely (no duplicates)
+ memset(&colplanef, 0, sizeof(colplanef));
+ VectorCopy(out->firstbrushside[k].plane->normal, colplanef.normal);
+ colplanef.dist = out->firstbrushside[k].plane->dist;
+ for (k = 0;k < numplanes;k++)
+ if (VectorCompare(planesbuf[k].normal, colplanef.normal) && planesbuf[k].dist == colplanef.dist)
+ break;
+ if (k == numplanes)
+ {
+ // check if there are too many and skip the brush
+ if (numplanes >= 256)
+ {
+ Con_Printf("Mod_Q3BSP_LoadBrushes: failed to build collision brush: too many planes for buffer\n");
+ FreeWinding(w);
+ goto failedtomakecolbrush;
+ }
+ // add the new one
+ planesbuf[numplanes++] = colplanef;
+ }
+ FreeWinding(w);
+ }
+ // if anything is left, create the collision brush
+ if (numplanes && numpoints)
+ {
+ out->colbrushf = Collision_AllocBrushFloat(loadmodel->mempool, numpoints, numplanes);
+ memcpy(out->colbrushf->points, pointsbuf, numpoints * sizeof(float[3]));
+ memcpy(out->colbrushf->planes, planesbuf, numplanes * sizeof(mplane_t));
+ }
+ // return from errors to here
+ failedtomakecolbrush:;
+ }
+}
+
+static void Mod_Q3BSP_LoadEffects(lump_t *l)
+{
+ q3deffect_t *in;
+ q3meffect_t *out;
+ int i, n, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadEffects: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_effects = out;
+ loadmodel->brushq3.num_effects = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ strncpy(out->shadername, in->shadername, sizeof(out->shadername) - 1);
+ n = LittleLong(in->brushindex);
+ if (n < 0 || n >= loadmodel->brushq3.num_brushes)
+ Host_Error("Mod_Q3BSP_LoadEffects: invalid brushindex %i (%i brushes)\n", n, loadmodel->brushq3.num_brushes);
+ out->brush = loadmodel->brushq3.data_brushes + n;
+ out->unknown = LittleLong(in->unknown);
+ }
+}
+
+static void Mod_Q3BSP_LoadVertices(lump_t *l)
+{
+ q3dvertex_t *in;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadVertices: funny lump size in %s",loadmodel->name);
+ loadmodel->brushq3.num_vertices = count = l->filelen / sizeof(*in);
+ loadmodel->brushq3.data_vertex3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3]));
+ loadmodel->brushq3.data_texturetexcoord2f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[2]));
+ loadmodel->brushq3.data_lightmaptexcoord2f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[2]));
+ loadmodel->brushq3.data_svector3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3]));
+ loadmodel->brushq3.data_tvector3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3]));
+ loadmodel->brushq3.data_normal3f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[3]));
+ loadmodel->brushq3.data_color4f = Mem_Alloc(loadmodel->mempool, count * sizeof(float[4]));
+
+ for (i = 0;i < count;i++, in++)
+ {
+ loadmodel->brushq3.data_vertex3f[i * 3 + 0] = LittleFloat(in->origin3f[0]);
+ loadmodel->brushq3.data_vertex3f[i * 3 + 1] = LittleFloat(in->origin3f[1]);
+ loadmodel->brushq3.data_vertex3f[i * 3 + 2] = LittleFloat(in->origin3f[2]);
+ loadmodel->brushq3.data_texturetexcoord2f[i * 2 + 0] = LittleFloat(in->texcoord2f[0]);
+ loadmodel->brushq3.data_texturetexcoord2f[i * 2 + 1] = LittleFloat(in->texcoord2f[1]);
+ loadmodel->brushq3.data_lightmaptexcoord2f[i * 2 + 0] = LittleFloat(in->lightmap2f[0]);
+ loadmodel->brushq3.data_lightmaptexcoord2f[i * 2 + 1] = LittleFloat(in->lightmap2f[1]);
+ // svector/tvector are calculated later in face loading
+ loadmodel->brushq3.data_svector3f[i * 3 + 0] = 0;
+ loadmodel->brushq3.data_svector3f[i * 3 + 1] = 0;
+ loadmodel->brushq3.data_svector3f[i * 3 + 2] = 0;
+ loadmodel->brushq3.data_tvector3f[i * 3 + 0] = 0;
+ loadmodel->brushq3.data_tvector3f[i * 3 + 1] = 0;
+ loadmodel->brushq3.data_tvector3f[i * 3 + 2] = 0;
+ loadmodel->brushq3.data_normal3f[i * 3 + 0] = LittleFloat(in->normal3f[0]);
+ loadmodel->brushq3.data_normal3f[i * 3 + 1] = LittleFloat(in->normal3f[1]);
+ loadmodel->brushq3.data_normal3f[i * 3 + 2] = LittleFloat(in->normal3f[2]);
+ loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f);
+ loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f);
+ loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f);
+ loadmodel->brushq3.data_color4f[i * 4 + 3] = in->color4ub[3] * (1.0f / 255.0f);
+ }
+}
+
+static void Mod_Q3BSP_LoadTriangles(lump_t *l)
+{
+ int *in;
+ int *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(int[3]))
+ Host_Error("Mod_Q3BSP_LoadTriangles: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.num_triangles = count / 3;
+ loadmodel->brushq3.data_element3i = out;
+ loadmodel->brushq3.data_neighbor3i = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ *out = LittleLong(*in);
+ if (*out < 0 || *out >= loadmodel->brushq3.num_vertices)
+ Host_Error("Mod_Q3BSP_LoadTriangles: invalid vertexindex %i (%i vertices)\n", *out, loadmodel->brushq3.num_vertices);
+ }
+}
+
+static void Mod_Q3BSP_LoadLightmaps(lump_t *l)
+{
+ q3dlightmap_t *in;
+ rtexture_t **out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadLightmaps: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_lightmaps = out;
+ loadmodel->brushq3.num_lightmaps = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ *out = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), 128, 128, in->rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+}
+
+static void Mod_Q3BSP_LoadFaces(lump_t *l)
+{
+ q3dface_t *in;
+ q3mface_t *out;
+ int i, j, n, count, invalidelements, patchsize[2];
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadFaces: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_faces = out;
+ loadmodel->brushq3.num_faces = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ // check face type first
+ out->type = LittleLong(in->type);
+ if (out->type != Q3FACETYPE_POLYGON
+ && out->type != Q3FACETYPE_PATCH
+ && out->type != Q3FACETYPE_MESH
+ && out->type != Q3FACETYPE_FLARE)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, out->type);
+ out->type = 0; // error
+ continue;
+ }
+
+ n = LittleLong(in->textureindex);
+ if (n < 0 || n >= loadmodel->brushq3.num_textures)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->brushq3.num_textures);
+ out->type = 0; // error
+ continue;
+ n = 0;
+ }
+ out->texture = loadmodel->brushq3.data_textures + n;
+ n = LittleLong(in->effectindex);
+ if (n < -1 || n >= loadmodel->brushq3.num_effects)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
+ n = -1;
+ }
+ if (n == -1)
+ out->effect = NULL;
+ else
+ out->effect = loadmodel->brushq3.data_effects + n;
+ n = LittleLong(in->lightmapindex);
+ if (n < -1 || n >= loadmodel->brushq3.num_lightmaps)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps);
+ n = -1;
+ }
+ if (n == -1)
+ out->lightmaptexture = NULL;
+ else
+ out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
+
+ out->firstvertex = LittleLong(in->firstvertex);
+ out->numvertices = LittleLong(in->numvertices);
+ out->firstelement = LittleLong(in->firstelement);
+ out->numelements = LittleLong(in->numelements);
+ out->numtriangles = out->numelements / 3;
+ if (out->firstvertex < 0 || out->firstvertex + out->numvertices > loadmodel->brushq3.num_vertices)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, out->firstvertex, out->firstvertex + out->numvertices, loadmodel->brushq3.num_vertices);
+ out->type = 0; // error
+ continue;
+ }
+ if (out->firstelement < 0 || out->firstelement + out->numelements > loadmodel->brushq3.num_triangles * 3)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, out->firstelement, out->firstelement + out->numelements, loadmodel->brushq3.num_triangles * 3);
+ out->type = 0; // error
+ continue;
+ }
+ if (out->numtriangles * 3 != out->numelements)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, out->numelements);
+ out->type = 0; // error
+ continue;
+ }
+ switch(out->type)
+ {
+ case Q3FACETYPE_POLYGON:
+ case Q3FACETYPE_MESH:
+ out->data_vertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3;
+ out->data_texturetexcoord2f = loadmodel->brushq3.data_texturetexcoord2f + out->firstvertex * 2;
+ out->data_lightmaptexcoord2f = loadmodel->brushq3.data_lightmaptexcoord2f + out->firstvertex * 2;
+ out->data_svector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3;
+ out->data_tvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3;
+ out->data_normal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3;
+ out->data_color4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4;
+ out->data_element3i = loadmodel->brushq3.data_element3i + out->firstelement;
+ out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement;
+ break;
+ case Q3FACETYPE_PATCH:
+ patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
+ patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
+ if (patchsize[0] < 1 || patchsize[1] < 1)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]);
+ out->type = 0; // error
+ continue;
+ }
+ // FIXME: convert patch to triangles here!
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_PATCH not supported (yet)\n", i, out->texture->name);
+ out->type = 0;
+ continue;
+ break;
+ case Q3FACETYPE_FLARE:
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
+ out->type = 0;
+ continue;
+ break;
+ }
+ for (j = 0, invalidelements = 0;j < out->numelements;j++)
+ if (out->data_element3i[j] < 0 || out->data_element3i[j] >= out->numvertices)
+ invalidelements++;
+ if (invalidelements)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->contents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, out->type, out->texture->name, out->texture->surfaceflags, out->texture->contents, out->firstvertex, out->numvertices, out->firstelement, out->numelements);
+ for (j = 0;j < out->numelements;j++)
+ {
+ Con_Printf(" %i", out->data_element3i[j]);
+ if (out->data_element3i[j] < 0 || out->data_element3i[j] >= out->numvertices)
+ out->data_element3i[j] = 0;
+ }
+ Con_Printf("\n");
+ }
+ }
+}
+
+static void Mod_Q3BSP_LoadModels(lump_t *l)
+{
+ q3dmodel_t *in;
+ q3mmodel_t *out;
+ int i, j, n, c, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadModels: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_models = out;
+ loadmodel->brushq3.num_models = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ for (j = 0;j < 3;j++)
+ {
+ out->mins[j] = LittleFloat(in->mins[j]);
+ out->maxs[j] = LittleFloat(in->maxs[j]);
+ }
+ n = LittleLong(in->firstface);
+ c = LittleLong(in->numfaces);
+ if (n < 0 || n + c > loadmodel->brushq3.num_faces)
+ Host_Error("Mod_Q3BSP_LoadModels: invalid face range %i : %i (%i faces)\n", n, n + c, loadmodel->brushq3.num_faces);
+ out->firstface = loadmodel->brushq3.data_faces + n;
+ out->numfaces = c;
+ n = LittleLong(in->firstbrush);
+ c = LittleLong(in->numbrushes);
+ if (n < 0 || n + c > loadmodel->brushq3.num_brushes)
+ Host_Error("Mod_Q3BSP_LoadModels: invalid brush range %i : %i (%i brushes)\n", n, n + c, loadmodel->brushq3.num_brushes);
+ out->firstbrush = loadmodel->brushq3.data_brushes + n;
+ out->numbrushes = c;
+ }
+}
+
+static void Mod_Q3BSP_LoadLeafBrushes(lump_t *l)
+{
+ int *in;
+ q3mbrush_t **out;
+ int i, n, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_leafbrushes = out;
+ loadmodel->brushq3.num_leafbrushes = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ n = LittleLong(*in);
+ if (n < 0 || n >= loadmodel->brushq3.num_brushes)
+ Host_Error("Mod_Q3BSP_LoadLeafBrushes: invalid brush index %i (%i brushes)\n", n, loadmodel->brushq3.num_brushes);
+ *out = loadmodel->brushq3.data_brushes + n;
+ }
+}
+
+static void Mod_Q3BSP_LoadLeafFaces(lump_t *l)
+{
+ int *in;
+ q3mface_t **out;
+ int i, n, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_leaffaces = out;
+ loadmodel->brushq3.num_leaffaces = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ n = LittleLong(*in);
+ if (n < 0 || n >= loadmodel->brushq3.num_faces)
+ Host_Error("Mod_Q3BSP_LoadLeafFaces: invalid face index %i (%i faces)\n", n, loadmodel->brushq3.num_faces);
+ *out = loadmodel->brushq3.data_faces + n;
+ }
+}
+
+static void Mod_Q3BSP_LoadLeafs(lump_t *l)
+{
+ q3dleaf_t *in;
+ q3mleaf_t *out;
+ int i, j, n, c, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadLeafs: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_leafs = out;
+ loadmodel->brushq3.num_leafs = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ out->isnode = false;
+ out->parent = NULL;
+ out->clusterindex = LittleLong(in->clusterindex);
+ out->areaindex = LittleLong(in->areaindex);
+ for (j = 0;j < 3;j++)
+ {
+ // yes the mins/maxs are ints
+ out->mins[j] = LittleLong(in->mins[j]);
+ out->maxs[j] = LittleLong(in->maxs[j]);
+ }
+ n = LittleLong(in->firstleafface);
+ c = LittleLong(in->numleaffaces);
+ if (n < 0 || n + c > loadmodel->brushq3.num_leaffaces)
+ Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafface range %i : %i (%i leaffaces)\n", n, n + c, loadmodel->brushq3.num_leaffaces);
+ out->firstleafface = loadmodel->brushq3.data_leaffaces + n;
+ out->numleaffaces = c;
+ n = LittleLong(in->firstleafbrush);
+ c = LittleLong(in->numleafbrushes);
+ if (n < 0 || n + c > loadmodel->brushq3.num_leafbrushes)
+ Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafbrush range %i : %i (%i leafbrushes)\n", n, n + c, loadmodel->brushq3.num_leafbrushes);
+ out->firstleafbrush = loadmodel->brushq3.data_leafbrushes + n;
+ out->numleafbrushes = c;
+ }
+}
+
+static void Mod_Q3BSP_LoadNodes_RecursiveSetParent(q3mnode_t *node, q3mnode_t *parent)
+{
+ if (node->parent)
+ Host_Error("Mod_Q3BSP_LoadNodes_RecursiveSetParent: runaway recursion\n");
+ node->parent = parent;
+ if (node->isnode)
+ {
+ Mod_Q3BSP_LoadNodes_RecursiveSetParent(node->children[0], node);
+ Mod_Q3BSP_LoadNodes_RecursiveSetParent(node->children[1], node);
+ }
+}
+
+static void Mod_Q3BSP_LoadNodes(lump_t *l)
+{
+ q3dnode_t *in;
+ q3mnode_t *out;
+ int i, j, n, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadNodes: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->brushq3.data_nodes = out;
+ loadmodel->brushq3.num_nodes = count;
+
+ for (i = 0;i < count;i++, in++, out++)
+ {
+ out->isnode = true;
+ out->parent = NULL;
+ n = LittleLong(in->planeindex);
+ if (n < 0 || n >= loadmodel->brushq3.num_planes)
+ Host_Error("Mod_Q3BSP_LoadNodes: invalid planeindex %i (%i planes)\n", n, loadmodel->brushq3.num_planes);
+ out->plane = loadmodel->brushq3.data_planes + n;
+ for (j = 0;j < 2;j++)
+ {
+ n = LittleLong(in->childrenindex[j]);
+ if (n >= 0)
+ {
+ if (n >= loadmodel->brushq3.num_nodes)
+ Host_Error("Mod_Q3BSP_LoadNodes: invalid child node index %i (%i nodes)\n", n, loadmodel->brushq3.num_nodes);
+ out->children[j] = loadmodel->brushq3.data_nodes + n;
+ }
+ else
+ {
+ n = 1 - n;
+ if (n >= loadmodel->brushq3.num_leafs)
+ Host_Error("Mod_Q3BSP_LoadNodes: invalid child leaf index %i (%i leafs)\n", n, loadmodel->brushq3.num_leafs);
+ out->children[j] = (q3mnode_t *)(loadmodel->brushq3.data_leafs + n);
+ }
+ }
+ // we don't load the mins/maxs
+ }
+
+ // set the parent pointers
+ Mod_Q3BSP_LoadNodes_RecursiveSetParent(loadmodel->brushq3.data_nodes, NULL);
+}
+
+static void Mod_Q3BSP_LoadLightGrid(lump_t *l)
+{
+ q3dlightgrid_t *in;
+ q3dlightgrid_t *out;
+ int count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadLightGrid: funny lump size in %s",loadmodel->name);
+ loadmodel->brushq3.num_lightgrid_scale[0] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[0];
+ loadmodel->brushq3.num_lightgrid_scale[1] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[1];
+ loadmodel->brushq3.num_lightgrid_scale[2] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[2];
+ loadmodel->brushq3.num_lightgrid_imins[0] = ceil(loadmodel->brushq3.data_models->mins[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
+ loadmodel->brushq3.num_lightgrid_imins[1] = ceil(loadmodel->brushq3.data_models->mins[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
+ loadmodel->brushq3.num_lightgrid_imins[2] = ceil(loadmodel->brushq3.data_models->mins[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
+ loadmodel->brushq3.num_lightgrid_imaxs[0] = floor(loadmodel->brushq3.data_models->maxs[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
+ loadmodel->brushq3.num_lightgrid_imaxs[1] = floor(loadmodel->brushq3.data_models->maxs[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
+ loadmodel->brushq3.num_lightgrid_imaxs[2] = floor(loadmodel->brushq3.data_models->maxs[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
+ loadmodel->brushq3.num_lightgrid_isize[0] = loadmodel->brushq3.num_lightgrid_imaxs[0] - loadmodel->brushq3.num_lightgrid_imins[0] + 1;
+ loadmodel->brushq3.num_lightgrid_isize[1] = loadmodel->brushq3.num_lightgrid_imaxs[1] - loadmodel->brushq3.num_lightgrid_imins[1] + 1;
+ loadmodel->brushq3.num_lightgrid_isize[2] = loadmodel->brushq3.num_lightgrid_imaxs[2] - loadmodel->brushq3.num_lightgrid_imins[2] + 1;
+ count = loadmodel->brushq3.num_lightgrid_isize[0] * loadmodel->brushq3.num_lightgrid_isize[1] * loadmodel->brushq3.num_lightgrid_isize[2];
+ if (l->filelen < count * (int)sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)\n", l->filelen, count * sizeof(*in), loadmodel->brushq3.num_lightgrid_dimensions[0], loadmodel->brushq3.num_lightgrid_dimensions[1], loadmodel->brushq3.num_lightgrid_dimensions[2]);
+ if (l->filelen != count * (int)sizeof(*in))
+ Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i\n", count * sizeof(*in), l->filelen);
+
+ out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+ loadmodel->brushq3.data_lightgrid = out;
+ loadmodel->brushq3.num_lightgrid = count;
+
+ // no swapping or validation necessary
+ memcpy(out, in, count * (int)sizeof(*out));
+
+ Matrix4x4_CreateScale3(&loadmodel->brushq3.num_lightgrid_indexfromworld, loadmodel->brushq3.num_lightgrid_scale[0], loadmodel->brushq3.num_lightgrid_scale[1], loadmodel->brushq3.num_lightgrid_scale[2]);
+ Matrix4x4_ConcatTranslate(&loadmodel->brushq3.num_lightgrid_indexfromworld, -loadmodel->brushq3.num_lightgrid_imins[0] * loadmodel->brushq3.num_lightgrid_cellsize[0], -loadmodel->brushq3.num_lightgrid_imins[1] * loadmodel->brushq3.num_lightgrid_cellsize[1], -loadmodel->brushq3.num_lightgrid_imins[2] * loadmodel->brushq3.num_lightgrid_cellsize[2]);
+}
+
+static void Mod_Q3BSP_LoadPVS(lump_t *l)
+{
+ q3dpvs_t *in;
+ int totalchains;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen < 9)
+ Host_Error("Mod_Q3BSP_LoadPVS: funny lump size in %s",loadmodel->name);
+
+ loadmodel->brushq3.num_pvsclusters = LittleLong(in->numclusters);
+ loadmodel->brushq3.num_pvschainlength = LittleLong(in->chainlength);
+ if (loadmodel->brushq3.num_pvschainlength < ((loadmodel->brushq3.num_pvsclusters + 7) / 8))
+ Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8\n", loadmodel->brushq3.num_pvschainlength, loadmodel->brushq3.num_pvsclusters);
+ totalchains = loadmodel->brushq3.num_pvschainlength * loadmodel->brushq3.num_pvsclusters;
+ if (l->filelen < totalchains + (int)sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadPVS: lump too small ((numclusters = %i) * (chainlength = %i) + sizeof(q3dpvs_t) == %i bytes, lump is %i bytes)\n", loadmodel->brushq3.num_pvsclusters, loadmodel->brushq3.num_pvschainlength, totalchains + sizeof(*in), l->filelen);
+
+ loadmodel->brushq3.data_pvschains = Mem_Alloc(loadmodel->mempool, totalchains);
+ memcpy(loadmodel->brushq3.data_pvschains, (qbyte *)(in + 1), totalchains);
+}
+
+void Mod_Q3BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3_t out, vec_t radius)
+{
+ // FIXME: finish this code
+ VectorCopy(in, out);
+}
+
+void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end)
+{
+ if (node->isnode)
+ {
+ // recurse down node sides
+ int i;
+ float dist;
+ colpointf_t *ps, *pe;
+ // FIXME? if TraceBrushPolygonTransform were to be made usable, the
+ // node planes would need to be transformed too
+ dist = node->plane->dist - (1.0f / 8.0f);
+ for (i = 0, ps = thisbrush_start->points, pe = thisbrush_end->points;i < thisbrush_start->numpoints;i++, ps++, pe++)
+ {
+ if (DotProduct(ps->v, node->plane->normal) > dist || DotProduct(pe->v, node->plane->normal) > dist)
+ {
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end);
+ break;
+ }
+ }
+ dist = node->plane->dist + (1.0f / 8.0f);
+ for (i = 0, ps = thisbrush_start->points, pe = thisbrush_end->points;i < thisbrush_start->numpoints;i++, ps++, pe++)
+ {
+ if (DotProduct(ps->v, node->plane->normal) < dist || DotProduct(pe->v, node->plane->normal) < dist)
+ {
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end);
+ break;
+ }
+ }
+ /*
+ sides = BoxOnPlaneSide(boxstartmins, boxstartmaxs, node->plane) | BoxOnPlaneSide(boxendmins, boxendmaxs, node->plane);
+ if (sides & 1)
+ Mod_Q3BSP_TraceBox_RecursiveBSPNode(trace, node->children[0], boxstartmins, boxstartmaxs, boxendmins, boxendmaxs);
+ if (sides & 2)
+ Mod_Q3BSP_TraceBox_RecursiveBSPNode(trace, node->children[1], boxstartmins, boxstartmaxs, boxendmins, boxendmaxs);
+ */
+ }
+ else
+ {
+ int i;
+ q3mleaf_t *leaf;
+ leaf = (q3mleaf_t *)node;
+ for (i = 0;i < leaf->numleafbrushes;i++)
+ Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+ }
+}
+
+void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
+{
+ // FIXME: write this
+ ambientcolor[0] += 255;
+ ambientcolor[1] += 255;
+ ambientcolor[2] += 255;
+}
+
+void Mod_Q3BSP_TraceBox(model_t *model, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs)
+{
+ int i;
+ colbrushf_t *thisbrush_start, *thisbrush_end;
+ matrix4x4_t startmatrix, endmatrix;
+ // FIXME: finish this code
+ Matrix4x4_CreateIdentity(&startmatrix);
+ Matrix4x4_CreateIdentity(&endmatrix);
+ thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs);
+ thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
+ memset(trace, 0, sizeof(*trace));
+ trace->fraction = 1;
+ if (model->brushq3.num_nodes)
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model->brushq3.data_nodes, thisbrush_start, thisbrush_end);
+ else
+ for (i = 0;i < model->brushq3.num_brushes;i++)
+ Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, model->brushq3.data_brushes[i].colbrushf, model->brushq3.data_brushes[i].colbrushf);
+}
+
+
+static int Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(const model_t *model, const q3mnode_t *node, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
+{
+ int clusterindex;
+loc0:
+ if (!node->isnode)
+ {
+ // leaf
+ clusterindex = ((q3mleaf_t *)node)->clusterindex;
+ return pvs[clusterindex >> 3] & (1 << (clusterindex & 7));
+ }
+
+ // node - recurse down the BSP tree
+ switch (BoxOnPlaneSide(mins, maxs, node->plane))
+ {
+ case 1: // front
+ node = node->children[0];
+ goto loc0;
+ case 2: // back
+ node = node->children[1];
+ goto loc0;
+ default: // crossing
+ if (Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(model, node->children[0], pvs, mins, maxs))
+ return true;
+ node = node->children[1];
+ goto loc0;
+ }
+ // never reached
+ return false;
+}
+
+int Mod_Q3BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
+{
+ return Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(model, model->brushq3.data_nodes, pvs, mins, maxs);
+}
+
+int Mod_Q3BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
+{
+ // FIXME: write this
+ memset(pvsbuffer, 0xFF, pvsbufferlength);
+ return pvsbufferlength;
+}
+
+//extern void R_Q3BSP_DrawSky(struct entity_render_s *ent);
+extern void R_Q3BSP_Draw(struct entity_render_s *ent);
+//extern void R_Q3BSP_DrawFakeShadow(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_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
+void Mod_Q3BSP_Load(model_t *mod, void *buffer)
+{
+ int i;
+ q3dheader_t *header;
+
+ mod->type = mod_brushq2;
+
+ header = (q3dheader_t *)buffer;
+
+ i = LittleLong(header->version);
+ if (i != Q3BSPVERSION)
+ Host_Error("Mod_Q3BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q3BSPVERSION);
+ if (loadmodel->isworldmodel)
+ {
+ Cvar_SetValue("halflifebsp", false);
+ // until we get a texture for it...
+ R_ResetQuakeSky();
+ }
+
+ mod->brush.FatPVS = Mod_Q3BSP_FatPVS;
+ mod->brush.BoxTouchingPVS = Mod_Q3BSP_BoxTouchingPVS;
+ mod->brush.LightPoint = Mod_Q3BSP_LightPoint;
+ mod->brush.FindNonSolidLocation = Mod_Q3BSP_FindNonSolidLocation;
+ mod->brush.TraceBox = Mod_Q3BSP_TraceBox;
+ //mod->DrawSky = R_Q3BSP_DrawSky;
+ mod->Draw = R_Q3BSP_Draw;
+ //mod->DrawFakeShadow = R_Q3BSP_DrawFakeShadow;
+ //mod->DrawShadowVolume = R_Q3BSP_DrawShadowVolume;
+ //mod->DrawLight = R_Q3BSP_DrawLight;
+
+ mod_base = (qbyte *)header;
+
+ // swap all the lumps
+ for (i = 0;i < (int) sizeof(*header) / 4;i++)
+ ((int *)header)[i] = LittleLong(((int *)header)[i]);
+
+ Mod_Q3BSP_LoadEntities(&header->lumps[Q3LUMP_ENTITIES]);
+ Mod_Q3BSP_LoadTextures(&header->lumps[Q3LUMP_TEXTURES]);
+ Mod_Q3BSP_LoadPlanes(&header->lumps[Q3LUMP_PLANES]);
+ Mod_Q3BSP_LoadBrushSides(&header->lumps[Q3LUMP_BRUSHSIDES]);
+ Mod_Q3BSP_LoadBrushes(&header->lumps[Q3LUMP_BRUSHES]);
+ Mod_Q3BSP_LoadEffects(&header->lumps[Q3LUMP_EFFECTS]);
+ Mod_Q3BSP_LoadVertices(&header->lumps[Q3LUMP_VERTICES]);
+ Mod_Q3BSP_LoadTriangles(&header->lumps[Q3LUMP_TRIANGLES]);
+ Mod_Q3BSP_LoadLightmaps(&header->lumps[Q3LUMP_LIGHTMAPS]);
+ Mod_Q3BSP_LoadFaces(&header->lumps[Q3LUMP_FACES]);
+ Mod_Q3BSP_LoadModels(&header->lumps[Q3LUMP_MODELS]);
+ Mod_Q3BSP_LoadLeafBrushes(&header->lumps[Q3LUMP_LEAFBRUSHES]);
+ Mod_Q3BSP_LoadLeafFaces(&header->lumps[Q3LUMP_LEAFFACES]);
+ Mod_Q3BSP_LoadLeafs(&header->lumps[Q3LUMP_LEAFS]);
+ Mod_Q3BSP_LoadNodes(&header->lumps[Q3LUMP_NODES]);
+ Mod_Q3BSP_LoadLightGrid(&header->lumps[Q3LUMP_LIGHTGRID]);
+ Mod_Q3BSP_LoadPVS(&header->lumps[Q3LUMP_PVS]);
+}
+
+void Mod_IBSP_Load(model_t *mod, void *buffer)
+{
+ int i = LittleLong(((int *)buffer)[1]);
+ if (i == Q3BSPVERSION)
+ Mod_Q3BSP_Load(mod,buffer);
+ else if (i == Q2BSPVERSION)
+ Mod_Q2BSP_Load(mod,buffer);
+ else
+ Host_Error("Mod_IBSP_Load: unknown/unsupported version %i\n", i);
+}
+
+void Mod_MAP_Load(model_t *mod, void *buffer)
+{
+ Host_Error("Mod_MAP_Load: not yet implemented\n");
+}
+