+void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
+{
+ int i, j;
+ float *v;
+
+ mins[0] = mins[1] = mins[2] = 9999;
+ maxs[0] = maxs[1] = maxs[2] = -9999;
+ v = verts;
+ for (i = 0;i < numverts;i++)
+ {
+ for (j = 0;j < 3;j++, v++)
+ {
+ if (*v < mins[j])
+ mins[j] = *v;
+ if (*v > maxs[j])
+ maxs[j] = *v;
+ }
+ }
+}
+
+#if 0
+#define MAX_SUBDIVPOLYTRIANGLES 4096
+#define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
+
+static int subdivpolyverts, subdivpolytriangles;
+static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
+static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
+
+static int subdivpolylookupvert(vec3_t v)
+{
+ int i;
+ for (i = 0;i < subdivpolyverts;i++)
+ if (subdivpolyvert[i][0] == v[0]
+ && subdivpolyvert[i][1] == v[1]
+ && subdivpolyvert[i][2] == v[2])
+ return i;
+ if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
+ Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
+ VectorCopy(v, subdivpolyvert[subdivpolyverts]);
+ return subdivpolyverts++;
+}
+
+static void SubdividePolygon (int numverts, float *verts)
+{
+ int i, i1, i2, i3, f, b, c, p;
+ vec3_t mins, maxs, front[256], back[256];
+ float m, *pv, *cv, dist[256], frac;
+
+ if (numverts > 250)
+ Host_Error ("SubdividePolygon: ran out of verts in buffer");
+
+ BoundPoly (numverts, verts, mins, maxs);
+
+ for (i = 0;i < 3;i++)
+ {
+ m = (mins[i] + maxs[i]) * 0.5;
+ m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
+ if (maxs[i] - m < 8)
+ continue;
+ if (m - mins[i] < 8)
+ continue;
+
+ // cut it
+ for (cv = verts, c = 0;c < numverts;c++, cv += 3)
+ dist[c] = cv[i] - m;
+
+ f = b = 0;
+ for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
+ {
+ if (dist[p] >= 0)
+ {
+ VectorCopy (pv, front[f]);
+ f++;
+ }
+ if (dist[p] <= 0)
+ {
+ VectorCopy (pv, back[b]);
+ b++;
+ }
+ if (dist[p] == 0 || dist[c] == 0)
+ continue;
+ if ( (dist[p] > 0) != (dist[c] > 0) )
+ {
+ // clip point
+ frac = dist[p] / (dist[p] - dist[c]);
+ front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
+ front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
+ front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
+ f++;
+ b++;
+ }
+ }
+
+ SubdividePolygon (f, front[0]);
+ SubdividePolygon (b, back[0]);
+ return;
+ }
+
+ i1 = subdivpolylookupvert(verts);
+ i2 = subdivpolylookupvert(verts + 3);
+ for (i = 2;i < numverts;i++)
+ {
+ if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
+ {
+ Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
+ return;
+ }
+
+ i3 = subdivpolylookupvert(verts + i * 3);
+ subdivpolyindex[subdivpolytriangles][0] = i1;
+ subdivpolyindex[subdivpolytriangles][1] = i2;
+ subdivpolyindex[subdivpolytriangles][2] = i3;
+ i2 = i3;
+ subdivpolytriangles++;
+ }
+}
+
+/*
+================
+Mod_GenerateWarpMesh
+
+Breaks a polygon up along axial 64 unit
+boundaries so that turbulent and sky warps
+can be done reasonably.
+================
+*/
+void Mod_GenerateWarpMesh (msurface_t *surf)
+{
+ int i, j;
+ surfvertex_t *v;
+ surfmesh_t *mesh;
+
+ subdivpolytriangles = 0;
+ subdivpolyverts = 0;
+ SubdividePolygon (surf->poly_numverts, surf->poly_verts);
+ if (subdivpolytriangles < 1)
+ Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
+
+ surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
+ mesh->numverts = subdivpolyverts;
+ mesh->numtriangles = subdivpolytriangles;
+ mesh->vertex = (surfvertex_t *)(mesh + 1);
+ mesh->index = (int *)(mesh->vertex + mesh->numverts);
+ memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
+
+ for (i = 0;i < mesh->numtriangles;i++)
+ for (j = 0;j < 3;j++)
+ mesh->index[i*3+j] = subdivpolyindex[i][j];
+
+ for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
+ {
+ VectorCopy(subdivpolyvert[i], v->v);
+ v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
+ v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
+ }
+}
+#endif
+
+void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
+{
+ 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;
+}