@@ -437,6 +437,8 @@ void vehicle_draw(vehicle_t *v, view_mode_t view_mode, bool selected,
437437 col_roll_neg = (Color ){ 255 , 40 , 80 , 255 }; // red (port)
438438 }
439439
440+ // Batched line trail: single rlBegin/rlEnd instead of per-segment DrawLine3D
441+ rlBegin (RL_LINES );
440442 for (int i = 1 ; i < v -> trail_count ; i ++ ) {
441443 int idx0 = (start + i - 1 ) % v -> trail_capacity ;
442444 int idx1 = (start + i ) % v -> trail_capacity ;
@@ -485,23 +487,26 @@ void vehicle_draw(vehicle_t *v, view_mode_t view_mode, bool selected,
485487 cb += (col_roll_neg .b - cb ) * rt * 0.7f ;
486488 }
487489
488- Color c ;
489- c .r = (unsigned char )(cr > 255 ? 255 : cr );
490- c .g = (unsigned char )(cg > 255 ? 255 : cg );
491- c .b = (unsigned char )(cb > 255 ? 255 : cb );
492- c .a = (unsigned char )(t * trail_color .a );
493- DrawLine3D (v -> trail [idx0 ], v -> trail [idx1 ], c );
490+ unsigned char ccr = (unsigned char )(cr > 255 ? 255 : cr );
491+ unsigned char ccg = (unsigned char )(cg > 255 ? 255 : cg );
492+ unsigned char ccb = (unsigned char )(cb > 255 ? 255 : cb );
493+ unsigned char ca = (unsigned char )(t * trail_color .a );
494+ rlColor4ub (ccr , ccg , ccb , ca );
495+ rlVertex3f (v -> trail [idx0 ].x , v -> trail [idx0 ].y , v -> trail [idx0 ].z );
496+ rlVertex3f (v -> trail [idx1 ].x , v -> trail [idx1 ].y , v -> trail [idx1 ].z );
494497 }
498+ rlEnd ();
495499 } else {
496500 // ── Speed ribbon trail (mode 2) ──
497- // Precompute per-vertex perpendicular by averaging adjacent segment
498- // directions so ribbon edges flow smoothly at joints .
501+ // Batched triangle ribbon: single rlBegin/rlEnd instead of per-quad DrawTriangle3D.
502+ // Perpendicular blending (70% previous + 30% current) prevents twisting on tight turns .
499503 float max_speed = v -> trail_speed_max > 1.0f ? v -> trail_speed_max : 1.0f ;
500504 float max_half_w = v -> model_scale * 0.25f ;
501505 float min_half_w = 0.02f ;
502506 Vector3 prev_perp = {0 };
503507 bool have_prev = false;
504508
509+ rlBegin (RL_TRIANGLES );
505510 for (int i = 1 ; i < v -> trail_count ; i ++ ) {
506511 int idx0 = (start + i - 1 ) % v -> trail_capacity ;
507512 int idx1 = (start + i ) % v -> trail_capacity ;
@@ -518,16 +523,14 @@ void vehicle_draw(vehicle_t *v, view_mode_t view_mode, bool selected,
518523
519524 // Compute perpendicular: use world-up cross for horizontal flight,
520525 // camera-based billboard for vertical flight
521- float vert = fabsf (dir .y );
526+ float vt = fabsf (dir .y );
522527 Vector3 perp ;
523- if (vert < 0.7f ) {
524- // Mostly horizontal: cross with world up
528+ if (vt < 0.7f ) {
525529 Vector3 up = { 0 , 1 , 0 };
526530 perp = (Vector3 ){ dir .z * up .y - dir .y * up .z ,
527531 dir .x * up .z - dir .z * up .x ,
528532 dir .y * up .x - dir .x * up .y };
529533 } else {
530- // Mostly vertical: cross with world forward (Z)
531534 Vector3 fwd = { 0 , 0 , 1 };
532535 perp = (Vector3 ){ dir .y * fwd .z - dir .z * fwd .y ,
533536 dir .z * fwd .x - dir .x * fwd .z ,
@@ -541,12 +544,16 @@ void vehicle_draw(vehicle_t *v, view_mode_t view_mode, bool selected,
541544 perp .x /= plen ; perp .y /= plen ; perp .z /= plen ;
542545 }
543546
544- // Ensure consistent orientation (don't flip side-to-side)
547+ // Ensure consistent orientation then blend with previous to reduce twisting
545548 if (have_prev ) {
546549 float dot = perp .x * prev_perp .x + perp .y * prev_perp .y + perp .z * prev_perp .z ;
547- if (dot < 0.0f ) {
548- perp .x = - perp .x ; perp .y = - perp .y ; perp .z = - perp .z ;
549- }
550+ if (dot < 0.0f ) { perp .x = - perp .x ; perp .y = - perp .y ; perp .z = - perp .z ; }
551+ float blend = 0.3f ;
552+ perp .x = prev_perp .x * (1.0f - blend ) + perp .x * blend ;
553+ perp .y = prev_perp .y * (1.0f - blend ) + perp .y * blend ;
554+ perp .z = prev_perp .z * (1.0f - blend ) + perp .z * blend ;
555+ float nlen = sqrtf (perp .x * perp .x + perp .y * perp .y + perp .z * perp .z );
556+ if (nlen > 0.001f ) { perp .x /= nlen ; perp .y /= nlen ; perp .z /= nlen ; }
550557 }
551558 prev_perp = perp ;
552559 have_prev = true;
@@ -574,11 +581,13 @@ void vehicle_draw(vehicle_t *v, view_mode_t view_mode, bool selected,
574581 Vector3 d = { p1 .x + perp .x * hw1 , p1 .y + perp .y * hw1 , p1 .z + perp .z * hw1 };
575582 Vector3 e = { p1 .x - perp .x * hw1 , p1 .y - perp .y * hw1 , p1 .z - perp .z * hw1 };
576583
577- DrawTriangle3D (a , b , d , c );
578- DrawTriangle3D (b , e , d , c );
579- DrawTriangle3D (d , b , a , c );
580- DrawTriangle3D (d , e , b , c );
584+ rlColor4ub (c .r , c .g , c .b , c .a );
585+ rlVertex3f (a .x , a .y , a .z ); rlVertex3f (b .x , b .y , b .z ); rlVertex3f (d .x , d .y , d .z );
586+ rlVertex3f (b .x , b .y , b .z ); rlVertex3f (e .x , e .y , e .z ); rlVertex3f (d .x , d .y , d .z );
587+ rlVertex3f (d .x , d .y , d .z ); rlVertex3f (b .x , b .y , b .z ); rlVertex3f (a .x , a .y , a .z );
588+ rlVertex3f (d .x , d .y , d .z ); rlVertex3f (e .x , e .y , e .z ); rlVertex3f (b .x , b .y , b .z );
581589 }
590+ rlEnd ();
582591 }
583592 }
584593
0 commit comments