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 */
StripLength(int starttri,int startv)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 */
FanLength(int starttri,int startv)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 */
BuildTris(void)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 */
GL_MakeAliasModelDisplayLists(model_t * m,aliashdr_t * hdr)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