#include #include #include "gauges.h" // 7-seg masks, bit order A B C D E F G; >=10 are letters const U8 SEG7[G_COUNT] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x50, // r 0x54, // n 0x40, // - 0x77, // A 0x7C, // b 0x6D, // S 0x78, // t 0x39, // C }; F32 gauge_angle( F32 t ) { const F32 A0 = -90.0f * (F32)M_PI / 180.0f; // south const F32 A1 = -360.0f * (F32)M_PI / 180.0f; // east, clockwise if( t < 0.0f ) t = 0.0f; if( t > 1.0f ) t = 1.0f; return A0 + ( A1 - A0 ) * t; } GAUGE_RENDERER::GAUGE_RENDERER() { nverts = 0; fade = 1.0f; } void GAUGE_RENDERER::clear() { nverts = 0; fade = 1.0f; } void GAUGE_RENDERER::set_fade( F32 f ) { if( f < 0.0f ) f = 0.0f; if( f > 1.0f ) f = 1.0f; fade = f; } U32 GAUGE_RENDERER::faded( U32 c ) const { if( fade >= 0.999f ) return c; U32 a = (U32)( ( c >> 24 ) * fade ); return ( c & 0x00ffffffu ) | ( a << 24 ); } void GAUGE_RENDERER::rect( F32 x, F32 y, F32 w, F32 h, U32 c ) { c = faded( c ); if( w <= 0.0f || h <= 0.0f ) return; if( nverts + 6 > MAX_VERTS ) return; VERTEX *v = verts + nverts; v[0].x = x; v[0].y = y; v[1].x = x + w; v[1].y = y; v[2].x = x; v[2].y = y + h; v[3].x = x + w; v[3].y = y; v[4].x = x + w; v[4].y = y + h; v[5].x = x; v[5].y = y + h; for( I32 i = 0; i < 6; i++ ) v[i].col = c; nverts += 6; } void GAUGE_RENDERER::line( F32 x0, F32 y0, F32 x1, F32 y1, F32 t, U32 c ) { c = faded( c ); F32 dx = x1 - x0, dy = y1 - y0; F32 len = sqrtf( dx * dx + dy * dy ); if( len < 1e-3f || nverts + 6 > MAX_VERTS ) return; F32 nx = -dy / len * t * 0.5f; F32 ny = dx / len * t * 0.5f; VERTEX *v = verts + nverts; v[0].x = x0 + nx; v[0].y = y0 + ny; v[1].x = x1 + nx; v[1].y = y1 + ny; v[2].x = x0 - nx; v[2].y = y0 - ny; v[3].x = x1 + nx; v[3].y = y1 + ny; v[4].x = x1 - nx; v[4].y = y1 - ny; v[5].x = x0 - nx; v[5].y = y0 - ny; for( I32 i = 0; i < 6; i++ ) v[i].col = c; nverts += 6; } void GAUGE_RENDERER::arc( F32 cx, F32 cy, F32 r0, F32 r1, F32 a0, F32 a1, U32 c ) { c = faded( c ); F32 span = a1 - a0; I32 segs = (I32)( fabsf( span ) / 0.05f ) + 1; if( segs > 256 ) segs = 256; F32 step = span / (F32)segs; F32 ca = cosf( a0 ), sa = sinf( a0 ); for( I32 i = 0; i < segs; i++ ) { if( nverts + 6 > MAX_VERTS ) return; F32 a = a0 + step * (F32)( i + 1 ); F32 cb = cosf( a ), sb = sinf( a ); VERTEX *v = verts + nverts; v[0].x = cx + r0 * ca; v[0].y = cy - r0 * sa; v[1].x = cx + r1 * ca; v[1].y = cy - r1 * sa; v[2].x = cx + r0 * cb; v[2].y = cy - r0 * sb; v[3].x = cx + r1 * ca; v[3].y = cy - r1 * sa; v[4].x = cx + r1 * cb; v[4].y = cy - r1 * sb; v[5].x = cx + r0 * cb; v[5].y = cy - r0 * sb; for( I32 k = 0; k < 6; k++ ) v[k].col = c; nverts += 6; ca = cb; sa = sb; } } void GAUGE_RENDERER::arc_grad( F32 cx, F32 cy, F32 r0, F32 r1, F32 a0, F32 a1, U32 c_in, U32 c_out ) { c_in = faded( c_in ); c_out = faded( c_out ); F32 span = a1 - a0; I32 segs = (I32)( fabsf( span ) / 0.05f ) + 1; if( segs > 256 ) segs = 256; F32 step = span / (F32)segs; F32 ca = cosf( a0 ), sa = sinf( a0 ); for( I32 i = 0; i < segs; i++ ) { if( nverts + 6 > MAX_VERTS ) return; F32 a = a0 + step * (F32)( i + 1 ); F32 cb = cosf( a ), sb = sinf( a ); VERTEX *v = verts + nverts; v[0].x = cx + r0 * ca; v[0].y = cy - r0 * sa; v[0].col = c_in; v[1].x = cx + r1 * ca; v[1].y = cy - r1 * sa; v[1].col = c_out; v[2].x = cx + r0 * cb; v[2].y = cy - r0 * sb; v[2].col = c_in; v[3].x = cx + r1 * ca; v[3].y = cy - r1 * sa; v[3].col = c_out; v[4].x = cx + r1 * cb; v[4].y = cy - r1 * sb; v[4].col = c_out; v[5].x = cx + r0 * cb; v[5].y = cy - r0 * sb; v[5].col = c_in; nverts += 6; ca = cb; sa = sb; } } void GAUGE_RENDERER::disc( F32 cx, F32 cy, F32 r, U32 c ) { arc( cx, cy, 0.0f, r, 0.0f, 2.0f * (F32)M_PI, c ); } void GAUGE_RENDERER::disc_grad( F32 cx, F32 cy, F32 r, U32 c_in, U32 c_out ) { arc_grad( cx, cy, 0.0f, r, 0.0f, 2.0f * (F32)M_PI, c_in, c_out ); } void GAUGE_RENDERER::tick( F32 cx, F32 cy, F32 a, F32 rin, F32 rout, F32 t, U32 c ) { F32 dx = cosf( a ), dy = -sinf( a ); line( cx + dx * rin, cy + dy * rin, cx + dx * rout, cy + dy * rout, t, c ); } void GAUGE_RENDERER::needle( F32 cx, F32 cy, F32 a, F32 len, F32 back, F32 w, U32 c ) { c = faded( c ); if( nverts + 6 > MAX_VERTS ) return; F32 dx = cosf( a ), dy = -sinf( a ); F32 px = -dy, py = dx; F32 bx = cx - dx * back, by = cy - dy * back; F32 tx = cx + dx * len, ty = cy + dy * len; F32 wt = w * 0.18f; VERTEX *v = verts + nverts; v[0].x = bx + px * w * 0.5f; v[0].y = by + py * w * 0.5f; v[1].x = tx + px * wt; v[1].y = ty + py * wt; v[2].x = bx - px * w * 0.5f; v[2].y = by - py * w * 0.5f; v[3].x = tx + px * wt; v[3].y = ty + py * wt; v[4].x = tx - px * wt; v[4].y = ty - py * wt; v[5].x = bx - px * w * 0.5f; v[5].y = by - py * w * 0.5f; for( I32 i = 0; i < 6; i++ ) v[i].col = c; nverts += 6; } void GAUGE_RENDERER::needle_trail( F32 cx, F32 cy, F32 a0, F32 a1, F32 r0, F32 r1, U32 c ) { c = faded( c ); F32 span = a1 - a0; if( fabsf( span ) < 1e-3f ) return; I32 segs = (I32)( fabsf( span ) / 0.03f ) + 1; if( segs > 96 ) segs = 96; F32 step = span / (F32)segs; U32 base_a = c >> 24; U32 rgb = c & 0x00ffffffu; F32 ca = cosf( a0 ), sa = sinf( a0 ); for( I32 i = 0; i < segs; i++ ) { if( nverts + 6 > MAX_VERTS ) return; F32 f0 = (F32)i / (F32)segs; F32 f1 = (F32)( i + 1 ) / (F32)segs; U32 c0 = rgb | ( (U32)( base_a * f0 * f0 ) << 24 ); U32 c1 = rgb | ( (U32)( base_a * f1 * f1 ) << 24 ); F32 a = a0 + step * (F32)( i + 1 ); F32 cb = cosf( a ), sb = sinf( a ); VERTEX *v = verts + nverts; v[0].x = cx + r0 * ca; v[0].y = cy - r0 * sa; v[0].col = c0; v[1].x = cx + r1 * ca; v[1].y = cy - r1 * sa; v[1].col = c0; v[2].x = cx + r0 * cb; v[2].y = cy - r0 * sb; v[2].col = c1; v[3].x = cx + r1 * ca; v[3].y = cy - r1 * sa; v[3].col = c1; v[4].x = cx + r1 * cb; v[4].y = cy - r1 * sb; v[4].col = c1; v[5].x = cx + r0 * cb; v[5].y = cy - r0 * sb; v[5].col = c0; nverts += 6; ca = cb; sa = sb; } } void GAUGE_RENDERER::glyph( F32 x, F32 y, F32 dw, F32 dh, I32 g, U32 c ) { if( g < 0 || g >= G_COUNT ) return; U32 m = SEG7[g]; F32 t = dh * 0.13f; if( t < 1.0f ) t = 1.0f; F32 half = ( dh - 3.0f * t ) * 0.5f; if( m & 0x01 ) rect( x + t, y, dw - 2 * t, t, c ); if( m & 0x02 ) rect( x + dw - t, y + t, t, half, c ); if( m & 0x04 ) rect( x + dw - t, y + 2 * t + half, t, half, c ); if( m & 0x08 ) rect( x + t, y + dh - t, dw - 2 * t, t, c ); if( m & 0x10 ) rect( x, y + 2 * t + half, t, half, c ); if( m & 0x20 ) rect( x, y + t, t, half, c ); if( m & 0x40 ) rect( x + t, y + ( dh - t ) * 0.5f, dw - 2 * t, t, c ); } void GAUGE_RENDERER::glyph_c( F32 cx, F32 cy, F32 dw, F32 dh, I32 g, U32 c ) { glyph( cx - dw * 0.5f, cy - dh * 0.5f, dw, dh, g, c ); } void GAUGE_RENDERER::number( F32 cx, F32 cy, F32 dw, F32 dh, I32 val, U32 c ) { if( val < 0 ) val = 0; if( val > 99999 ) val = 99999; I32 nd = 1, v = val; while( v >= 10 ) { nd++; v /= 10; } F32 adv = dw * 1.35f; F32 x = cx + ( adv * (F32)nd - ( adv - dw ) ) - dw; v = val; for( I32 i = 0; i < nd; i++ ) { glyph( x, cy - dh * 0.5f, dw, dh, v % 10, c ); v /= 10; x -= adv; } } void GAUGE_RENDERER::number_r( F32 cx, F32 cy, F32 dw, F32 dh, I32 val, U32 c ) { if( val < 0 ) val = 0; if( val > 99999 ) val = 99999; I32 nd = 1, v = val; while( v >= 10 ) { nd++; v /= 10; } F32 adv = dw * 1.35f; F32 x = cx; v = val; for( I32 i = 0; i < nd; i++ ) { glyph( x, cy - dh * 0.5f, dw, dh, v % 10, c ); v /= 10; x -= adv; } } void GAUGE_RENDERER::number_c( F32 cx, F32 cy, F32 dw, F32 dh, I32 val, U32 c ) { if( val < 0 ) val = 0; if( val > 99999 ) val = 99999; I32 nd = 1, v = val; while( v >= 10 ) { nd++; v /= 10; } F32 adv = dw * 1.35f; F32 x = cx + ( adv * (F32)nd - ( adv - dw ) ) * 0.5f - dw; v = val; for( I32 i = 0; i < nd; i++ ) { glyph( x, cy - dh * 0.5f, dw, dh, v % 10, c ); v /= 10; x -= adv; } } void GAUGE_RENDERER::lamp( F32 cx, F32 cy, F32 h, const I32 g[3], U32 c ) { F32 dw = h * 0.62f; F32 adv = dw * 1.35f; F32 x = cx - adv; for( I32 i = 0; i < 3; i++ ) { glyph_c( x, cy, dw, h, g[i], c ); x += adv; } } void GAUGE_RENDERER::build_tach_bg( F32 cx, F32 cy, F32 r, F32 rpm_max, F32 red_ang, F32 rpm_off ) { disc_grad( cx, cy, r * 1.10f, C_HALO_IN, C_HALO_OUT ); disc_grad( cx, cy, r, C_FACE_MID, C_FACE_EDGE ); arc( cx, cy, r * 0.20f, r * 0.54f, 40.0f * (F32)M_PI / 180.0f, 270.0f * (F32)M_PI / 180.0f, C_SWIRL ); arc( cx, cy, r - 2.0f, r, 0.0f, 2.0f * (F32)M_PI, C_RIM ); if( rpm_off > 0.f ) { arc( cx, cy, r * 0.84f, r * 0.965f, gauge_angle( red_ang ), gauge_angle( red_ang + rpm_off ), C_REDLINE2 ); } arc( cx, cy, r * 0.84f, r * 0.965f, gauge_angle( red_ang + rpm_off ), gauge_angle( 1.0f ), C_REDLINE ); I32 kmax = (I32)( rpm_max / 1000.0f + 0.999f ); for( I32 k1000 = 0; k1000 <= kmax; k1000++ ) { F32 t = (F32)k1000 * 1000.0f / rpm_max; if( t > 1.0f ) break; F32 a = gauge_angle( t ); tick( cx, cy, a, r * 0.85f, r - 2.0f, r * 0.020f, C_TICK ); F32 lx = cx + cosf( a ) * r * 0.74f; F32 ly = cy - sinf( a ) * r * 0.74f; if( k1000 < 10 ) glyph_c( lx, ly, r * 0.09f, r * 0.15f, k1000, C_LABEL ); else number_c( lx, ly, r * 0.075f, r * 0.13f, k1000, C_LABEL ); } for( I32 rr = 250; rr <= (I32)rpm_max; rr += 250 ) { if( rr % 1000 == 0 ) continue; F32 t = (F32)rr / rpm_max; if( t > 1.0f ) break; tick( cx, cy, gauge_angle( t ), r * 0.87f, r * 0.93f, r * 0.010f, C_TICKMIN ); } } void GAUGE_RENDERER::build_tach_gear_speed( F32 cx, F32 cy, F32 r, F32 rpm, F32 rpm_max, I32 gear, F32 speed, F32 red_ang ) { F32 now = t_nows(); U8 flash = fmodf( now, 0.2f ) > 0.1f; I32 g = gear == 0 ? G_R : ( gear >= 11 ? G_N : gear ); glyph_c( cx + r * 0.45f, cy - r * 0.11f, r * 0.19f, r * 0.29f, 0, C_LAMPBG ); U32 gearc = C_GEAR; if( gear != G_N && rpm > rpm_max * red_ang && !flash ) gearc = rgba( 255, 0, 0, 255 ); else if( gear == 0 && flash ) gearc = rgba( 0, 255, 255, 255 ); glyph_c( cx + r * 0.45f, cy - r * 0.11f, r * 0.19f, r * 0.29f, g, gearc ); I32 spx = cx + r * 0.37f; I32 spy = cy + r * 0.24f; for( U32 i = 0; i < 3; ++i ) number( spx + i * r * 0.13f * 1.35f, spy, r * 0.13f, r * 0.24f, 0, C_LAMPBG ); number_r( spx + r * 0.13f * 1.35f * 2, spy, r * 0.13f, r * 0.24f, (I32)( speed + 0.5f ), C_SPEED ); } void GAUGE_RENDERER::build_tach( F32 cx, F32 cy, F32 r, F32 trail, F32 rpm, F32 rpm_max, F32 red_ang, F32 rpm_off, F32 peak, I32 gear, F32 speed, U8 have_ext, U8 flash_needle ) { F32 now = t_nows(); U8 flash = fmodf( now, 0.2f ) > 0.1f; if( rpm_max < 100.0f ) rpm_max = 8000.0f; build_tach_bg( cx, cy, r, rpm_max, red_ang, rpm_off ); if( have_ext ) { build_tach_gear_speed( cx, cy, r, rpm, rpm_max, gear, speed, red_ang ); } F32 pt = peak / rpm_max; if( pt > 0.01f && pt <= 1.0f ) { tick( cx, cy, gauge_angle( pt ), r * 0.84f, r * 0.945f, r * 0.016f, C_PEAK ); } U32 trailc = C_TRAIL; U32 needlec = C_NEEDLE; if( flash_needle ) { if( flash && rpm > rpm_max * red_ang ) needlec = trailc = rgba( 255, 0, 0, 255 ); else if( !flash && gear == 0 ) needlec = trailc = C_LAMP; } F32 t = rpm / rpm_max; if( t < 0.0f ) t = 0.0f; if( t > 1.0f ) t = 1.0f; if( fabsf( trail ) > 0.002f ) { F32 t0 = t - trail; if( t0 < 0.0f ) t0 = 0.0f; if( t0 > 1.0f ) t0 = 1.0f; needle_trail( cx, cy, gauge_angle( t0 ), gauge_angle( t ), r * 0.10f, r * 0.82f, trailc ); } needle( cx, cy, gauge_angle( t ), r * 0.82f, r * 0.16f, r * 0.05f, needlec ); disc( cx, cy, r * 0.065f, C_HUB ); disc( cx, cy, r * 0.026f, C_HUBDOT ); } void GAUGE_RENDERER::build_boost_bg( F32 cx, F32 cy, F32 r, F32 range ) { F32 span = range + 1.0f; disc_grad( cx, cy, r * 1.12f, C_HALO_IN, C_HALO_OUT ); disc_grad( cx, cy, r, C_FACE_MID, C_FACE_EDGE ); arc( cx, cy, r - 2.0f, r, 0.0f, 2.0f * (F32)M_PI, C_RIM ); arc( cx, cy, r * 0.80f, r * 0.92f, gauge_angle( 0.0f ), gauge_angle( 0.10f / span ), C_REDLINE ); arc( cx, cy, r * 0.80f, r * 0.92f, gauge_angle( ( span - 0.25f ) / span ), gauge_angle( 1.0f ), C_REDLINE ); arc( cx, cy, r * 0.86f, r * 0.90f, gauge_angle( 0.10f / span ), gauge_angle( 1.0f / span ), C_VACUUM ); for( I32 q = 0; q <= (I32)( span / 0.25f + 0.5f ); q++ ) { F32 v = -1.0f + 0.25f * (F32)q; F32 t = ( v + 1.0f ) / span; if( t > 1.001f ) break; U8 whole = fabsf( v - roundf( v ) ) < 0.01f; U8 zero = fabsf( v ) < 0.01f; tick( cx, cy, gauge_angle( t ), whole ? r * 0.74f : r * 0.85f, r - 2.0f, zero ? r * 0.05f : ( whole ? r * 0.03f : r * 0.018f ), zero ? C_ZERO : ( whole ? C_TICK : C_TICKMIN ) ); if( whole ) { F32 a = gauge_angle( t ); F32 lx = cx + cosf( a ) * r * 0.58f; F32 ly = cy - sinf( a ) * r * 0.58f; I32 av = (I32)fabsf( roundf( v ) ); if( v < -0.01f ) { glyph_c( lx - r * 0.09f, ly, r * 0.09f, r * 0.16f, G_DASH, C_LABEL ); glyph_c( lx + r * 0.05f, ly, r * 0.09f, r * 0.16f, av, C_LABEL ); } else { glyph_c( lx, ly, r * 0.10f, r * 0.17f, av, C_LABEL ); } } } } void GAUGE_RENDERER::build_boost( F32 cx, F32 cy, F32 r, F32 bar, F32 range, F32 trail ) { build_boost_bg( cx, cy, r, range ); F32 span = range + 1.0f; F32 t = ( bar + 1.0f ) / span; if( fabsf( trail ) > 0.002f ) { F32 t0 = t - trail; if( t0 < 0.0f ) t0 = 0.0f; if( t0 > 1.0f ) t0 = 1.0f; needle_trail( cx, cy, gauge_angle( t0 ), gauge_angle( t ), r * 0.12f, r * 0.76f, C_TRAIL ); } needle( cx, cy, gauge_angle( t ), r * 0.78f, r * 0.16f, r * 0.06f, C_NEEDLE ); disc( cx, cy, r * 0.075f, C_HUB ); disc( cx, cy, r * 0.030f, C_HUBDOT ); } void GAUGE_RENDERER::build_lamps( F32 cx, F32 cy, F32 r, F32 h, U8 hb, U8 abs_on, U8 tcs_on, U8 abs_flash, U8 tcs_flash ) { const I32 ABS[3] = { G_A, G_B, G_S }; const I32 TCS[3] = { G_T, G_C, G_S }; F32 hbx = cx + r * 0.48f; F32 hby = cy + r * 0.53f; U32 col = !hb ? C_LAMPBG : rgba( 255, 0, 0, 255 ); arc( hbx, hby, r * 0.1f, r * 0.117f, 0, M_PI * 2.f, col ); line( hbx, hby - r * 0.075, hbx, hby + r * 0.04f, r * 0.03, col ); line( hbx, hby + r * 0.05, hbx, hby + r * 0.085f, r * 0.03, col ); if( abs_on ) lamp( cx + h * 1.6f, cy + r * 0.35f, h, ABS, C_LAMPBG ); if( abs_flash ) lamp( cx + h * 1.6f, cy + r * 0.35f, h, ABS, C_LAMP ); if( tcs_on ) lamp( cx + h * 1.6f, cy + r * 0.35f + h * 1.1f, h, TCS, C_LAMPBG ); if( tcs_flash ) lamp( cx + h * 1.6f, cy + r * 0.35f + h * 1.1f, h, TCS, C_LAMP ); } U32 get_tire_color( F32 temp ) { U32 a = 200; temp -= 32.f; temp /= 1.8f; if( temp < 30.f ) return rgba( 0, 0, 255, a ); if( temp < 45.f ) return rgba( 0, 255, 255, a ); if( temp < 75.f ) return rgba( 0, 255, 0, a ); if( temp < 90.f ) return rgba( 0, 170, 0, a ); if( temp < 120.f ) return rgba( 255, 170, 0, a ); if( temp < 150.f ) return rgba( 255, 100, 0, a ); return rgba( 255, 0, 0, a ); } void GAUGE_RENDERER::build_tires( F32 cx, F32 cy, F32 h, F32 fl, F32 fr, F32 rl, F32 rr ) { const F32 tire_w = h * 0.023f; const F32 tire_h = h * 0.037f; const F32 rect_w = tire_w * 0.53f; const F32 rect_h = tire_h * 0.3f; line( cx - tire_w, cy - tire_h, cx + tire_w, cy - tire_h, 2, C_TICK ); line( cx - tire_w, cy + tire_h, cx + tire_w, cy + tire_h, 2, C_TICK ); line( cx, cy - tire_h, cx, cy + tire_h, 2, C_TICK ); // fl rect( cx - tire_w - rect_w, cy - tire_h - rect_h, rect_w, rect_h * 2.f, get_tire_color( fl ) ); line( cx - tire_w, cy - tire_h - rect_h, cx - tire_w, cy - tire_h + rect_h, 2, C_TICK ); line( cx - tire_w, cy - tire_h - rect_h, cx - tire_w - rect_w, cy - tire_h - rect_h, 2, C_TICK ); line( cx - tire_w, cy - tire_h + rect_h, cx - tire_w - rect_w, cy - tire_h + rect_h, 2, C_TICK ); line( cx - tire_w - rect_w, cy - tire_h - rect_h, cx - tire_w - rect_w, cy - tire_h + rect_h, 2, C_TICK ); // fr rect( cx + tire_w, cy - tire_h - rect_h, rect_w, rect_h * 2.f, get_tire_color( fr ) ); line( cx + tire_w, cy - tire_h - rect_h, cx + tire_w, cy - tire_h + rect_h, 2, C_TICK ); line( cx + tire_w, cy - tire_h - rect_h, cx + tire_w + rect_w, cy - tire_h - rect_h, 2, C_TICK ); line( cx + tire_w, cy - tire_h + rect_h, cx + tire_w + rect_w, cy - tire_h + rect_h, 2, C_TICK ); line( cx + tire_w + rect_w, cy - tire_h - rect_h, cx + tire_w + rect_w, cy - tire_h + rect_h, 2, C_TICK ); // rl rect( cx - tire_w - rect_w, cy + tire_h - rect_h, rect_w, rect_h * 2.f, get_tire_color( rl ) ); line( cx - tire_w, cy + tire_h - rect_h, cx - tire_w, cy + tire_h + rect_h, 2, C_TICK ); line( cx - tire_w, cy + tire_h - rect_h, cx - tire_w - rect_w, cy + tire_h - rect_h, 2, C_TICK ); line( cx - tire_w, cy + tire_h + rect_h, cx - tire_w - rect_w, cy + tire_h + rect_h, 2, C_TICK ); line( cx - tire_w - rect_w, cy + tire_h - rect_h, cx - tire_w - rect_w, cy + tire_h + rect_h, 2, C_TICK ); // rr rect( cx + tire_w, cy + tire_h - rect_h, rect_w, rect_h * 2.f, get_tire_color( rr ) ); line( cx + tire_w, cy + tire_h - rect_h, cx + tire_w, cy + tire_h + rect_h, 2, C_TICK ); line( cx + tire_w, cy + tire_h - rect_h, cx + tire_w + rect_w, cy + tire_h - rect_h, 2, C_TICK ); line( cx + tire_w, cy + tire_h + rect_h, cx + tire_w + rect_w, cy + tire_h + rect_h, 2, C_TICK ); line( cx + tire_w + rect_w, cy + tire_h - rect_h, cx + tire_w + rect_w, cy + tire_h + rect_h, 2, C_TICK ); }