+ int i, iu, iv, *index, smax, tmax;
+ float *in, s, t, u, v, ubase, vbase, uscale, vscale;
+ surfmesh_t *mesh;
+
+ smax = surf->extents[0] >> 4;
+ tmax = surf->extents[1] >> 4;
+
+ if (vertexonly)
+ {
+ surf->lightmaptexturestride = 0;
+ surf->lightmaptexture = NULL;
+ uscale = 0;
+ vscale = 0;
+ ubase = 0;
+ vbase = 0;
+ }
+ else
+ {
+ surf->flags |= SURF_LIGHTMAP;
+ if (r_miplightmaps.integer)
+ {
+ surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
+ surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE);
+ }
+ else
+ {
+ surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
+ surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
+ }
+ 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);
+ }
+
+ surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * (4 + 2 + 2 + 2 + 1) * sizeof(float));
+ mesh->numverts = surf->poly_numverts;
+ mesh->numtriangles = surf->poly_numverts - 2;
+ mesh->verts = (float *)(mesh + 1);
+ mesh->st = mesh->verts + mesh->numverts * 4;
+ mesh->uv = mesh->st + mesh->numverts * 2;
+ mesh->ab = mesh->uv + mesh->numverts * 2;
+ mesh->lightmapoffsets = (int *)(mesh->ab + mesh->numverts * 2);
+ mesh->index = mesh->lightmapoffsets + mesh->numverts;
+
+ 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;i < mesh->numverts;i++, in += 3)
+ {
+ 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
+ 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->st[i * 2 + 0] = s / surf->texinfo->texture->width;
+ mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
+ mesh->uv[i * 2 + 0] = u;
+ mesh->uv[i * 2 + 1] = v;
+ mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
+ mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
+ mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
+ }
+}
+
+void Mod_GenerateVertexMesh (msurface_t *surf)
+{
+ int i, *index;
+ float *in, s, t;
+ 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 * (4 + 2 + 2) * sizeof(float));
+ mesh->numverts = surf->poly_numverts;
+ mesh->numtriangles = surf->poly_numverts - 2;
+ mesh->verts = (float *)(mesh + 1);
+ mesh->st = mesh->verts + mesh->numverts * 4;
+ mesh->ab = mesh->st + mesh->numverts * 2;
+ mesh->index = (int *)(mesh->ab + mesh->numverts * 2);
+
+ 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;i < mesh->numverts;i++, in += 3)
+ {
+ 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->st[i * 2 + 0] = s / surf->texinfo->texture->width;
+ mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
+ mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
+ mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
+ }
+}
+
+void Mod_GenerateSurfacePolygon (msurface_t *surf)
+{
+ int i, lindex;
+ float *vec, *vert, mins[3], maxs[3];
+
+ // convert edges back to a normal polygon
+ surf->poly_numverts = surf->numedges;
+ vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
+ for (i = 0;i < surf->numedges;i++)
+ {
+ lindex = loadmodel->surfedges[surf->firstedge + i];
+ if (lindex > 0)
+ vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
+ else
+ vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
+ VectorCopy (vec, vert);
+ vert += 3;
+ }
+ vert = surf->poly_verts;
+ VectorCopy(vert, mins);
+ VectorCopy(vert, maxs);
+ vert += 3;
+ for (i = 1;i < surf->poly_numverts;i++)
+ {
+ 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];
+ vert += 3;
+ }
+ 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;
+}
+
+/*
+=================
+Mod_LoadFaces
+=================
+*/
+static void Mod_LoadFaces (lump_t *l)
+{
+ dface_t *in;
+ msurface_t *out;
+ int i, count, surfnum, planenum, ssize, tsize;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
+
+ loadmodel->surfaces = out;
+ loadmodel->numsurfaces = count;
+ loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
+ loadmodel->surfacepvsframes = 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);
+ if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
+ Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
+
+ i = LittleShort (in->texinfo);
+ if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
+ Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
+ out->texinfo = loadmodel->texinfo + i;
+ out->flags = out->texinfo->texture->flags;
+
+ planenum = LittleShort(in->planenum);
+ if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
+ Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
+
+ if (LittleShort(in->side))
+ out->flags |= SURF_PLANEBACK;
+
+ out->plane = loadmodel->planes + planenum;
+
+ // clear lightmap (filled in later)
+ out->lightmaptexture = NULL;
+
+ // force lightmap upload on first time seeing the surface
+ out->cached_dlight = true;
+ out->cached_ambient = -1000;
+ out->cached_lightscalebit = -1000;
+
+ CalcSurfaceExtents (out);
+
+ ssize = (out->extents[0] >> 4) + 1;
+ tsize = (out->extents[1] >> 4) + 1;
+
+ // lighting info
+ for (i = 0;i < MAXLIGHTMAPS;i++)
+ out->styles[i] = in->styles[i];
+ i = LittleLong(in->lightofs);
+ if (i == -1)
+ out->samples = NULL;
+ else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
+ out->samples = loadmodel->lightdata + i;
+ else // LordHavoc: white lighting (bsp version 29)
+ out->samples = loadmodel->lightdata + (i * 3);
+
+ Mod_GenerateSurfacePolygon(out);
+ if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
+ {
+ if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
+ 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
+ Mod_GenerateVertexMesh (out);
+ }
+}
+
+/*
+=================
+Mod_SetParent
+=================
+*/
+static void Mod_SetParent (mnode_t *node, mnode_t *parent)
+{
+ node->parent = parent;
+ if (node->contents < 0)
+ return;
+ Mod_SetParent (node->children[0], node);
+ Mod_SetParent (node->children[1], node);
+}
+
+/*
+=================
+Mod_LoadNodes
+=================
+*/
+static void Mod_LoadNodes (lump_t *l)
+{
+ int i, j, count, p;
+ dnode_t *in;