00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <vamos/body/Gl_Car.h>
00020
00021 #include <vamos/geometry/Conversions.h>
00022 #include <vamos/body/Fuel_Tank.h>
00023 #include <vamos/body/Gauge.h>
00024 #include <vamos/body/Wheel.h>
00025
00026
00027
00028 #include <algorithm>
00029 #include <iomanip>
00030 #include <sstream>
00031 #include <string>
00032
00033 using namespace Vamos_Geometry;
00034
00035
00036
00037
00038 Vamos_Body::
00039 Rear_View_Mirror::Rear_View_Mirror (const Three_Vector& position,
00040 double width, double height,
00041 double direction,
00042 double field,
00043 double near_plane, double far_plane,
00044 std::string mask_file) :
00045 m_position (position),
00046 m_width (width),
00047 m_height (height),
00048 m_direction (direction),
00049 m_field (field),
00050 m_near_plane (near_plane),
00051 m_far_plane (far_plane),
00052 mp_mask (new Gl_Texture_Image (mask_file, false, false))
00053 {
00054 }
00055
00056
00057 Vamos_Body::
00058 Rear_View_Mirror::~Rear_View_Mirror ()
00059 {
00060 delete mp_mask;
00061 }
00062
00063 void Vamos_Body::
00064 Rear_View_Mirror::activate_viewport ()
00065 {
00066 glViewport (m_viewport.x, m_viewport.y, m_viewport.width, m_viewport.height);
00067 glScissor (m_viewport.x, m_viewport.y, m_viewport.width, m_viewport.height);
00068 }
00069
00070 Three_Vector Vamos_Body::
00071 Rear_View_Mirror::get_center () const
00072 {
00073 return Three_Vector (m_position [0],
00074 m_position [1] - m_width / 2.0,
00075 m_position [2] + m_height / 2.0);
00076 }
00077
00078 void Vamos_Body::
00079 Rear_View_Mirror::transform_view () const
00080 {
00081 glMatrixMode (GL_PROJECTION);
00082 glLoadIdentity ();
00083
00084 glScaled (-1.0, 1.0, 1.0);
00085 gluPerspective (m_field, m_viewport.aspect (), m_near_plane, m_far_plane);
00086 }
00087
00088 void Vamos_Body::
00089 Rear_View_Mirror::set_view ()
00090 {
00091 activate_viewport ();
00092 glClear (GL_DEPTH_BUFFER_BIT);
00093 transform_view ();
00094 }
00095
00096
00097
00098 extern bool verbose_output;
00099
00100
00101 Vamos_Body::
00102 Gl_Car::Gl_Car (const Three_Vector& pos)
00103 : Car (pos),
00104 mp_engine_sample (0),
00105 mp_dashboard (0)
00106 {
00107 if (verbose_output)
00108 std::cout << "gl_car init" << std::endl;
00109 int i;
00110 for (i = 0; i < 4; i++)
00111 tire_source[i] = 0;
00112
00113 num_paintjobs = 0;
00114 }
00115
00116
00117 Vamos_Body::
00118 Gl_Car::~Gl_Car ()
00119 {
00120 if (verbose_output)
00121 std::cout << "gl_car deinit" << std::endl;
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 delete mp_engine_sample;
00142
00143 delete mp_dashboard;
00144
00145 for (std::vector <Rear_View_Mirror*>::iterator it = m_mirrors.begin ();
00146 it != m_mirrors.end ();
00147 it++)
00148 {
00149 delete *it;
00150 }
00151
00152
00153
00154
00155
00156 shadowtex.Unload();
00157
00158
00159 }
00160
00161 void Vamos_Body::
00162 Gl_Car::exterior_model (std::string file, double scale,
00163 const Three_Vector& translation,
00164 const Three_Vector& rotation)
00165 {
00166
00167
00168
00169
00170
00171
00172
00173 string tex_size = "";
00174 settings.Get( "display.texture_size", tex_size );
00175
00176 shadowtex.Load(settings.GetFullDataPath("cars/" + m_car_file + "/textures/" + tex_size + "/shadow.png"), false);
00177 joeglass.Load(settings.GetFullDataPath("cars/" + m_car_file + "/glass.joe"));
00178 joeglass.AdditiveTexture(settings.GetFullDataPath("cars/" + m_car_file + "/brake-glass.joe"), 1);
00179 joeglass.Load(settings.GetFullDataPath("cars/" + m_car_file + "/glass.joe"));
00180 joeglass.AdditiveTexture(settings.GetFullDataPath("cars/" + m_car_file + "/brake-glass.joe"), 1);
00181 joeexterior.Load(settings.GetFullDataPath("cars/" + m_car_file + "/body.joe"));
00182 joeexterior.AdditiveTexture(settings.GetFullDataPath("cars/" + m_car_file + "/brake.joe"), 1);
00183
00184 joecollision.Load(settings.GetFullDataPath("cars/" + m_car_file + "/collision.joe"));
00185
00186
00187 char texfile[1024];
00188 int count = 0;
00189 sprintf(texfile, "cars/%s/textures/%s/body%02i.png", m_car_file.c_str(), tex_size.c_str(), count);
00190 while (count < 99 && utility.FileExists(settings.GetFullDataPath(texfile)))
00191 {
00192 count++;
00193 sprintf(texfile, "cars/%s/textures/%s/body%02i.png", m_car_file.c_str(), tex_size.c_str(), count);
00194 }
00195 num_paintjobs = count;
00196 }
00197
00198 void Vamos_Body::
00199 Gl_Car::interior_model (std::string file, double scale,
00200 const Three_Vector& translation,
00201 const Three_Vector& rotation)
00202 {
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 joeinterior.Load(settings.GetFullDataPath("cars/" + m_car_file + "/interior.joe"));
00213 }
00214
00215 void Vamos_Body::
00216 Gl_Car::set_perspective (double aspect)
00217 {
00218 gluPerspective (m_field_of_view, aspect, m_near_plane, m_far_plane);
00219 }
00220
00221 void Vamos_Body::
00222 Gl_Car::set_view (const Vamos_Geometry::Three_Vector& position,
00223 double field_of_view,
00224 double near_plane, double far_plane,
00225 double pan_angle)
00226 {
00227 m_driver_view = position;
00228 m_field_of_view = field_of_view;
00229 m_near_plane = near_plane;
00230 m_far_plane = far_plane;
00231 m_pan_angle = pan_angle;
00232 }
00233
00234 void Vamos_Body::
00235 Gl_Car::add_rear_view (const Vamos_Geometry::Three_Vector& position,
00236 double width, double height,
00237 double direction, double field,
00238 double near_plane, double far_plane,
00239 std::string mask_file)
00240 {
00241 m_mirrors.push_back (new Rear_View_Mirror (position, width, height,
00242 direction, field,
00243 near_plane, far_plane,
00244 mask_file));
00245 }
00246
00247
00248
00249 void Vamos_Body::
00250 Gl_Car::make_rear_view_mask (int window_width, int window_height)
00251 {
00252 glMatrixMode (GL_PROJECTION);
00253 glLoadIdentity ();
00254
00255 glViewport (0, 0, window_width, window_height);
00256 glScissor (0, 0, window_width, window_height);
00257
00258 glClearColor (0.0, 0.0, 0.0, 0.0);
00259 glClearStencil (0);
00260 glClear (GL_COLOR_BUFFER_BIT
00261 | GL_DEPTH_BUFFER_BIT
00262 | GL_STENCIL_BUFFER_BIT);
00263
00264 const double near_plane = 0.2;
00265 const double far_plane = 10.0;
00266 gluPerspective (field_of_view (), double (window_width)/window_height,
00267 near_plane, far_plane);
00268 view (0.0);
00269 glMatrixMode (GL_MODELVIEW);
00270 transform_body ();
00271
00272 for (std::vector <Rear_View_Mirror*>::iterator it = m_mirrors.begin ();
00273 it != m_mirrors.end ();
00274 it++)
00275 {
00276 (*it)->make_mask (window_width, window_height,
00277 m_driver_view, field_of_view ());
00278 }
00279 }
00280
00281
00282
00283 void Vamos_Body::
00284 Rear_View_Mirror::make_mask (int window_width, int window_height,
00285 const Three_Vector& driver_position,
00286 double driver_field_of_view)
00287 {
00288 glDisable (GL_LIGHTING);
00289 set_viewport (window_width, window_height,
00290 driver_position, driver_field_of_view);
00291 draw_mask_shape ();
00292 set_stencil (window_width, window_height);
00293 glEnable (GL_LIGHTING);
00294 }
00295
00296
00297
00298
00299 void Vamos_Body::
00300 Rear_View_Mirror::set_viewport (int window_width, int window_height,
00301 const Three_Vector& driver_position,
00302 double driver_field_of_view)
00303 {
00304 const Three_Vector pos = m_position - driver_position;
00305 const double y_factor =
00306 -1.0 / (pos [0] * tan (0.5 * deg_to_rad (driver_field_of_view)));
00307 const double aspect = double (window_width) / window_height;
00308 const double x_factor = -y_factor / aspect;
00309
00310 const int x0 = to_pixels (window_width, x_factor, pos [1]) - 1;
00311 m_viewport.x = clip (x0, 0, window_width - 1);
00312 const int y0 = to_pixels (window_height, y_factor, pos [2]) - 1;
00313 m_viewport.y = clip (y0, 0, window_height - 1);
00314
00315 const int x1 = to_pixels (window_width, x_factor, pos [1] - m_width);
00316 m_viewport.width = clip (x1, 0, window_width - 1) - m_viewport.x;
00317 const int y1 = to_pixels (window_height, y_factor, pos [2] + m_height);
00318 m_viewport.height = clip (y1, 0, window_height - 1) - m_viewport.y;
00319 }
00320
00321
00322
00323 void Vamos_Body::
00324 Rear_View_Mirror::draw_mask_shape ()
00325 {
00326 glStencilFunc (GL_ALWAYS, 1, 1);
00327 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
00328
00329 mp_mask->activate ();
00330
00331 glColor3d (1.0, 1.0, 1.0);
00332 glBegin (GL_QUADS);
00333 glTexCoord2d (0.0, 1.0);
00334 glVertex3d (m_position [0], m_position [1], m_position [2]);
00335 glTexCoord2d (1.0, 1.0);
00336 glVertex3d (m_position [0], m_position [1] - m_width, m_position [2]);
00337 glTexCoord2d (1.0, 0.0);
00338 glVertex3d (m_position [0], m_position [1] - m_width,
00339 m_position [2] + m_height);
00340 glTexCoord2d (0.0, 0.0);
00341 glVertex3d (m_position [0], m_position [1], m_position [2] + m_height);
00342 glEnd ();
00343
00344 glFlush ();
00345 }
00346
00347
00348
00349 void Vamos_Body::
00350 Rear_View_Mirror::set_stencil (int window_width, int window_height)
00351 {
00352 unsigned char* stencil_buffer = make_stencil_buffer ();
00353
00354 glMatrixMode (GL_PROJECTION);
00355 glPushMatrix ();
00356 glLoadIdentity ();
00357 gluOrtho2D (0.0, double (window_width), 0.0, double (window_height));
00358 glMatrixMode (GL_MODELVIEW);
00359 glPushMatrix ();
00360 glLoadIdentity ();
00361 glStencilFunc (GL_EQUAL, 1, 1);
00362 glStencilOp (GL_KEEP, GL_REPLACE, GL_REPLACE);
00363 glRasterPos2i (m_viewport.x, m_viewport.y);
00364 glDrawPixels (m_viewport.width, m_viewport.height, GL_STENCIL_INDEX,
00365 GL_UNSIGNED_BYTE, stencil_buffer);
00366 glPopMatrix ();
00367
00368 glMatrixMode (GL_PROJECTION);
00369 glPopMatrix ();
00370
00371 glFinish ();
00372
00373 delete stencil_buffer;
00374 }
00375
00376
00377
00378 unsigned char* Vamos_Body::
00379 Rear_View_Mirror::make_stencil_buffer ()
00380 {
00381 glReadBuffer (GL_BACK);
00382 const size_t elements = m_viewport.width * m_viewport.height;
00383 unsigned char* rgba_buffer = new unsigned char [4 * elements];
00384
00385 glReadPixels (m_viewport.x, m_viewport.y,
00386 m_viewport.width, m_viewport.height,
00387 GL_RGBA, GL_UNSIGNED_BYTE, rgba_buffer);
00388
00389 unsigned char* buffer = new unsigned char [elements];
00390 for (size_t i = 0; i < elements; i++)
00391 {
00392 buffer [i] = rgba_buffer [4 * i];
00393 }
00394 delete rgba_buffer;
00395 return buffer;
00396 }
00397
00398
00399 void Vamos_Body::
00400 Gl_Car::draw_rear_view (double aspect, int index)
00401 {
00402 Rear_View_Mirror* mirror = m_mirrors [index];
00403 mirror->set_view ();
00404 view (mirror->get_direction (), mirror->get_center ());
00405 }
00406
00407
00408 void Vamos_Body::
00409 Gl_Car::dashboard (Dashboard* dash)
00410 {
00411 delete mp_dashboard;
00412 mp_dashboard = dash;
00413 }
00414
00415 extern GLfloat LightPosition[4];
00416 #include "quat.h"
00417
00418 void Vamos_Body::
00419 Gl_Car::transform_body ()
00420 {
00421
00422
00423
00424
00425 Three_Vector cm = m_chassis.position ();
00426 glTranslatef (cm [0], cm [1], cm [2]);
00427
00428 double angle;
00429 Three_Vector axis = m_chassis.axis_angle (&angle);
00430
00431
00432
00433
00434
00435 glRotatef (angle, axis [0], axis [1], axis [2]);
00436
00437
00438
00439
00440
00441
00442
00443 cm = -m_chassis.center_of_mass ();
00444 glTranslatef (cm [0], cm [1], cm [2]);
00445
00446 QUATERNION carrot;
00447 carrot.SetAxisAngle(angle*3.141593/180.0, axis[0], axis[2], axis[1]);
00448 QUATERNION goofyfoot;
00449 goofyfoot.Rotate(-3.141593/2.0, 1,0,0);
00450 double tempmat[16];
00451 goofyfoot.GetMat(tempmat);
00452 float lp[4];
00453 lp[0] = LightPosition[0];
00454 lp[1] = LightPosition[1];
00455 lp[2] = LightPosition[2];
00456 lp[3] = 0;
00457 VERTEX lpv;
00458 lpv.Set(lp);
00459
00460 lpv = goofyfoot.ReturnConjugate().RotateVec(lpv);
00461 lpv = carrot.ReturnConjugate().RotateVec(lpv);
00462 lp[0] = lpv.x;
00463 lp[1] = lpv.z;
00464 lp[2] = lpv.y;
00465
00466 }
00467
00468
00469 void Vamos_Body::
00470 Gl_Car::draw (bool transform, float opacity)
00471 {
00472
00473 {
00474 if (transform)
00475 transform_body ();
00476
00477
00478
00479
00480
00481 glPushAttrib(GL_ALL_ATTRIB_BITS);
00482
00483
00484
00485 bool illum = false;
00486 if (brakesetting != 0)
00487 illum = true;
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 glColor4f(1,1,1,opacity);
00508
00509 glEnable(GL_BLEND);
00510 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00511 glCullFace(GL_FRONT);
00512 glEnable(GL_CULL_FACE);
00513
00514 joeexterior.SetTU(1, illum);
00515 joeexterior.DrawStatic();
00516
00517 glCullFace(GL_BACK);
00518 glColor4f(0,0,0,opacity);
00519 joeexterior.DrawStatic();
00520
00521 glColor4f(1,1,1,opacity);
00522 glDisable(GL_CULL_FACE);
00523
00524 joeinterior.DrawStatic();
00525
00526
00527 std::for_each (m_wheels.begin (), m_wheels.end (),
00528 std::mem_fun (&Wheel::draw));
00529
00530
00531
00532 utility.SelectTU(0);
00533
00534 glEnable(GL_CULL_FACE);
00535 glEnable(GL_BLEND);
00536 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00537 glCullFace(GL_FRONT);
00538 glEnable(GL_CULL_FACE);
00539 glDepthMask(0);
00540 glColor4f(1,1,1,opacity);
00541 joeglass.SetTU(1, illum);
00542 joeglass.DrawStatic();
00543
00544 glDepthMask(1);
00545
00546 glPopAttrib();
00547
00548 utility.SelectTU(3);
00549 glDisable(GL_TEXTURE_2D);
00550 utility.SelectTU(1);
00551 glDisable(GL_TEXTURE_2D);
00552 utility.SelectTU(0);
00553 }
00554 }
00555
00556 void Vamos_Body::
00557 Gl_Car::draw_interior ()
00558 {
00559
00560 draw_dashboard ();
00561 }
00562
00563 TEXTURE_HANDLE * Vamos_Body::
00564 Gl_Car::shadow_texture()
00565 {return &shadowtex;}
00566
00567 void Vamos_Body::
00568 Gl_Car::draw_dashboard ()
00569 {
00570 mp_dashboard->set_tachometer (rad_s_to_rpm (engine ()->rotational_speed ()));
00571 mp_dashboard->set_speedometer (m_s_to_km_h (wheel (2)->speed ()));
00572 mp_dashboard->set_fuel_gauge (fuel_tank ()->fuel ());
00573 mp_dashboard->set_gear_indicator (transmission ()->gear ());
00574 mp_dashboard->set_steering_wheel (m_steer_key_control.value ());
00575
00576 mp_dashboard->draw ();
00577 if (m_show_dashboard_extras)
00578 {
00579 draw_dashboard_extras ();
00580 }
00581 }
00582
00583 void Vamos_Body::
00584 Gl_Car::draw_string (const std::string& str, double x, double y)
00585 {
00586 font.Print(x, y, str.c_str(), 1, 5, 1);
00587
00588
00589
00590
00591
00592 }
00593
00594 void Vamos_Body::
00595 Gl_Car::draw_dashboard_extras ()
00596 {
00597 glMatrixMode (GL_PROJECTION);
00598 glPushMatrix ();
00599 glLoadIdentity ();
00600
00601
00602 gluOrtho2D (0, 10, 0, 10);
00603 glMatrixMode (GL_MODELVIEW);
00604 glPushMatrix ();
00605 glLoadIdentity ();
00606
00607 glDisable (GL_DEPTH_TEST);
00608 glDisable (GL_LIGHTING);
00609 glDisable (GL_TEXTURE_2D);
00610
00611 glColor3f (1.0, 1.0, 1.0);
00612
00613 std::ostringstream b_stream;
00614
00615 int rpm =
00616 int (Vamos_Geometry::rad_s_to_rpm (engine ()->rotational_speed ()));
00617 b_stream << "RPM " << rpm;
00618 draw_string (b_stream.str (), 0.4, 1.8);
00619
00620 b_stream.str ("");
00621 b_stream << "Torque " << int (engine ()->drive_torque ()) << " Nm";
00622 draw_string (b_stream.str (), 0.4, 1.4);
00623
00624 b_stream.str ("");
00625 b_stream << "Speed " << int (m_s_to_km_h (wheel (2)->speed ()))
00626 << " km/h";
00627 draw_string (b_stream.str (), 0.4, 1.0);
00628
00629 b_stream.str ("");
00630 b_stream << "Mass " << int (m_chassis.mass ()) << " kg";
00631 draw_string (b_stream.str (), 0.4, 0.6);
00632
00633 b_stream.str ("");
00634 char gear = 'N';
00635 if (transmission ()->gear () == -1)
00636 {
00637 gear = 'R';
00638 }
00639 else if (transmission ()->gear () > 0)
00640 {
00641 gear = transmission ()->gear () + '0';
00642 }
00643 b_stream << "Gear " << gear;
00644 draw_string (b_stream.str (), 0.4, 0.2);
00645
00646 b_stream.str ("");
00647 b_stream << "Fuel " << std::setprecision (1)
00648 << mp_fuel_tank->fuel () << " L";
00649 draw_string (b_stream.str (), 2.8, 0.2);
00650
00651
00652 b_stream.str ("");
00653 b_stream << "Slip Ratios";
00654 draw_string (b_stream.str (), 2.8, 1.4);
00655
00656 b_stream.str ("");
00657 b_stream.setf (std::ios::fixed);
00658 b_stream << std::setprecision (3) << m_wheels [0]->slip ();
00659 draw_string (b_stream.str (), 2.8, 1.0);
00660
00661 b_stream.str ("");
00662 b_stream << std::setprecision (3) << m_wheels [1]->slip ();
00663 draw_string (b_stream.str (), 3.6, 1.0);
00664
00665 b_stream.str ("");
00666 b_stream << std::setprecision (3) << m_wheels [2]->slip ();
00667 draw_string (b_stream.str (), 2.8, 0.6);
00668
00669 b_stream.str ("");
00670 b_stream << std::setprecision (3) << m_wheels [3]->slip ();
00671 draw_string (b_stream.str (), 3.6, 0.6);
00672
00673 glEnable (GL_DEPTH_TEST);
00674 glEnable (GL_LIGHTING);
00675 glEnable (GL_TEXTURE_2D);
00676
00677 glMatrixMode (GL_PROJECTION);
00678 glPopMatrix ();
00679 glMatrixMode (GL_MODELVIEW);
00680 glPopMatrix ();
00681 }
00682
00683
00684 void Vamos_Body::
00685 Gl_Car::view (double pan, const Three_Vector& view_position)
00686 {
00687 if (pan == 0.0)
00688 {
00689 pan = m_pan_key_control.value ();
00690 }
00691
00692
00693 double angle;
00694 Three_Vector axis = m_chassis.axis_angle (&angle);
00695
00696
00697 glRotated (90, 0.0, 1.0, 0.0);
00698 glRotated (-90, 1.0, 0.0, 0.0);
00699 glRotated (-angle, axis [0], axis [1], axis [2]);
00700
00701 Three_Vector z = m_chassis.rotate_out (Three_Vector (0.0, 0.0, 1.0));
00702 glRotated (-pan, z [0], z [1], z [2]);
00703
00704 Three_Vector pos =
00705 -m_chassis.transform_out (view_position - m_chassis.center_of_mass ());
00706 glTranslated (pos [0], pos [1], pos [2]);
00707 }
00708
00709
00710
00711 void Vamos_Body::
00712 Gl_Car::engine_sound (std::string file,
00713 double volume,
00714 double throttle_volume_factor,
00715 double engine_speed_volume_factor,
00716 double pitch)
00717 {
00718 delete mp_engine_sample;
00719
00720
00721 {
00722 m_throttle_volume_factor = throttle_volume_factor;
00723 m_engine_speed_volume_factor = engine_speed_volume_factor;
00724 mp_engine_sample = new Sample (file, volume, pitch, true, true);
00725
00726
00727 bool error = false;
00728 real_engine_sample = sound.NewSource(settings.GetFullDataPath("cars/" + m_car_file + "/engine.wav"), error);
00729 if (!error)
00730 sound.SetGain(real_engine_sample, 0);
00731
00732
00733 int i;
00734 for (i = 0; i < 4; i++)
00735 {
00736 error = false;
00737 tire_source[i] = sound.NewSource(settings.GetFullDataPath("sounds/tire_squeal.wav"), error);
00738 if (!error)
00739 sound.SetGain(tire_source[i], 0.0);
00740
00741 }
00742 }
00743 }
00744
00745 double Vamos_Body::
00746 Gl_Car::engine_pitch ()
00747 {
00748 return engine ()->rotational_speed ();
00749 }
00750
00751 double Vamos_Body::
00752 Gl_Car::engine_volume ()
00753 {
00754 return 1.0 + m_throttle_volume_factor * engine ()->throttle ()
00755 + m_engine_speed_volume_factor * engine ()->rotational_speed ();
00756 }
00757
00758 int Vamos_Body::Gl_Car::GetSoundSource()
00759 {
00760 return real_engine_sample;
00761 }
00762
00763 int Vamos_Body::Gl_Car::GetTireSoundSource(int i)
00764 {
00765 return tire_source[i];
00766 }
00767
00768 void Vamos_Body::Gl_Car::SetPaint(int pid)
00769 {
00770
00771
00772 if (num_paintjobs <= 0)
00773 return;
00774
00775
00776
00777 char texfile[1024];
00778 if (pid < 0)
00779 pid = num_paintjobs - ((-pid) % num_paintjobs);
00780 pid = pid % num_paintjobs;
00781 sprintf(texfile, "cars/%s/body%02i.png", m_car_file.c_str(), pid);
00782 joeexterior.Texture(settings.GetFullDataPath(texfile), 0);
00783
00784
00785
00786 }