You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
350 lines
6.3 KiB
350 lines
6.3 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
|
|
// tristrip - convert triangle list into tristrips and fans |
|
|
|
#pragma warning( disable : 4244 ) |
|
#pragma warning( disable : 4237 ) |
|
#pragma warning( disable : 4305 ) |
|
|
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <sys/stat.h> |
|
|
|
#include "cmdlib.h" |
|
#include "lbmlib.h" |
|
#include "scriplib.h" |
|
#include "mathlib/mathlib.h" |
|
#include "..\..\engine\studio.h" |
|
#include "studiomdl.h" |
|
|
|
int used[MAXSTUDIOTRIANGLES]; |
|
|
|
// the command list holds counts and s/t values that are valid for |
|
// every frame |
|
short commands[MAXSTUDIOTRIANGLES * 13]; |
|
int numcommands; |
|
|
|
// all frames will have their vertexes rearranged and expanded |
|
// so they are in the order expected by the command list |
|
|
|
int allverts, alltris; |
|
|
|
int stripverts[MAXSTUDIOTRIANGLES+2]; |
|
int striptris[MAXSTUDIOTRIANGLES+2]; |
|
int stripcount; |
|
|
|
int neighbortri[MAXSTUDIOTRIANGLES][3]; |
|
int neighboredge[MAXSTUDIOTRIANGLES][3]; |
|
|
|
|
|
s_trianglevert_t (*triangles)[3]; |
|
s_mesh_t *pmesh; |
|
|
|
|
|
void FindNeighbor (int starttri, int startv) |
|
{ |
|
s_trianglevert_t m1, m2; |
|
int j; |
|
s_trianglevert_t *last, *check; |
|
int k; |
|
|
|
// used[starttri] |= (1 << startv); |
|
|
|
last = &triangles[starttri][0]; |
|
|
|
m1 = last[(startv+1)%3]; |
|
m2 = last[(startv+0)%3]; |
|
|
|
for (j=starttri+1, check=&triangles[starttri+1][0] ; j<pmesh->numtris ; j++, check += 3) |
|
{ |
|
if (used[j] == 7) |
|
continue; |
|
for (k=0 ; k<3 ; k++) |
|
{ |
|
if (memcmp(&check[k],&m1,sizeof(m1))) |
|
continue; |
|
if (memcmp(&check[ (k+1)%3 ],&m2,sizeof(m2))) |
|
continue; |
|
|
|
neighbortri[starttri][startv] = j; |
|
neighboredge[starttri][startv] = k; |
|
|
|
neighbortri[j][k] = starttri; |
|
neighboredge[j][k] = startv; |
|
|
|
used[starttri] |= (1 << startv); |
|
used[j] |= (1 << k); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
|
|
/* |
|
================ |
|
StripLength |
|
================ |
|
*/ |
|
int StripLength (int starttri, int startv) |
|
{ |
|
int j; |
|
int k; |
|
|
|
used[starttri] = 2; |
|
|
|
stripverts[0] = (startv)%3; |
|
stripverts[1] = (startv+1)%3; |
|
stripverts[2] = (startv+2)%3; |
|
|
|
striptris[0] = starttri; |
|
striptris[1] = starttri; |
|
striptris[2] = starttri; |
|
stripcount = 3; |
|
|
|
while( 1 ) |
|
{ |
|
if (stripcount & 1) |
|
{ |
|
j = neighbortri[starttri][(startv+1)%3]; |
|
k = neighboredge[starttri][(startv+1)%3]; |
|
} |
|
else |
|
{ |
|
j = neighbortri[starttri][(startv+2)%3]; |
|
k = neighboredge[starttri][(startv+2)%3]; |
|
} |
|
if (j == -1 || used[j]) |
|
goto done; |
|
|
|
stripverts[stripcount] = (k+2)%3; |
|
striptris[stripcount] = j; |
|
stripcount++; |
|
|
|
used[j] = 2; |
|
|
|
starttri = j; |
|
startv = k; |
|
} |
|
|
|
done: |
|
|
|
// clear the temp used flags |
|
for (j=0 ; j<pmesh->numtris ; j++) |
|
if (used[j] == 2) |
|
used[j] = 0; |
|
|
|
return stripcount; |
|
} |
|
|
|
/* |
|
=========== |
|
FanLength |
|
=========== |
|
*/ |
|
int FanLength (int starttri, int startv) |
|
{ |
|
int j; |
|
int k; |
|
|
|
used[starttri] = 2; |
|
|
|
stripverts[0] = (startv)%3; |
|
stripverts[1] = (startv+1)%3; |
|
stripverts[2] = (startv+2)%3; |
|
|
|
striptris[0] = starttri; |
|
striptris[1] = starttri; |
|
striptris[2] = starttri; |
|
stripcount = 3; |
|
|
|
while( 1 ) |
|
{ |
|
j = neighbortri[starttri][(startv+2)%3]; |
|
k = neighboredge[starttri][(startv+2)%3]; |
|
|
|
if (j == -1 || used[j]) |
|
goto done; |
|
|
|
stripverts[stripcount] = (k+2)%3; |
|
striptris[stripcount] = j; |
|
stripcount++; |
|
|
|
used[j] = 2; |
|
|
|
starttri = j; |
|
startv = k; |
|
} |
|
|
|
done: |
|
|
|
// clear the temp used flags |
|
for (j=0 ; j<pmesh->numtris ; j++) |
|
if (used[j] == 2) |
|
used[j] = 0; |
|
|
|
return stripcount; |
|
} |
|
|
|
|
|
/* |
|
================ |
|
BuildTris |
|
|
|
Generate a list of trifans or strips |
|
for the model, which holds for all frames |
|
================ |
|
*/ |
|
int numcommandnodes; |
|
|
|
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 ); |
|
} |
|
|
|
|