/* ================ BuildTris Generate a list of trifans or strips for the model, which holds for all frames ================ */ void BuildTris (void) { int i, j, k; int startv; float s, t; int len, bestlen, besttype; int bestverts[1024]; int besttris[1024]; int type; // // build tristrips // numorder = 0; numcommands = 0; memset (used, 0, sizeof(used)); for (i = 0; i < pheader->numtris; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; besttype = 0; for (type = 0 ; type < 2 ; type++) // type = 1; { for (startv = 0; startv < 3; startv++) { if (type == 1) len = StripLength (i, startv); else len = FanLength (i, startv); if (len > bestlen) { besttype = type; bestlen = len; for (j = 0; j < bestlen+2; j++) bestverts[j] = stripverts[j]; for (j = 0; j < bestlen; j++) besttris[j] = striptris[j]; } } } // mark the tris on the best strip as used for (j = 0; j < bestlen; j++) used[besttris[j]] = 1; if (besttype == 1) commands[numcommands++] = (bestlen+2); else commands[numcommands++] = -(bestlen+2); for (j = 0; j < bestlen+2; j++) { int tmp; // emit a vertex into the reorder buffer k = bestverts[j]; vertexorder[numorder++] = k; // emit s/t coords into the commands stream s = stverts[k].s; t = stverts[k].t; if (!triangles[besttris[0]].facesfront && stverts[k].onseam) s += pheader->skinwidth / 2; // on back side s = (s + 0.5) / pheader->skinwidth; t = (t + 0.5) / pheader->skinheight; // *(float *)&commands[numcommands++] = s; // *(float *)&commands[numcommands++] = t; // NOTE: 4 == sizeof(int) // == sizeof(float) memcpy (&tmp, &s, 4); commands[numcommands++] = tmp; memcpy (&tmp, &t, 4); commands[numcommands++] = tmp; } } commands[numcommands++] = 0; // end of list marker Con_DPrintf2 ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); allverts += numorder; alltris += pheader->numtris; }
int BuildTris (s_trianglevert_t (*x)[3], s_mesh_t *y, byte **ppdata ) { int i, j, k, m; int startv; int len, bestlen, besttype; int bestverts[MAXSTUDIOTRIANGLES]; int besttris[MAXSTUDIOTRIANGLES]; int peak[MAXSTUDIOTRIANGLES]; int type; int total = 0; long t; int maxlen; triangles = x; pmesh = y; t = time( NULL ); for (i=0 ; i<pmesh->numtris ; i++) { neighbortri[i][0] = neighbortri[i][1] = neighbortri[i][2] = -1; used[i] = 0; peak[i] = pmesh->numtris; } // printf("finding neighbors\n"); for (i=0 ; i<pmesh->numtris; i++) { for (k = 0; k < 3; k++) { if (used[i] & (1 << k)) continue; FindNeighbor( i, k ); } // printf("%d", used[i] ); } // printf("\n"); // // build tristrips // numcommandnodes = 0; numcommands = 0; memset (used, 0, sizeof(used)); for (i=0 ; i<pmesh->numtris ;) { // pick an unused triangle and start the trifan if (used[i]) { i++; continue; } maxlen = 9999; bestlen = 0; m = 0; for (k = i; k < pmesh->numtris && bestlen < 127; k++) { int localpeak = 0; if (used[k]) continue; if (peak[k] <= bestlen) continue; m++; for (type = 0 ; type < 2 ; type++) { for (startv =0 ; startv < 3 ; startv++) { if (type == 1) len = FanLength (k, startv); else len = StripLength (k, startv); if (len > 127) { // skip these, they are too long to encode } else if (len > bestlen) { besttype = type; bestlen = len; for (j=0 ; j<bestlen ; j++) { besttris[j] = striptris[j]; bestverts[j] = stripverts[j]; } // printf("%d %d\n", k, bestlen ); } if (len > localpeak) localpeak = len; } } peak[k] = localpeak; if (localpeak == maxlen) break; } total += (bestlen - 2); // printf("%d (%d) %d\n", bestlen, pmesh->numtris - total, i ); maxlen = bestlen; // mark the tris on the best strip as used for (j=0 ; j<bestlen ; j++) used[besttris[j]] = 1; if (besttype == 1) commands[numcommands++] = -bestlen; else commands[numcommands++] = bestlen; for (j=0 ; j<bestlen ; j++) { s_trianglevert_t *tri; tri = &triangles[besttris[j]][bestverts[j]]; commands[numcommands++] = tri->vertindex; commands[numcommands++] = tri->normindex; commands[numcommands++] = tri->s; commands[numcommands++] = tri->t; } // printf("%d ", bestlen - 2 ); numcommandnodes++; if (t != time(NULL)) { printf("%2d%%\r", (total * 100) / pmesh->numtris ); t = time(NULL); } } commands[numcommands++] = 0; // end of list marker *ppdata = (byte *)commands; // printf("%d %d %d\n", numcommandnodes, numcommands, pmesh->numtris ); return numcommands * sizeof( short ); }
/* BuildTris Generate a list of trifans or strips for the model, which holds for all frames */ static void BuildTris (void) { float s, t; int bestlen, len, startv, type, i, j, k; int besttype = 0; int *bestverts = 0, *besttris = 0; // build tristrips numorder = 0; numcommands = 0; stripcount = 0; alloc_used (pheader->mdl.numtris); memset (used, 0, used_size * sizeof (used[0])); for (i = 0; i < pheader->mdl.numtris; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; for (type = 0; type < 2; type++) { // type = 1; for (startv = 0; startv < 3; startv++) { if (type == 1) len = StripLength (i, startv); else len = FanLength (i, startv); if (len > bestlen) { besttype = type; bestlen = len; if (bestverts) free (bestverts); if (besttris) free (besttris); bestverts = stripverts; besttris = striptris; stripverts = striptris = 0; strip_size = 0; } } } // mark the tris on the best strip as used for (j = 0; j < bestlen; j++) used[besttris[j + 2]] = 1; if (besttype == 1) add_command (bestlen + 2); else add_command (-(bestlen + 2)); for (j = 0; j < bestlen + 2; j++) { int tmp; // emit a vertex into the reorder buffer k = bestverts[j]; add_vertex (k); // emit s/t coords into the commands stream s = stverts[k].s; t = stverts[k].t; if (!triangles[besttris[0]].facesfront && stverts[k].onseam) s += pheader->mdl.skinwidth / 2; // on back side s = (s + 0.5) / pheader->mdl.skinwidth; t = (t + 0.5) / pheader->mdl.skinheight; memcpy (&tmp, &s, 4); add_command (tmp); memcpy (&tmp, &t, 4); add_command (tmp); } } add_command (0); // end of list marker Sys_MaskPrintf (SYS_DEV, "%3i tri %3i vert %3i cmd\n", pheader->mdl.numtris, numorder, numcommands); allverts += numorder; alltris += pheader->mdl.numtris; if (bestverts) free (bestverts); if (besttris) free (besttris); }
/* ================ BuildTris Generate a list of trifans or strips for the model, which holds for all frames ================ */ void BuildTris (void) { int i, j, k; int startv; mtriangle_t *last, *check; int m1, m2; int striplength; trivertx_t *v; mtriangle_t *tv; float s, t; int index; int len, bestlen, besttype; int* bestverts = Sys_BigStackAlloc(1024 * sizeof(int), "BuildTris"); int* besttris = Sys_BigStackAlloc(1024 * sizeof(int), "BuildTris"); int type; // // build tristrips // numorder = 0; numcommands = 0; memset (used, 0, sizeof(used)); for (i=0 ; i<pheader->numtris ; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; for (type = 0 ; type < 2 ; type++) // type = 1; { for (startv =0 ; startv < 3 ; startv++) { if (type == 1) len = StripLength (i, startv); else len = FanLength (i, startv); if (len > bestlen) { besttype = type; bestlen = len; for (j=0 ; j<bestlen+2 ; j++) bestverts[j] = stripverts[j]; for (j=0 ; j<bestlen ; j++) besttris[j] = striptris[j]; } } } // mark the tris on the best strip as used for (j=0 ; j<bestlen ; j++) used[besttris[j]] = 1; if (besttype == 1) commands[numcommands++] = (bestlen+2); else commands[numcommands++] = -(bestlen+2); for (j=0 ; j<bestlen+2 ; j++) { // emit a vertex into the reorder buffer k = bestverts[j]; vertexorder[numorder++] = k; // emit s/t coords into the commands stream s = stverts[k].s; t = stverts[k].t; if (!triangles[besttris[0]].facesfront && stverts[k].onseam) s += pheader->skinwidth / 2; // on back side s = (s + 0.5) / pheader->skinwidth; t = (t + 0.5) / pheader->skinheight; *(float *)&commands[numcommands++] = s; *(float *)&commands[numcommands++] = t; } } commands[numcommands++] = 0; // end of list marker Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); allverts += numorder; alltris += pheader->numtris; Sys_BigStackFree(1024 * sizeof(int) + 1024 * sizeof(int), "BuildTris"); }
static int BuildOptimizedList( int mesh[][3], int strip[][3], int numInputTris ){ int t; int stripLen = 0; int startTri = -1; int bestTri = -1, bestLength = 0, bestOrientation = -1; int matchedSides = 0; int orientation = 0; int seedTriangles[MAX_MATCHED_SIDES][MAX_SEED_TRIANGLES]; int seedLengths[MAX_ORIENTATIONS][MAX_MATCHED_SIDES][MAX_SEED_TRIANGLES]; int numSeeds[MAX_MATCHED_SIDES] = { 0, 0, 0 }; int i; // build a ranked list of candidate seed triangles based on // number of offshoot strips. Precedence goes to orphans, // then corners, then edges, and interiors. memset( seedTriangles, 0xff, sizeof( seedTriangles ) ); memset( seedLengths, 0xff, sizeof( seedLengths ) ); for ( i = 0; i < MAX_MATCHED_SIDES; i++ ) { // find the triangle with lowest number of child strips for ( t = 0; t < numInputTris; t++ ) { int orientation; int n; if ( s_used[t] ) { continue; } // try the candidate triangle in three different orientations matchedSides = 0; for ( orientation = 0; orientation < 3; orientation++ ) { if ( ( n = FindNextTriangleInStripOrFan( mesh, t, orientation, numInputTris, 1 ) ) != -1 ) { matchedSides++; } } if ( matchedSides == i ) { seedTriangles[i][numSeeds[i]] = t; numSeeds[i]++; if ( numSeeds[i] == MAX_SEED_TRIANGLES ) { break; } } } } // we have a list of potential seed triangles, so we now go through each // potential candidate and look to see which produces the longest strip // and select our startTri based on this for ( i = 0; i < MAX_MATCHED_SIDES; i++ ) { int j; for ( j = 0; j < numSeeds[i]; j++ ) { for ( orientation = 0; orientation < 3; orientation++ ) { int k; seedLengths[orientation][i][j] = StripLength( mesh, strip, seedTriangles[i][j], orientation, numInputTris, 2 ); if ( seedLengths[orientation][i][j] > bestLength ) { bestTri = seedTriangles[i][j]; bestLength = seedLengths[orientation][i][j]; bestOrientation = orientation; } for ( k = 0; k < numInputTris; k++ ) { if ( s_used[k] == 2 ) { s_used[k] = 0; } } } } if ( bestTri != -1 ) { break; } } // build the strip for real if ( bestTri != -1 ) { stripLen = StripLength( mesh, strip, bestTri, bestOrientation, numInputTris, 1 ); } return stripLen; }
/* ================ BuildGlCmds Generate a list of trifans or strips for the model, which holds for all frames ================ */ static void BuildGlCmds (void) { int i, j, k; int startv; float s, t; int len, bestlen, besttype; int best_xyz[1024]; int best_st[1024]; int best_tris[1024]; int type; // // build tristrips // numcommands = 0; numglverts = 0; memset (used, 0, sizeof(used)); for (i=0 ; i<model.num_tris ; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; for (type = 0 ; type < 2 ; type++) // type = 1; { for (startv =0 ; startv < 3 ; startv++) { if (type == 1) len = StripLength (i, startv); else len = FanLength (i, startv); if (len > bestlen) { besttype = type; bestlen = len; for (j=0 ; j<bestlen+2 ; j++) { best_st[j] = strip_st[j]; best_xyz[j] = strip_xyz[j]; } for (j=0 ; j<bestlen ; j++) best_tris[j] = strip_tris[j]; } } } // mark the tris on the best strip/fan as used for (j=0 ; j<bestlen ; j++) used[best_tris[j]] = 1; if (besttype == 1) commands[numcommands++] = (bestlen+2); else commands[numcommands++] = -(bestlen+2); numglverts += bestlen+2; for (j=0 ; j<bestlen+2 ; j++) { // emit a vertex into the reorder buffer k = best_st[j]; // emit s/t coords into the commands stream s = base_st[k].s; t = base_st[k].t; s = (s + 0.5) / model.skinwidth; t = (t + 0.5) / model.skinheight; *(float *)&commands[numcommands++] = s; *(float *)&commands[numcommands++] = t; *(int *)&commands[numcommands++] = best_xyz[j]; } } commands[numcommands++] = 0; // end of list marker }
/* ================ BuildTris Generate a list of trifans or strips for the model, which holds for all frames ================ */ void BuildTris (void) { int i, j, k; int startv; mtriangle_t *last, *check; int m1, m2; int striplength; trivertx_t *v; mtriangle_t *tv; float s, t; int index; int len, bestlen, besttype; int bestverts[1024]; int besttris[1024]; int type; int stripmax = 0; // // build tristrips // numorder = 0; numcommands = 0; memset (used, 0, sizeof(used)); for (i=0 ; i<pheader->numtris ; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; for (type = 0 ; type < 2 ; type++) // type = 1; { for (startv =0 ; startv < 3 ; startv++) { if (type == 1) len = StripLength (i, startv); else len = FanLength (i, startv); // Save peak if (len > stripmax) stripmax = len; if (len > bestlen) { besttype = type; bestlen = len; for (j=0 ; j<bestlen+2 ; j++) bestverts[j] = stripverts[j]; for (j=0 ; j<bestlen ; j++) besttris[j] = striptris[j]; } } } // mark the tris on the best strip as used for (j=0 ; j<bestlen ; j++) used[besttris[j]] = 1; ChkCmds ("BuildTris"); if (besttype == 1) commands[numcommands++] = (bestlen+2); else commands[numcommands++] = -(bestlen+2); for (j=0 ; j<bestlen+2 ; j++) { // emit a vertex into the reorder buffer k = bestverts[j]; vertexorder[numorder++] = k; // emit s/t coords into the commands stream s = stverts[k].s; t = stverts[k].t; if (!triangles[besttris[0]].facesfront && stverts[k].onseam) s += pheader->skinwidth / 2; // on back side s = (s + 0.5) / pheader->skinwidth; t = (t + 0.5) / pheader->skinheight; ChkCmds ("BuildTris"); *(float *)&commands[numcommands++] = s; *(float *)&commands[numcommands++] = t; } } ChkCmds ("BuildTris"); commands[numcommands++] = 0; // end of list marker // Check old limit if (stripmax + 2 >= 128) { Con_Printf ("\002BuildTris: "); Con_Printf ("excessive stripcount (%d, normal max = %d) in %s\n", stripmax, 128 - 2, aliasmodel->name); } // Check old limit if (numcommands >= 8192) { Con_Printf ("\002BuildTris: "); Con_Printf ("excessive commands (%d, normal max = %d) in %s\n", numcommands, 8192, aliasmodel->name); } #ifndef NO_CACHE_MESH Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); #endif }