1 /*
2  * Tux Racer
3  * Copyright (C) 1999-2001 Jasmin F. Patry
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * 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 #include "track_marks.h"
21 #include "gl_util.h"
22 #include "tux.h"
23 #include "hier.h"
24 #include "phys_sim.h"
25 #include "textures.h"
26 #include "alglib.h"
27 #include "course_render.h"
28 #include "render_util.h"
29 
30 #undef TRACK_TRIANGLES
31 
32 #define TRACK_WIDTH  0.7
33 #define MAX_TRACK_MARKS 1000
34 #define MAX_CONTINUE_TRACK_DIST TRACK_WIDTH*4
35 #define MAX_CONTINUE_TRACK_TIME .1
36 #define SPEED_TO_START_TRENCH 0.0
37 #define SPEED_OF_DEEPEST_TRENCH 10
38 
39 #ifdef TRACK_TRIANGLES
40   #define TRACK_HEIGHT 0.1
41   #define MAX_TRACK_DEPTH 10
42   #define MAX_TRIS MAX_TRACK_MARKS
43 #else
44   #define TRACK_HEIGHT 0.08
45   #define MAX_TRACK_DEPTH 0.7
46 #endif
47 
48 typedef enum track_types_t {
49     TRACK_HEAD,
50     TRACK_MARK,
51     TRACK_TAIL,
52     NUM_TRACK_TYPES
53 } track_types_t;
54 
55 typedef struct track_quad_t {
56     point_t v1, v2, v3, v4;
57     point2d_t t1, t2, t3, t4;
58     vector_t n1, n2, n3, n4;
59     track_types_t track_type;
60     scalar_t alpha;
61 } track_quad_t;
62 
63 typedef struct track_marks_t {
64     track_quad_t quads[MAX_TRACK_MARKS];
65     int current_mark;
66     int next_mark;
67     scalar_t last_mark_time;
68     point_t last_mark_pos;
69 } track_marks_t;
70 
71 static track_marks_t track_marks;
72 static bool_t continuing_track;
73 
74 
75 
76 #ifdef TRACK_TRIANGLES
77 typedef struct track_tris_t {
78     triangle_t tri[MAX_TRIS];
79     track_types_t *track_type[MAX_TRIS];
80     scalar_t *alpha[MAX_TRIS];
81     int first_mark;
82     int next_mark;
83     int current_start;
84     int current_end;
85     int num_tris;
86 } track_tris_t;
87 
88 typedef struct track_tri_t {
89     point_t v1, v2, v3;
90 } track_tri_t;
91 
92 static track_tris_t track_tris;
93 
draw_tri(triangle_t * tri,scalar_t alpha)94 static void draw_tri( triangle_t *tri, scalar_t alpha )
95 {
96     vector_t nml;
97     GLfloat c[4] = {1.0, 0.0, 0.0, 1.0};
98 
99 /*    set_material_alpha( white, black, 1.0, alpha ); */
100     set_material_alpha( white, black, 1.0, 1.0 );
101 
102     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c);
103 
104     glBegin(GL_TRIANGLES);
105 
106     nml = find_course_normal( tri->p[0].x, tri->p[0].z );
107     glNormal3f( nml.x, nml.y, nml.z );
108     glTexCoord2f( tri->t[0].x, tri->t[0].y );
109     glVertex3f( tri->p[0].x, tri->p[0].y, tri->p[0].z );
110 
111     nml = find_course_normal( tri->p[1].x, tri->p[1].z );
112     glNormal3f( nml.x, nml.y, nml.z );
113     glTexCoord2f( tri->t[1].x, tri->t[1].y );
114     glVertex3f( tri->p[1].x, tri->p[1].y, tri->p[1].z );
115 
116     nml = find_course_normal( tri->p[2].x, tri->p[2].z );
117     glNormal3f( nml.x, nml.y, nml.z );
118     glTexCoord2f( tri->t[2].x, tri->t[2].y );
119     glVertex3f( tri->p[2].x, tri->p[2].y, tri->p[2].z );
120 
121     glEnd();
122 }
123 
draw_tri_tracks(void)124 static void draw_tri_tracks( void )
125 {
126     GLuint texid[NUM_TRACK_TYPES];
127     int i;
128 
129     set_gl_options( TRACK_MARKS );
130 
131     glColor4f( 0, 0, 0, 1);
132 
133     get_texture_binding( "track_head", &texid[TRACK_HEAD] );
134     get_texture_binding( "track_mark", &texid[TRACK_MARK] );
135     get_texture_binding( "track_tail", &texid[TRACK_TAIL] );
136 
137     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
138     set_material( white, black, 1.0 );
139     setup_course_lighting();
140 
141     for( i = 0; i < track_tris.num_tris; i++ ) {
142 	glBindTexture( GL_TEXTURE_2D,
143 		       texid[*track_tris.track_type[(track_tris.first_mark+i)%MAX_TRIS]] );
144 	draw_tri( &track_tris.tri[(track_tris.first_mark+i)%MAX_TRIS],
145 		  *track_tris.alpha[(track_tris.first_mark+i)%MAX_TRIS] );
146     }
147 }
148 
add_tri_tracks_from_tri(point_t p1,point_t p2,point_t p3,point2d_t t1,point2d_t t2,point2d_t t3,track_types_t * track_type,scalar_t * alpha)149 static void add_tri_tracks_from_tri( point_t p1, point_t p2, point_t p3,
150 				     point2d_t t1, point2d_t t2, point2d_t t3,
151 				     track_types_t *track_type, scalar_t *alpha )
152 {
153     scalar_t minx, maxx;
154     scalar_t minz, maxz;
155     int nx, nz;
156     scalar_t width, length;
157     int i, j, k;
158     scalar_t xstep, zstep;
159     line_t cut;
160     int num_tris;
161     int this_set_end;
162     int num_new;
163 
164     /* Make 'em planar. Calculate y later anyway */
165     p1.y = p2.y = p3.y = 0;
166 
167     get_course_divisions( &nx, &nz );
168     get_course_dimensions( &width, &length );
169     xstep = width/(nx-1);
170     zstep = length/(nz-1);
171 
172     minx = min(min(p1.x, p2.x), p3.x);
173     minz = min(min(p1.z, p2.z), p3.z);
174     maxx = max(max(p1.x, p2.x), p3.x);
175     maxz = max(max(p1.z, p2.z), p3.z);
176 
177     track_tris.current_start = track_tris.next_mark;
178     track_tris.current_end = track_tris.next_mark;
179 
180     track_tris.tri[track_tris.next_mark].p[0] = p1;
181     track_tris.tri[track_tris.next_mark].p[1] = p2;
182     track_tris.tri[track_tris.next_mark].p[2] = p3;
183     track_tris.tri[track_tris.next_mark].t[0] = t1;
184     track_tris.tri[track_tris.next_mark].t[1] = t2;
185     track_tris.tri[track_tris.next_mark].t[2] = t3;
186 
187     /*
188      * Make lengthwise cuts
189      */
190     for( i = (int)((minx/xstep)+0.9999); i < (int)(maxx/xstep); i++ ) {
191 	cut.pt = make_point( i*xstep, 0, 0 );
192 	cut.nml = make_vector( 1, 0, 0 );
193 	this_set_end = track_tris.current_end;
194 	for ( j = track_tris.current_start; j <= this_set_end; j++ ) {
195 	    num_tris = cut_triangle( &track_tris.tri[j%MAX_TRIS],
196 				     &track_tris.tri[(track_tris.current_end+1)%MAX_TRIS],
197 				     &track_tris.tri[(track_tris.current_end+2)%MAX_TRIS],
198 				     cut );
199 	    track_tris.current_end = (track_tris.current_end + num_tris - 1)%MAX_TRIS;
200 	}
201     }
202 
203     /*
204      * Make cross cuts
205      */
206     for( i = (int)((minz/zstep)+0.9999); i < (int)(maxz/zstep); i++ ) {
207 	cut.pt = make_point( 0, 0, i*zstep );
208 	cut.nml = make_vector( 0, 0, 1 );
209 	this_set_end = track_tris.current_end;
210 	for ( j = track_tris.current_start; j <= this_set_end; j++ ) {
211 	    num_tris = cut_triangle( &track_tris.tri[j%MAX_TRIS],
212 				     &track_tris.tri[(track_tris.current_end+1)%MAX_TRIS],
213 				     &track_tris.tri[(track_tris.current_end+2)%MAX_TRIS],
214 				     cut );
215 	    track_tris.current_end = (track_tris.current_end + num_tris - 1)%MAX_TRIS;
216 	}
217     }
218 
219     /*
220      * Make diagonal cuts
221      */
222     for( i = (int)((minx/xstep)+0.9999), j = (int)((minz/zstep)+0.9999);
223 	 (i < (int)(maxx/xstep)) && (j < (int)(maxz/zstep));
224 	 i++, j++) {
225 	if ( (i+j)%2 != 0 ) {
226 	    i--;
227 	}
228 	cut.pt = make_point( i*xstep, 0, j*zstep );
229 	cut.nml = make_vector( 1, 0, 1 );
230 	normalize_vector(&cut.nml);
231 	for ( k = track_tris.current_start; k <= this_set_end; k++ ) {
232 	    num_tris = cut_triangle( &track_tris.tri[k%MAX_TRIS],
233 				     &track_tris.tri[(track_tris.current_end+1)%MAX_TRIS],
234 				     &track_tris.tri[(track_tris.current_end+2)%MAX_TRIS],
235 				     cut );
236 	    track_tris.current_end = (track_tris.current_end + num_tris - 1)%MAX_TRIS;
237 	}
238     }
239 
240     /*
241      * Make other diagonal cuts
242      */
243     for( i = (int)((minx/xstep)+0.9999), j = (int)(maxz/zstep);
244 	 (i < (int)(maxx/xstep)) && (j > (int)((minz/zstep) + 0.9999));
245 	 i++, j--) {
246 	if ( (i+j)%2 != 0 ) {
247 	    i--;
248 	}
249 	cut.pt = make_point( i*xstep, 0, j*zstep );
250 	cut.nml = make_vector( 1, 0, 1 );
251 	normalize_vector(&cut.nml);
252 	for ( k = track_tris.current_start; k <= this_set_end; k++ ) {
253 	    num_tris = cut_triangle( &track_tris.tri[k%MAX_TRIS],
254 				     &track_tris.tri[(track_tris.current_end+1)%MAX_TRIS],
255 				     &track_tris.tri[(track_tris.current_end+2)%MAX_TRIS],
256 				     cut );
257 	    track_tris.current_end = (track_tris.current_end + num_tris - 1)%MAX_TRIS;
258 	}
259     }
260 
261 
262     /* Reset first, next and num_tris */
263     if (track_tris.current_start <= track_tris.current_end) {
264 	num_new = track_tris.current_end - track_tris.current_start + 1;
265 	track_tris.num_tris = track_tris.num_tris + num_new;
266 	track_tris.next_mark = (track_tris.current_end+1)%MAX_TRIS;
267 	if ( ((track_tris.num_tris - num_new) > 0) &&
268 	     (track_tris.first_mark >= track_tris.current_start) &&
269 	     (track_tris.first_mark <= track_tris.current_end) ) {
270 	    track_tris.num_tris = track_tris.num_tris - (track_tris.current_end - track_tris.first_mark + 1);
271 	    track_tris.first_mark = track_tris.next_mark;
272 	}
273 
274     } else {
275 	num_new = (track_tris.current_end + 1) + (MAX_TRIS - track_tris.current_start);
276 	track_tris.num_tris = track_tris.num_tris + num_new;
277 	track_tris.next_mark = (track_tris.current_end+1)%MAX_TRIS;
278 	if (track_tris.first_mark >= track_tris.current_start) {
279 	    track_tris.num_tris = track_tris.num_tris - (track_tris.current_end + 1) -
280 		(MAX_TRIS - track_tris.first_mark);
281 	    track_tris.first_mark = track_tris.next_mark;
282 	} else if (track_tris.first_mark <= track_tris.current_end) {
283 	    track_tris.num_tris = track_tris.num_tris - (track_tris.current_end - track_tris.first_mark + 1);
284 	    track_tris.first_mark = track_tris.next_mark;
285 	}
286 
287     }
288 
289     for ( i = 0; i < num_new; i++ ) {
290 	track_tris.alpha[(track_tris.current_start+i)%MAX_TRIS] = alpha;
291 	track_tris.track_type[(track_tris.current_start+i)%MAX_TRIS] = track_type;
292 	track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[0].y =
293 	    find_y_coord( track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[0].x,
294 			  track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[0].z ) +
295 	    TRACK_HEIGHT;
296 	track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[1].y =
297 	    find_y_coord( track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[1].x,
298 			  track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[1].z ) +
299 	    TRACK_HEIGHT;
300 	track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[2].y =
301 	    find_y_coord( track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[2].x,
302 			  track_tris.tri[(track_tris.current_start+i)%MAX_TRIS].p[2].z ) +
303 	    TRACK_HEIGHT;
304     }
305 
306 }
307 
add_tri_tracks_from_quad(track_quad_t * q)308 static void add_tri_tracks_from_quad( track_quad_t *q )
309 {
310     add_tri_tracks_from_tri( q->v1, q->v2, q->v3, q->t1, q->t2, q->t3,
311 			     &q->track_type, &q->alpha );
312     add_tri_tracks_from_tri( q->v2, q->v4, q->v3, q->t2, q->t4, q->t3,
313 			     &q->track_type, &q->alpha );
314 }
315 
316 #endif
317 
318 
319 
init_track_marks(void)320 void init_track_marks(void)
321 {
322     track_marks.current_mark = 0;
323     track_marks.next_mark = 0;
324     track_marks.last_mark_time = -99999;
325     track_marks.last_mark_pos = make_point(-9999, -9999, -9999);
326     continuing_track = False;
327 #ifdef TRACK_TRIANGLES
328     track_tris.first_mark = 0;
329     track_tris.next_mark = 0;
330     track_tris.num_tris = 0;
331 #endif
332 }
333 
334 
335 
draw_track_marks(void)336 void draw_track_marks(void)
337 {
338 #ifdef TRACK_TRIANGLES
339     draw_tri_tracks();
340 #else
341     GLuint texid[NUM_TRACK_TYPES];
342     int current_quad, num_quads;
343     int first_quad;
344     track_quad_t *q, *qnext;
345     colour_t track_colour;
346 
347     track_colour = white;
348 
349     if (getparam_track_marks() == False) {
350 	return;
351     }
352 
353     set_gl_options( TRACK_MARKS );
354 
355     glColor4f( 0, 0, 0, 1);
356 
357     get_texture_binding( "track_head", &texid[TRACK_HEAD] );
358     get_texture_binding( "track_mark", &texid[TRACK_MARK] );
359     get_texture_binding( "track_tail", &texid[TRACK_TAIL] );
360 
361     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
362     set_material( white, black, 1.0 );
363     setup_course_lighting();
364 
365     num_quads = min( track_marks.current_mark, MAX_TRACK_MARKS -
366 		     track_marks.next_mark + track_marks.current_mark );
367     first_quad = track_marks.current_mark - num_quads;
368 
369     for ( current_quad = 0;
370 	  current_quad < num_quads;
371 	  current_quad++ )
372     {
373 	q = &track_marks.quads[(first_quad + current_quad)%MAX_TRACK_MARKS];
374 
375 	track_colour.a = q->alpha;
376 	set_material( track_colour, black, 1.0 );
377 
378 	glBindTexture( GL_TEXTURE_2D, texid[q->track_type] );
379 
380 	if ((q->track_type == TRACK_HEAD) || (q->track_type == TRACK_TAIL)) {
381 	    glBegin(GL_QUADS);
382 
383 	    glNormal3f( q->n1.x, q->n1.y, q->n1.z );
384 	    glTexCoord2f( q->t1.x, q->t1.y );
385 	    glVertex3f( q->v1.x, q->v1.y, q->v1.z );
386 
387 	    glNormal3f( q->n2.x, q->n2.y, q->n2.z );
388 	    glTexCoord2f( q->t2.x, q->t2.y );
389 	    glVertex3f( q->v2.x, q->v2.y, q->v2.z );
390 
391 	    glNormal3f( q->n4.x, q->n4.y, q->n4.z );
392 	    glTexCoord2f( q->t4.x, q->t4.y );
393 	    glVertex3f( q->v4.x, q->v4.y, q->v4.z );
394 
395 	    glNormal3f( q->n3.x, q->n3.y, q->n3.z );
396 	    glTexCoord2f( q->t3.x, q->t3.y );
397 	    glVertex3f( q->v3.x, q->v3.y, q->v3.z );
398 
399 	    glEnd();
400 
401 	} else {
402 
403 	    glBegin(GL_QUAD_STRIP);
404 
405 	    glNormal3f( q->n2.x, q->n2.y, q->n2.z );
406 	    glTexCoord2f( q->t2.x, q->t2.y );
407 	    glVertex3f( q->v2.x, q->v2.y, q->v2.z );
408 
409 	    glNormal3f( q->n1.x, q->n1.y, q->n1.z );
410 	    glTexCoord2f( q->t1.x, q->t1.y );
411 	    glVertex3f( q->v1.x, q->v1.y, q->v1.z );
412 
413 	    glNormal3f( q->n4.x, q->n4.y, q->n4.z );
414 	    glTexCoord2f( q->t4.x, q->t4.y );
415 	    glVertex3f( q->v4.x, q->v4.y, q->v4.z );
416 
417 	    glNormal3f( q->n3.x, q->n3.y, q->n3.z );
418 	    glTexCoord2f( q->t3.x, q->t3.y );
419 	    glVertex3f( q->v3.x, q->v3.y, q->v3.z );
420 
421 
422 	    qnext = &track_marks.quads[(first_quad+current_quad+1)%MAX_TRACK_MARKS];
423 	    while (( qnext->track_type == TRACK_MARK ) && (current_quad+1 < num_quads)) {
424 		current_quad++;
425 		q = &track_marks.quads[(first_quad+current_quad)%MAX_TRACK_MARKS];
426 		track_colour.a = qnext->alpha;
427 		set_material( track_colour, black, 1.0 );
428 
429 		glNormal3f( q->n4.x, q->n4.y, q->n4.z );
430 		glTexCoord2f( q->t4.x, q->t4.y );
431 		glVertex3f( q->v4.x, q->v4.y, q->v4.z );
432 
433 		glNormal3f( q->n3.x, q->n3.y, q->n3.z );
434 		glTexCoord2f( q->t3.x, q->t3.y );
435 		glVertex3f( q->v3.x, q->v3.y, q->v3.z );
436 
437 		qnext = &track_marks.quads[(first_quad+current_quad+1)%MAX_TRACK_MARKS];
438 	    }
439 	    glEnd();
440 	}
441 
442     }
443 #endif
444 
445 }
446 
break_track_marks(void)447 void break_track_marks( void )
448 {
449     track_quad_t *qprev, *qprevprev;
450     qprev = &track_marks.quads[(track_marks.current_mark-1)%MAX_TRACK_MARKS];
451     qprevprev = &track_marks.quads[(track_marks.current_mark-2)%MAX_TRACK_MARKS];
452 
453     if (track_marks.current_mark > 0) {
454 	qprev->track_type = TRACK_TAIL;
455 	qprev->t1 = make_point2d(0.0, 0.0);
456 	qprev->t2 = make_point2d(1.0, 0.0);
457 	qprev->t3 = make_point2d(0.0, 1.0);
458 	qprev->t4 = make_point2d(1.0, 1.0);
459 	qprevprev->t3.y = max((int)(qprevprev->t3.y+0.5), (int)(qprevprev->t1.y+1));
460 	qprevprev->t4.y = max((int)(qprevprev->t3.y+0.5), (int)(qprevprev->t1.y+1));
461     }
462     track_marks.last_mark_time = -99999;
463     track_marks.last_mark_pos = make_point(-9999, -9999, -9999);
464     continuing_track = False;
465 }
466 
add_track_mark(player_data_t * plyr)467 void add_track_mark( player_data_t *plyr )
468 {
469     vector_t width_vector;
470     vector_t left_vector;
471     vector_t right_vector;
472     scalar_t magnitude;
473     track_quad_t *q, *qprev, *qprevprev;
474     vector_t vel;
475     scalar_t speed;
476     point_t left_wing, right_wing;
477     scalar_t left_y, right_y;
478     scalar_t dist_from_surface;
479     plane_t surf_plane;
480     scalar_t comp_depth;
481     scalar_t tex_end;
482     scalar_t terrain_weights[NumTerrains];
483     scalar_t dist_from_last_mark;
484     vector_t vector_from_last_mark;
485 
486     if (getparam_track_marks() == False) {
487 	return;
488     }
489 
490     q = &track_marks.quads[track_marks.current_mark%MAX_TRACK_MARKS];
491     qprev = &track_marks.quads[(track_marks.current_mark-1)%MAX_TRACK_MARKS];
492     qprevprev = &track_marks.quads[(track_marks.current_mark-2)%MAX_TRACK_MARKS];
493 
494     vector_from_last_mark = subtract_points( plyr->pos, track_marks.last_mark_pos );
495     dist_from_last_mark = normalize_vector( &vector_from_last_mark );
496 
497 
498     get_surface_type(plyr->pos.x, plyr->pos.z, terrain_weights);
499     if (terrain_weights[Snow] < 0.5) {
500 	break_track_marks();
501 	return;
502     }
503 
504     vel = plyr->vel;
505     speed = normalize_vector( &vel );
506     if (speed < SPEED_TO_START_TRENCH) {
507 	break_track_marks();
508 	return;
509     }
510 
511     width_vector = cross_product( plyr->direction, make_vector( 0, 1, 0 ) );
512     magnitude = normalize_vector( &width_vector );
513     if ( magnitude == 0 ) {
514 	break_track_marks();
515 	return;
516     }
517 
518     left_vector = scale_vector( TRACK_WIDTH/2.0, width_vector );
519     right_vector = scale_vector( -TRACK_WIDTH/2.0, width_vector );
520     left_wing =  point_minus_vector( plyr->pos, left_vector );
521     right_wing = point_minus_vector( plyr->pos, right_vector );
522     left_y = find_y_coord( left_wing.x, left_wing.z );
523     right_y = find_y_coord( right_wing.x, right_wing.z );
524     if (fabs(left_y-right_y) > MAX_TRACK_DEPTH) {
525 	break_track_marks();
526 	return;
527     }
528 
529     surf_plane = get_local_course_plane( plyr->pos );
530     dist_from_surface = distance_to_plane( surf_plane, plyr->pos );
531     comp_depth = get_compression_depth(Snow);
532     if ( dist_from_surface >= (2*comp_depth) ) {
533 	break_track_marks();
534 	return;
535     }
536 
537 
538     if (!continuing_track) {
539 	break_track_marks();
540 	q->track_type = TRACK_HEAD;
541 	q->v1 = make_point( left_wing.x, left_y + TRACK_HEIGHT, left_wing.z );
542 	q->v2 = make_point( right_wing.x, right_y + TRACK_HEIGHT, right_wing.z );
543 	q->n1 = find_course_normal( q->v1.x, q->v1.z);
544 	q->n2 = find_course_normal( q->v2.x, q->v2.z);
545 	q->t1 = make_point2d(0.0, 0.0);
546 	q->t2 = make_point2d(1.0, 0.0);
547 	track_marks.next_mark = track_marks.current_mark + 1;
548     } else {
549 	if ( track_marks.next_mark == track_marks.current_mark ) {
550 	    q->v1 = qprev->v3;
551 	    q->v2 = qprev->v4;
552 	    q->n1 = qprev->n3;
553 	    q->n2 = qprev->n4;
554 	    q->t1 = qprev->t3;
555 	    q->t2 = qprev->t4;
556 	    if ( qprev->track_type != TRACK_HEAD ) {
557 		qprev->track_type = TRACK_MARK;
558 	    }
559 	    q->track_type = TRACK_MARK;
560 	}
561 	q->v3 = make_point( left_wing.x, left_y + TRACK_HEIGHT, left_wing.z );
562 	q->v4 = make_point( right_wing.x, right_y + TRACK_HEIGHT, right_wing.z );
563 	q->n3 = find_course_normal( q->v3.x, q->v3.z);
564 	q->n4 = find_course_normal( q->v4.x, q->v4.z);
565 	tex_end = speed*g_game.time_step/TRACK_WIDTH;
566 	if (q->track_type == TRACK_HEAD) {
567 	    q->t3= make_point2d(0.0, 1.0);
568 	    q->t4= make_point2d(1.0, 1.0);
569 	} else {
570 	    q->t3 = make_point2d(0.0, q->t1.y + tex_end);
571 	    q->t4 = make_point2d(1.0, q->t2.y + tex_end);
572 	}
573 
574 #ifdef TRACK_TRIANGLES
575 	add_tri_tracks_from_quad(q);
576 #endif
577 	track_marks.current_mark++;
578 	track_marks.next_mark = track_marks.current_mark;
579     }
580 
581     q->alpha = min( (2*comp_depth-dist_from_surface)/(4*comp_depth), 1.0 );
582 
583     track_marks.last_mark_time = g_game.time;
584     continuing_track = True;
585 
586 }
587