+
+
+/*
+// svbspmesh_t is in model_brush.h
+
+typedef struct svbsppolygon_s
+{
+ struct svbsppolygon_s *next;
+ int numverts;
+ float *verts;
+ float normal[3], dist;
+}
+svbsppolygon_t;
+
+typedef struct svbspnode_s
+{
+ // true if this is a leaf (has no children), not a node
+ int isleaf;
+ // (shared) parent node
+ struct svbspnode_s *parent;
+ // (leaf) dark or lit leaf
+ int dark;
+ // (leaf) polygons bounding this leaf
+ svbsppolygon_t *polygons;
+ // (node) children
+ struct svbspnode_s *children[2];
+ // (node) splitting plane
+ float normal[3], dist;
+}
+svbspnode_t;
+
+svbspnode_t *Mod_SVBSP_AllocNode(svbspnode_t *parent, svbspnode_t *child0, svbspnode_t *child1, float *normal, float dist)
+{
+ svbspnode_t *node;
+ node = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t));
+ node->parent = parent;
+ node->children[0] = child0;
+ node->children[1] = child1;
+ VectorCopy(normal, node->normal);
+ node->dist = dist;
+ return node;
+}
+
+svbspnode_t *Mod_SVBSP_AllocLeaf(svbspnode_t *parent, int dark)
+{
+ svbspnode_t *leaf;
+ leaf = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t));
+ leaf->isleaf = true;
+ leaf->parent = parent;
+ leaf->dark = dark;
+ return leaf;
+}
+
+svbspnode_t *Mod_SVBSP_NewTree(void)
+{
+ return Mod_SVBSP_AllocLeaf(NULL, false);
+}
+
+void Mod_SVBSP_FreeTree(svbspnode_t *node)
+{
+ if (!node->isleaf)
+ {
+ Mod_SVBSP_FreeTree(node->children[0]);
+ Mod_SVBSP_FreeTree(node->children[1]);
+ }
+ Mem_Free(node);
+}
+
+void Mod_SVBSP_RecursiveAddPolygon(svbspnode_t *node, int numverts, float *verts, float *normal, float dist, int constructmode)
+{
+ int i, j, numvertsfront, numvertsback, maxverts, counts[3];
+ float *vertsfront, *vertsback, *v, d, temp[3];
+ float dists[4096];
+ qbyte sides[4096];
+ svbsppolygon_t *poly;
+ if (node->isleaf)
+ {
+ if (constructmode == 0)
+ {
+ // construct tree structure
+ node->isleaf = false;
+ node->children[0] = Mod_SVBSP_AllocLeaf(node, false);
+ node->children[1] = Mod_SVBSP_AllocLeaf(node, false);
+ VectorCopy(normal, node->normal);
+ node->dist = dist;
+ }
+ else if (constructmode == 1)
+ {
+ // mark dark leafs
+ node->dark = true;
+ }
+ else
+ {
+ // link polygons into lit leafs only (this is the optimization)
+ if (!node->dark)
+ {
+ poly = Mem_Alloc(loadmodel->mempool, sizeof(svbsppolygon_t) + numverts * sizeof(float[3]));
+ poly->numverts = numverts;
+ poly->verts = (float *)(poly + 1);
+ VectorCopy(normal, poly->normal);
+ poly->dist = dist;
+ memcpy(poly->verts, verts, numverts * sizeof(float[3]));
+ poly->next = node->polygons;
+ node->polygons = poly;
+ }
+ }
+ }
+ else
+ {
+ counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
+ for (i = 0, v = verts;i < numverts;i++, v += 3)
+ {
+ dists[i] = DotProduct(v, node->normal) - node->dist;
+ if (dists[i] >= 0.1)
+ sides[i] = SIDE_FRONT;
+ else if (dists[i] <= -0.1)
+ sides[i] = SIDE_BACK;
+ else
+ sides[i] = SIDE_ON;
+ counts[sides[i]]++;
+ }
+ if (counts[SIDE_FRONT] && counts[SIDE_BACK])
+ {
+ // some front, some back... sliced
+ numvertsfront = 0;
+ numvertsback = 0;
+ // this is excessive, but nice for safety...
+ maxverts = numverts + 4;
+ vertsfront = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
+ vertsback = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
+ for (i = 0, j = numverts - 1;i < numverts;j = i, i++)
+ {
+ if (sides[j] == SIDE_FRONT)
+ {
+ VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]);
+ numvertsfront++;
+ if (sides[i] == SIDE_BACK)
+ {
+ d = dists[j] / (dists[j] - dists[i]);
+ VectorSubtract(&verts[i * 3], &verts[j * 3], temp);
+ VectorMA(&verts[j * 3], d, temp, temp);
+ VectorCopy(temp, &vertsfront[numvertsfront * 3]);
+ VectorCopy(temp, &vertsback[numvertsback * 3]);
+ numvertsfront++;
+ numvertsback++;
+ }
+ }
+ else if (sides[j] == SIDE_BACK)
+ {
+ VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]);
+ numvertsback++;
+ if (sides[i] == SIDE_FRONT)
+ {
+ d = dists[j] / (dists[j] - dists[i]);
+ VectorSubtract(&verts[i * 3], &verts[j * 3], temp);
+ VectorMA(&verts[j * 3], d, temp, temp);
+ VectorCopy(temp, &vertsfront[numvertsfront * 3]);
+ VectorCopy(temp, &vertsback[numvertsback * 3]);
+ numvertsfront++;
+ numvertsback++;
+ }
+ }
+ else
+ {
+ VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]);
+ VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]);
+ numvertsfront++;
+ numvertsback++;
+ }
+ }
+ Mod_SVBSP_RecursiveAddPolygon(node->children[1], numvertsfront, vertsfront, normal, dist, constructmode);
+ Mod_SVBSP_RecursiveAddPolygon(node->children[0], numvertsback, vertsback, normal, dist, constructmode);
+ Mem_Free(vertsfront);
+ Mem_Free(vertsback);
+ }
+ else if (counts[SIDE_BACK])
+ Mod_SVBSP_RecursiveAddPolygon(node->children[0], numverts, verts, normal, dist, constructmode);
+ else if (counts[SIDE_FRONT])
+ Mod_SVBSP_RecursiveAddPolygon(node->children[1], numverts, verts, normal, dist, constructmode);
+ else
+ {
+ // mode 0 is constructing tree, don't make unnecessary splits
+ if (constructmode == 1)
+ {
+ // marking dark leafs
+ // send it down the side it is not facing
+ Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) < 0], numverts, verts, normal, dist, constructmode);
+ }
+ else if (constructmode == 2)
+ {
+ // linking polygons into lit leafs only
+ // send it down the side it is facing
+ Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) >= 0], numverts, verts, normal, dist, constructmode);
+ }
+ }
+ }
+}
+
+int svbsp_count_nodes;
+int svbsp_count_leafs;
+int svbsp_count_polygons;
+int svbsp_count_darkleafs;
+int svbsp_count_originalpolygons;
+int svbsp_count_meshs;
+int svbsp_count_triangles;
+int svbsp_count_vertices;
+
+void Mod_SVBSP_AddPolygon(svbspnode_t *root, int numverts, float *verts, int constructmode, float *test, int linenumber)
+{
+ int i;
+ float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2;
+ svbsp_count_originalpolygons++;
+ for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3)
+ {
+ VectorSubtract(v0, v1, dir0);
+ VectorSubtract(v2, v1, dir1);
+ CrossProduct(dir0, dir1, normal);
+ if (DotProduct(normal, normal) >= 0.1)
+ break;
+ }
+ if (i == numverts)
+ return;
+ VectorNormalize(normal);
+ dist = DotProduct(verts, normal);
+ if (test && DotProduct(test, normal) > dist + 0.1)
+ Con_Printf("%i %f %f %f %f : %f %f %f %f\n", linenumber, normal[0], normal[1], normal[2], dist, test[0], test[1], test[2], DotProduct(test, normal));
+ Mod_SVBSP_RecursiveAddPolygon(root, numverts, verts, normal, dist, constructmode);
+}
+
+void Mod_SVBSP_RecursiveGatherStats(svbspnode_t *node)
+{
+ svbsppolygon_t *poly;
+ for (poly = node->polygons;poly;poly = poly->next)
+ svbsp_count_polygons++;
+ if (node->isleaf)
+ {
+ svbsp_count_leafs++;
+ if (node->dark)
+ svbsp_count_darkleafs++;
+ }
+ else
+ {
+ svbsp_count_nodes++;
+ Mod_SVBSP_RecursiveGatherStats(node->children[0]);
+ Mod_SVBSP_RecursiveGatherStats(node->children[1]);
+ }
+}
+
+svbspmesh_t *Mod_SVBSP_AllocMesh(int maxverts)
+{
+ svbspmesh_t *mesh;
+ mesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]));
+ mesh->maxverts = maxverts;
+ mesh->maxtriangles = maxverts;
+ mesh->numverts = 0;
+ mesh->numtriangles = 0;
+ mesh->verts = (float *)(mesh + 1);
+ mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4);
+ return mesh;
+}
+
+svbspmesh_t *Mod_SVBSP_ReAllocMesh(svbspmesh_t *oldmesh)
+{
+ svbspmesh_t *newmesh;
+ newmesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3]));
+ newmesh->maxverts = newmesh->numverts = oldmesh->numverts;
+ newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles;
+ newmesh->verts = (float *)(newmesh + 1);
+ newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4);
+ memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4]));
+ memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3]));
+ return newmesh;
+}
+
+void Mod_SVBSP_RecursiveBuildTriangleMeshs(svbspmesh_t *firstmesh, svbspnode_t *node)
+{
+ svbsppolygon_t *poly;
+ svbspmesh_t *mesh;
+ int i, j, k;
+ float *v, *m, temp[3];
+ if (node->isleaf)
+ {
+ for (poly = node->polygons;poly;poly = poly->next)
+ {
+ mesh = firstmesh;
+ while (poly->numverts + mesh->numverts > mesh->maxverts || (poly->numverts - 2) + mesh->numtriangles > mesh->maxtriangles)
+ {
+ if (mesh->next == NULL)
+ mesh->next = Mod_SVBSP_AllocMesh(max(1000, poly->numverts));
+ mesh = mesh->next;
+ }
+ for (i = 0, v = poly->verts;i < poly->numverts - 2;i++, v += 3)
+ {
+ for (k = 0;k < 3;k++)
+ {
+ if (k == 0)
+ v = poly->verts;
+ else if (k == 1)
+ v = poly->verts + (i + 1) * 3;
+ else if (k == 2)
+ v = poly->verts + (i + 2) * 3;
+ for (j = 0, m = mesh->verts;j < mesh->numverts;j++, m += 4)
+ {
+ VectorSubtract(v, m, temp);
+ if (DotProduct(temp, temp) < 0.1)
+ break;
+ }
+ if (j == mesh->numverts)
+ {
+ mesh->numverts++;
+ VectorCopy(v, m);
+ }
+ mesh->elements[mesh->numtriangles * 3 + k] = j;
+ }
+ mesh->numtriangles++;
+ }
+ }
+ }
+ else
+ {
+ Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[0]);
+ Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[1]);
+ }
+}
+
+svbspmesh_t *Mod_SVBSP_BuildTriangleMeshs(svbspnode_t *root, vec3_t mins, vec3_t maxs)
+{
+ svbspmesh_t *firstmesh, *mesh, *newmesh, *nextmesh;
+ int i;
+ float *v;
+ firstmesh = Mod_SVBSP_AllocMesh(1000);
+ Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, root);
+ // reallocate meshs to conserve space
+ for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
+ {
+ svbsp_count_meshs++;
+ svbsp_count_triangles += mesh->numtriangles;
+ svbsp_count_vertices += mesh->numverts;
+
+ // calculate bbox
+ if (firstmesh == NULL)
+ {
+ VectorCopy(mesh->verts, mins);
+ VectorCopy(mesh->verts, maxs);
+ }
+ for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4)
+ {
+ if (mins[0] > v[0]) mins[0] = v[0];if (maxs[0] < v[0]) maxs[0] = v[0];
+ if (mins[1] > v[1]) mins[1] = v[1];if (maxs[1] < v[1]) maxs[1] = v[1];
+ if (mins[2] > v[2]) mins[2] = v[2];if (maxs[2] < v[2]) maxs[2] = v[2];
+ }
+
+ nextmesh = mesh->next;
+ newmesh = Mod_SVBSP_ReAllocMesh(mesh);
+ newmesh->next = firstmesh;
+ firstmesh = newmesh;
+ Mem_Free(mesh);
+ }
+ return firstmesh;
+}
+
+void Mod_SVBSP_FreeTriangleMeshs(svbspmesh_t *mesh)
+{
+ svbspmesh_t *nextmesh;
+ for (;mesh;mesh = nextmesh)
+ {
+ nextmesh = mesh->next;
+ Mem_Free(mesh);
+ }
+}
+*/
+
+typedef struct svpolygon_s
+{
+ struct svpolygon_s *next;
+ int maxverts;
+ int numverts;
+ float *verts;
+ float normal[3], dist;
+}
+svpolygon_t;
+
+typedef struct svbrush_s
+{
+ struct svbrush_s *next;
+ svpolygon_t *polygons;
+ vec3_t mins, maxs;
+}
+svbrush_t;
+
+typedef struct svworld_s
+{
+ svbrush_t *brushs;
+}
+svworld_t;
+
+svworld_t *Mod_ShadowBrush_NewWorld(mempool_t *mempool)
+{
+ return Mem_Alloc(mempool, sizeof(svworld_t));
+}
+
+void Mod_ShadowBrush_FreeWorld(svworld_t *world)
+{
+ svbrush_t *brush, *brushnext;
+ svpolygon_t *poly, *polynext;
+ for (brush = world->brushs;brush;brush = brushnext)
+ {
+ brushnext = brush->next;
+ for (poly = brush->polygons;poly;poly = polynext)
+ {
+ polynext = poly->next;
+ Mem_Free(poly);
+ }
+ Mem_Free(brush);
+ }
+ Mem_Free(world);
+}
+
+svbrush_t *Mod_ShadowBrush_BeginBrush(mempool_t *mempool)
+{
+ return Mem_Alloc(mempool, sizeof(svbrush_t));
+}
+
+void Mod_ShadowBrush_AddPolygon(mempool_t *mempool, svbrush_t *brush, int numverts, float *verts)
+{
+ int i;
+ float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2;
+ svpolygon_t *poly;
+ for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3)
+ {
+ VectorSubtract(v0, v1, dir0);
+ VectorSubtract(v2, v1, dir1);
+ CrossProduct(dir0, dir1, normal);
+ if (DotProduct(normal, normal) >= 0.1)
+ break;
+ }
+ if (i == numverts)
+ return;
+ VectorNormalize(normal);
+ dist = DotProduct(verts, normal);
+
+ poly = Mem_Alloc(mempool, sizeof(svpolygon_t) + numverts * sizeof(float[3]));
+ poly->numverts = numverts;
+ poly->verts = (float *)(poly + 1);
+ VectorCopy(normal, poly->normal);
+ poly->dist = dist;
+ poly->next = brush->polygons;
+ brush->polygons = poly;
+ memcpy(poly->verts, verts, numverts * sizeof(float[3]));
+}
+
+void Mod_ShadowBrush_EndBrush(svworld_t *world, svbrush_t *brush)
+{
+ int i;
+ float *v;
+ svpolygon_t *poly;
+ if (!brush->polygons)
+ {
+ Mem_Free(brush);
+ return;
+ }
+ brush->next = world->brushs;
+ world->brushs = brush;
+ VectorCopy(brush->polygons->verts, brush->mins);
+ VectorCopy(brush->polygons->verts, brush->maxs);
+ for (poly = brush->polygons;poly;poly = poly->next)
+ {
+ for (i = 0, v = poly->verts;i < poly->numverts;i++, v += 3)
+ {
+ if (brush->mins[0] > v[0]) brush->mins[0] = v[0];if (brush->maxs[0] < v[0]) brush->maxs[0] = v[0];
+ if (brush->mins[1] > v[1]) brush->mins[1] = v[1];if (brush->maxs[1] < v[1]) brush->maxs[1] = v[1];
+ if (brush->mins[2] > v[2]) brush->mins[2] = v[2];if (brush->maxs[2] < v[2]) brush->maxs[2] = v[2];
+ }
+ }
+}
+
+void Mod_ShadowBrush_ProcessWorld(mempool_t *mempool, svworld_t *world)
+{
+ /*
+ for (clipbrush = world->brushs;clipbrush;clipbrush = clipbrush->next)
+ {
+ for (brush = world->brushs;brush;brush = brush->next)
+ {
+ if (brush != clipbrush
+ && brush->mins[0] <= clipbrush->maxs[0]
+ && brush->maxs[0] >= clipbrush->mins[0]
+ && brush->mins[1] <= clipbrush->maxs[1]
+ && brush->maxs[1] >= clipbrush->mins[1]
+ && brush->mins[2] <= clipbrush->maxs[2]
+ && brush->maxs[2] >= clipbrush->mins[2])
+ continue;
+ for (poly = brush->polygons;poly;poly = poly->next)
+ {
+
+ }
+ }
+ }
+ */
+}
+
+shadowmesh_t *Mod_ShadowBrush_BuildMeshs(mempool_t *mempool, svworld_t *world)
+{
+ shadowmesh_t *mesh;
+ svbrush_t *brush;
+ svpolygon_t *poly;
+ mesh = Mod_ShadowMesh_Begin(mempool);
+ for (brush = world->brushs;brush;brush = brush->next)
+ for (poly = brush->polygons;poly;poly = poly->next)
+ Mod_ShadowMesh_AddPolygon(mempool, mesh, poly->numverts, poly->verts);
+ mesh = Mod_ShadowMesh_Finish(mempool, mesh);
+ return mesh;
+}
+