1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // gl_mesh.c: triangle model functions 21 22 #include "quakedef.h" 23 24 /* 25 ================================================================= 26 27 ALIAS MODEL DISPLAY LIST GENERATION 28 29 ================================================================= 30 */ 31 32 model_t *aliasmodel; 33 aliashdr_t *paliashdr; 34 35 qboolean used[8192]; 36 37 // the command list holds counts and s/t values that are valid for 38 // every frame 39 int commands[8192]; 40 int numcommands; 41 42 // all frames will have their vertexes rearranged and expanded 43 // so they are in the order expected by the command list 44 int vertexorder[8192]; 45 int numorder; 46 47 int allverts, alltris; 48 49 int stripverts[128]; 50 int striptris[128]; 51 int stripcount; 52 53 /* 54 ================ 55 StripLength 56 ================ 57 */ 58 int StripLength (int starttri, int startv) 59 { 60 int m1, m2; 61 int j; 62 mtriangle_t *last, *check; 63 int k; 64 65 used[starttri] = 2; 66 67 last = &triangles[starttri]; 68 69 stripverts[0] = last->vertindex[(startv)%3]; 70 stripverts[1] = last->vertindex[(startv+1)%3]; 71 stripverts[2] = last->vertindex[(startv+2)%3]; 72 73 striptris[0] = starttri; 74 stripcount = 1; 75 76 m1 = last->vertindex[(startv+2)%3]; 77 m2 = last->vertindex[(startv+1)%3]; 78 79 // look for a matching triangle 80 nexttri: 81 for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++) 82 { 83 if (check->facesfront != last->facesfront) 84 continue; 85 for (k=0 ; k<3 ; k++) 86 { 87 if (check->vertindex[k] != m1) 88 continue; 89 if (check->vertindex[ (k+1)%3 ] != m2) 90 continue; 91 92 // this is the next part of the fan 93 94 // if we can't use this triangle, this tristrip is done 95 if (used[j]) 96 goto done; 97 98 // the new edge 99 if (stripcount & 1) 100 m2 = check->vertindex[ (k+2)%3 ]; 101 else 102 m1 = check->vertindex[ (k+2)%3 ]; 103 104 stripverts[stripcount+2] = check->vertindex[ (k+2)%3 ]; 105 striptris[stripcount] = j; 106 stripcount++; 107 108 used[j] = 2; 109 goto nexttri; 110 } 111 } 112 done: 113 114 // clear the temp used flags 115 for (j=starttri+1 ; j<pheader->numtris ; j++) 116 if (used[j] == 2) 117 used[j] = 0; 118 119 return stripcount; 120 } 121 122 /* 123 =========== 124 FanLength 125 =========== 126 */ 127 int FanLength (int starttri, int startv) 128 { 129 int m1, m2; 130 int j; 131 mtriangle_t *last, *check; 132 int k; 133 134 used[starttri] = 2; 135 136 last = &triangles[starttri]; 137 138 stripverts[0] = last->vertindex[(startv)%3]; 139 stripverts[1] = last->vertindex[(startv+1)%3]; 140 stripverts[2] = last->vertindex[(startv+2)%3]; 141 142 striptris[0] = starttri; 143 stripcount = 1; 144 145 m1 = last->vertindex[(startv+0)%3]; 146 m2 = last->vertindex[(startv+2)%3]; 147 148 149 // look for a matching triangle 150 nexttri: 151 for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++) 152 { 153 if (check->facesfront != last->facesfront) 154 continue; 155 for (k=0 ; k<3 ; k++) 156 { 157 if (check->vertindex[k] != m1) 158 continue; 159 if (check->vertindex[ (k+1)%3 ] != m2) 160 continue; 161 162 // this is the next part of the fan 163 164 // if we can't use this triangle, this tristrip is done 165 if (used[j]) 166 goto done; 167 168 // the new edge 169 m2 = check->vertindex[ (k+2)%3 ]; 170 171 stripverts[stripcount+2] = m2; 172 striptris[stripcount] = j; 173 stripcount++; 174 175 used[j] = 2; 176 goto nexttri; 177 } 178 } 179 done: 180 181 // clear the temp used flags 182 for (j=starttri+1 ; j<pheader->numtris ; j++) 183 if (used[j] == 2) 184 used[j] = 0; 185 186 return stripcount; 187 } 188 189 190 /* 191 ================ 192 BuildTris 193 194 Generate a list of trifans or strips 195 for the model, which holds for all frames 196 ================ 197 */ 198 void BuildTris (void) 199 { 200 int i, j, k; 201 int startv; 202 float s, t; 203 int len, bestlen, besttype; 204 int bestverts[1024]; 205 int besttris[1024]; 206 int type; 207 208 // 209 // build tristrips 210 // 211 numorder = 0; 212 numcommands = 0; 213 besttype = 0; 214 memset (used, 0, sizeof(used)); 215 for (i=0 ; i<pheader->numtris ; i++) 216 { 217 // pick an unused triangle and start the trifan 218 if (used[i]) 219 continue; 220 221 bestlen = 0; 222 for (type = 0 ; type < 2 ; type++) 223 // type = 1; 224 { 225 for (startv =0 ; startv < 3 ; startv++) 226 { 227 if (type == 1) 228 len = StripLength (i, startv); 229 else 230 len = FanLength (i, startv); 231 if (len > bestlen) 232 { 233 besttype = type; 234 bestlen = len; 235 for (j=0 ; j<bestlen+2 ; j++) 236 bestverts[j] = stripverts[j]; 237 for (j=0 ; j<bestlen ; j++) 238 besttris[j] = striptris[j]; 239 } 240 } 241 } 242 243 // mark the tris on the best strip as used 244 for (j=0 ; j<bestlen ; j++) 245 used[besttris[j]] = 1; 246 247 if (besttype == 1) 248 commands[numcommands++] = (bestlen+2); 249 else 250 commands[numcommands++] = -(bestlen+2); 251 252 for (j=0 ; j<bestlen+2 ; j++) 253 { 254 // emit a vertex into the reorder buffer 255 k = bestverts[j]; 256 vertexorder[numorder++] = k; 257 258 // emit s/t coords into the commands stream 259 s = stverts[k].s; 260 t = stverts[k].t; 261 if (!triangles[besttris[0]].facesfront && stverts[k].onseam) 262 s += pheader->skinwidth / 2; // on back side 263 s = (s + 0.5) / pheader->skinwidth; 264 t = (t + 0.5) / pheader->skinheight; 265 266 *(float *)&commands[numcommands++] = s; 267 *(float *)&commands[numcommands++] = t; 268 } 269 } 270 271 commands[numcommands++] = 0; // end of list marker 272 273 Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); 274 275 allverts += numorder; 276 alltris += pheader->numtris; 277 } 278 279 280 /* 281 ================ 282 GL_MakeAliasModelDisplayLists 283 ================ 284 */ 285 void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr) 286 { 287 int i, j; 288 int *cmds; 289 trivertx_t *verts; 290 char cache[MAX_QPATH], fullpath[MAX_OSPATH]; 291 FILE *f; 292 293 aliasmodel = m; 294 paliashdr = hdr; // (aliashdr_t *)Mod_Extradata (m); 295 296 // 297 // look for a cached version 298 // 299 strcpy (cache, "glquake/"); 300 COM_StripExtension (m->name+strlen("progs/"), cache+strlen("glquake/")); 301 strcat (cache, ".ms2"); 302 303 COM_FOpenFile (cache, &f); 304 if (f) 305 { 306 fread (&numcommands, 4, 1, f); 307 fread (&numorder, 4, 1, f); 308 fread (&commands, numcommands * sizeof(commands[0]), 1, f); 309 fread (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f); 310 fclose (f); 311 } 312 else 313 { 314 // 315 // build it from scratch 316 // 317 Con_Printf ("meshing %s...\n",m->name); 318 319 BuildTris (); // trifans or lists 320 321 // 322 // save out the cached version 323 // 324 sprintf (fullpath, "%s/%s", com_gamedir, cache); 325 f = fopen (fullpath, "wb"); 326 if (!f) { 327 char gldir[MAX_OSPATH]; 328 329 sprintf (gldir, "%s/glquake", com_gamedir); 330 Sys_mkdir (gldir); 331 f = fopen (fullpath, "wb"); 332 } 333 334 if (f) 335 { 336 fwrite (&numcommands, 4, 1, f); 337 fwrite (&numorder, 4, 1, f); 338 fwrite (&commands, numcommands * sizeof(commands[0]), 1, f); 339 fwrite (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f); 340 fclose (f); 341 } 342 } 343 344 345 // save the data out 346 347 paliashdr->poseverts = numorder; 348 349 cmds = Hunk_Alloc (numcommands * 4); 350 paliashdr->commands = (byte *)cmds - (byte *)paliashdr; 351 memcpy (cmds, commands, numcommands * 4); 352 353 verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts 354 * sizeof(trivertx_t) ); 355 paliashdr->posedata = (byte *)verts - (byte *)paliashdr; 356 for (i=0 ; i<paliashdr->numposes ; i++) 357 for (j=0 ; j<numorder ; j++) 358 *verts++ = poseverts[i][vertexorder[j]]; 359 } 360 361