// output top and bottom vectors // fvec == forward vector (eye viewpoint basically. in world coords) // pos == world coordinate of the point we're calculating "around" // w == width of the diff between top and bottom around pos void trail_calc_facing_pts( vec3d *top, vec3d *bot, vec3d *fvec, vec3d *pos, float w ) { vec3d uvec, rvec; vm_vec_sub( &rvec, &Eye_position, pos ); if (!IS_VEC_NULL(&rvec)) vm_vec_normalize( &rvec ); vm_vec_crossprod(&uvec,fvec,&rvec); if (!IS_VEC_NULL(&uvec)) vm_vec_normalize(&uvec); vm_vec_scale_add( top, pos, &uvec, w * 0.5f ); vm_vec_scale_add( bot, pos, &uvec, -w * 0.5f ); }
void physics_apply_whack(vec3d *impulse, vec3d *pos, physics_info *pi, matrix *orient, float mass) { vec3d local_torque, torque; // vec3d npos; // Detect null vector. if ((fl_abs(impulse->xyz.x) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.y) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.z) <= WHACK_LIMIT)) return; // first do the rotational velocity // calculate the torque on the body based on the point on the // object that was hit and the momentum being applied to the object vm_vec_crossprod(&torque, pos, impulse); vm_vec_rotate ( &local_torque, &torque, orient ); vec3d delta_rotvel; vm_vec_rotate( &delta_rotvel, &local_torque, &pi->I_body_inv ); vm_vec_scale ( &delta_rotvel, (float) ROTVEL_WHACK_CONST ); vm_vec_add2( &pi->rotvel, &delta_rotvel ); //mprintf(("Whack: %7.3f %7.3f %7.3f\n", pi->rotvel.xyz.x, pi->rotvel.xyz.y, pi->rotvel.xyz.z)); // instant whack on the velocity // reduce damping on all axes pi->flags |= PF_REDUCED_DAMP; update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) ); // find time for shake from weapon to end int dtime = timestamp_until(pi->afterburner_decay); if (dtime < WEAPON_SHAKE_TIME) { pi->afterburner_decay = timestamp( WEAPON_SHAKE_TIME ); } // Goober5000 - pi->mass should probably be just mass, as specified in the header vm_vec_scale_add2( &pi->vel, impulse, 1.0f / mass ); if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) { // Get DaveA nprintf(("Physics", "speed reset in physics_apply_whack [speed: %f]\n", vm_vec_mag(&pi->vel))); vm_vec_normalize(&pi->vel); vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED); } vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient ); // set so velocity will ramp starting from current speed // ramped velocity is now affected by collision }
void physics_apply_shock(vec3d *direction_vec, float pressure, physics_info *pi, matrix *orient, vec3d *min, vec3d *max, float radius) { vec3d normal; vec3d local_torque, temp_torque, torque; vec3d impact_vec; vec3d area; vec3d sin; if (radius > MAX_RADIUS) { return; } vm_vec_normalize_safe ( direction_vec ); area.xyz.x = (max->xyz.y - min->xyz.z) * (max->xyz.z - min->xyz.z); area.xyz.y = (max->xyz.x - min->xyz.x) * (max->xyz.z - min->xyz.z); area.xyz.z = (max->xyz.x - min->xyz.x) * (max->xyz.y - min->xyz.y); normal.xyz.x = vm_vec_dotprod( direction_vec, &orient->vec.rvec ); normal.xyz.y = vm_vec_dotprod( direction_vec, &orient->vec.uvec ); normal.xyz.z = vm_vec_dotprod( direction_vec, &orient->vec.fvec ); sin.xyz.x = fl_sqrt( fl_abs(1.0f - normal.xyz.x*normal.xyz.x) ); sin.xyz.y = fl_sqrt( fl_abs(1.0f - normal.xyz.y*normal.xyz.y) ); sin.xyz.z = fl_sqrt( fl_abs(1.0f - normal.xyz.z*normal.xyz.z) ); vm_vec_make( &torque, 0.0f, 0.0f, 0.0f ); // find the torque exerted due to the shockwave hitting each face // model the effect of the shockwave as if the shockwave were a plane of projectiles, // all moving in the direction direction_vec. then find the torque as the cross prod // of the force (pressure * area * normal * sin * scale * mass) // normal takes account the fraction of the surface exposed to the shockwave // the sin term is not technically needed but "feels" better // scale factors out the increase in area with larger objects // more massive objects get less rotation // find torque due to forces on the right/left face if ( normal.xyz.x < 0.0f ) // normal < 0, hits the right face vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, max->xyz.x * pressure * area.xyz.x * normal.xyz.x * sin.xyz.x / pi->mass ); else // normal > 0, hits the left face vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, min->xyz.x * pressure * area.xyz.x * -normal.xyz.x * sin.xyz.x / pi->mass ); vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec ); vm_vec_add2( &torque, &temp_torque ); // find torque due to forces on the up/down face if ( normal.xyz.y < 0.0f ) vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, max->xyz.y * pressure * area.xyz.y * normal.xyz.y * sin.xyz.y / pi->mass ); else vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, min->xyz.y * pressure * area.xyz.y * -normal.xyz.y * sin.xyz.y / pi->mass ); vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec ); vm_vec_add2( &torque, &temp_torque ); // find torque due to forces on the forward/backward face if ( normal.xyz.z < 0.0f ) vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, max->xyz.z * pressure * area.xyz.z * normal.xyz.z * sin.xyz.z / pi->mass ); else vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, min->xyz.z * pressure * area.xyz.z * -normal.xyz.z * sin.xyz.z / pi->mass ); vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec ); vm_vec_add2( &torque, &temp_torque ); // compute delta rotvel, scale according to blast and radius float scale; if (radius < MIN_RADIUS) { scale = 1.0f; } else { scale = (MAX_RADIUS - radius)/(MAX_RADIUS-MIN_RADIUS); } // set shockwave shake amplitude, duration, flag pi->shockwave_shake_amp = (float)(MAX_SHAKE*(pressure/STD_PRESSURE)*scale); pi->shockwave_decay = timestamp( SW_BLAST_DURATION ); pi->flags |= PF_IN_SHOCKWAVE; // safety dance if (!(IS_VEC_NULL_SQ_SAFE(&torque))) { vec3d delta_rotvel; vm_vec_rotate( &local_torque, &torque, orient ); vm_vec_copy_normalize(&delta_rotvel, &local_torque); vm_vec_scale(&delta_rotvel, (float)(MAX_ROTVEL*(pressure/STD_PRESSURE)*scale)); // nprintf(("Physics", "rotvel scale %f\n", (MAX_ROTVEL*(pressure/STD_PRESSURE)*scale))); vm_vec_add2(&pi->rotvel, &delta_rotvel); } // set reduced translational damping, set flags float velocity_scale = (float)MAX_VEL*scale; pi->flags |= PF_REDUCED_DAMP; update_reduced_damp_timestamp( pi, velocity_scale*pi->mass ); vm_vec_scale_add2( &pi->vel, direction_vec, velocity_scale ); vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient); // set so velocity will ramp starting from current speed // check that kick from shockwave is not too large if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) { // Get DaveA nprintf(("Physics", "speed reset in physics_apply_shock [speed: %f]\n", vm_vec_mag(&pi->vel))); vm_vec_normalize(&pi->vel); vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED); } }
float g3_draw_laser_htl(vec3d* p0, float width1, vec3d* p1, float width2, int r, int g, int b, uint tmap_flags) { width1 *= 0.5f; width2 *= 0.5f; vec3d uvec, fvec, rvec, center, reye; vm_vec_sub(&fvec, p0, p1); vm_vec_normalize_safe(&fvec); vm_vec_avg(¢er, p0, p1); //needed for the return value only vm_vec_sub(&reye, &Eye_position, ¢er); vm_vec_normalize(&reye); vm_vec_crossprod(&uvec, &fvec, &reye); vm_vec_normalize(&uvec); vm_vec_crossprod(&fvec, &uvec, &reye); vm_vec_normalize(&fvec); // if(vm_vec_mag_squared(&uvec)==0) uvec.xyz.y = 1.0f; //in case fvec is exactly equal to matrx.rvec, stick some arbitrary value in uvec //normalize new perpendicular vector // vm_vec_normalize(&uvec); //now recompute right vector, in case it wasn't entirely perpendiclar vm_vec_crossprod(&rvec, &uvec, &fvec); // Now have uvec, which is up vector and rvec which is the normal // of the face. int i; vec3d start, end; vm_vec_scale_add(&start, p0, &fvec, -width1); vm_vec_scale_add(&end, p1, &fvec, width2); vec3d vecs[4]; vertex pts[4]; vertex* ptlist[8] = { &pts[3], &pts[2], &pts[1], &pts[0], &pts[0], &pts[1], &pts[2], &pts[3] }; vm_vec_scale_add(&vecs[0], &start, &uvec, width1); vm_vec_scale_add(&vecs[1], &end, &uvec, width2); vm_vec_scale_add(&vecs[2], &end, &uvec, -width2); vm_vec_scale_add(&vecs[3], &start, &uvec, -width1); for (i = 0; i < 4; i++) { g3_transfer_vertex(&pts[i], &vecs[i]); } ptlist[0]->u = 0.0f; ptlist[0]->v = 0.0f; ptlist[1]->u = 1.0f; ptlist[1]->v = 0.0f; ptlist[2]->u = 1.0f; ptlist[2]->v = 1.0f; ptlist[3]->u = 0.0f; ptlist[3]->v = 1.0f; ptlist[0]->r = (ubyte)r; ptlist[0]->g = (ubyte)g; ptlist[0]->b = (ubyte)b; ptlist[0]->a = 255; ptlist[1]->r = (ubyte)r; ptlist[1]->g = (ubyte)g; ptlist[1]->b = (ubyte)b; ptlist[1]->a = 255; ptlist[2]->r = (ubyte)r; ptlist[2]->g = (ubyte)g; ptlist[2]->b = (ubyte)b; ptlist[2]->a = 255; ptlist[3]->r = (ubyte)r; ptlist[3]->g = (ubyte)g; ptlist[3]->b = (ubyte)b; ptlist[3]->a = 255; gr_tmapper(4, ptlist, tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); return center.xyz.z; }
float geometry_batcher::draw_laser(vec3d *p0, float width1, vec3d *p1, float width2, int r, int g, int b) { width1 *= 0.5f; width2 *= 0.5f; vec3d uvec, fvec, rvec, center, reye; vm_vec_sub( &fvec, p0, p1 ); vm_vec_normalize_safe( &fvec ); vm_vec_avg( ¢er, p0, p1 ); // needed for the return value only vm_vec_sub(&reye, &Eye_position, ¢er); vm_vec_normalize(&reye); // compute the up vector vm_vec_crossprod(&uvec, &fvec, &reye); vm_vec_normalize_safe(&uvec); // ... the forward vector vm_vec_crossprod(&fvec, &uvec, &reye); vm_vec_normalize_safe(&fvec); // now recompute right vector, in case it wasn't entirely perpendiclar vm_vec_crossprod(&rvec, &uvec, &fvec); // Now have uvec, which is up vector and rvec which is the normal // of the face. vec3d start, end; vm_vec_scale_add(&start, p0, &fvec, -width1); vm_vec_scale_add(&end, p1, &fvec, width2); vec3d vecs[4]; vertex *pts = &vert[n_to_render * 3]; vm_vec_scale_add( &vecs[0], &end, &uvec, width2 ); vm_vec_scale_add( &vecs[1], &start, &uvec, width1 ); vm_vec_scale_add( &vecs[2], &start, &uvec, -width1 ); vm_vec_scale_add( &vecs[3], &end, &uvec, -width2 ); g3_transfer_vertex( &pts[0], &vecs[0] ); g3_transfer_vertex( &pts[1], &vecs[1] ); g3_transfer_vertex( &pts[2], &vecs[2] ); g3_transfer_vertex( &pts[3], &vecs[0] ); g3_transfer_vertex( &pts[4], &vecs[2] ); g3_transfer_vertex( &pts[5], &vecs[3] ); pts[0].texture_position.u = 1.0f; pts[0].texture_position.v = 0.0f; pts[1].texture_position.u = 0.0f; pts[1].texture_position.v = 0.0f; pts[2].texture_position.u = 0.0f; pts[2].texture_position.v = 1.0f; pts[3].texture_position.u = 1.0f; pts[3].texture_position.v = 0.0f; pts[4].texture_position.u = 0.0f; pts[4].texture_position.v = 1.0f; pts[5].texture_position.u = 1.0f; pts[5].texture_position.v = 1.0f; pts[0].r = (ubyte)r; pts[0].g = (ubyte)g; pts[0].b = (ubyte)b; pts[0].a = 255; pts[1].r = (ubyte)r; pts[1].g = (ubyte)g; pts[1].b = (ubyte)b; pts[1].a = 255; pts[2].r = (ubyte)r; pts[2].g = (ubyte)g; pts[2].b = (ubyte)b; pts[2].a = 255; pts[3].r = (ubyte)r; pts[3].g = (ubyte)g; pts[3].b = (ubyte)b; pts[3].a = 255; pts[4].r = (ubyte)r; pts[4].g = (ubyte)g; pts[4].b = (ubyte)b; pts[4].a = 255; pts[5].r = (ubyte)r; pts[5].g = (ubyte)g; pts[5].b = (ubyte)b; pts[5].a = 255; n_to_render += 2; use_radius = false; return center.xyz.z; }
void geometry_batcher::draw_beam(vec3d *start, vec3d *end, float width, float intensity, float offset) { vec3d p[4]; vertex *P = &vert[n_to_render * 3]; float *R = &radius_list[n_to_render * 3]; vec3d fvec, uvecs, uvece, evec; vm_vec_sub(&fvec, start, end); vm_vec_normalize_safe(&fvec); vm_vec_sub(&evec, &View_position, start); vm_vec_normalize_safe(&evec); vm_vec_crossprod(&uvecs, &fvec, &evec); vm_vec_normalize_safe(&uvecs); vm_vec_sub(&evec, &View_position, end); vm_vec_normalize_safe(&evec); vm_vec_crossprod(&uvece, &fvec, &evec); vm_vec_normalize_safe(&uvece); vm_vec_scale_add(&p[0], start, &uvecs, width); vm_vec_scale_add(&p[1], end, &uvece, width); vm_vec_scale_add(&p[2], end, &uvece, -width); vm_vec_scale_add(&p[3], start, &uvecs, -width); //move all the data from the vecs into the verts //tri 1 g3_transfer_vertex(&P[0], &p[3]); g3_transfer_vertex(&P[1], &p[2]); g3_transfer_vertex(&P[2], &p[1]); //tri 2 g3_transfer_vertex(&P[3], &p[3]); g3_transfer_vertex(&P[4], &p[1]); g3_transfer_vertex(&P[5], &p[0]); //set up the UV coords //tri 1 P[0].texture_position.u = 0.0f; P[0].texture_position.v = 0.0f; P[1].texture_position.u = 1.0f; P[1].texture_position.v = 0.0f; P[2].texture_position.u = 1.0f; P[2].texture_position.v = 1.0f; //tri 2 P[3].texture_position.u = 0.0f; P[3].texture_position.v = 0.0f; P[4].texture_position.u = 1.0f; P[4].texture_position.v = 1.0f; P[5].texture_position.u = 0.0f; P[5].texture_position.v = 1.0f; ubyte _color = (ubyte)(255.0f * intensity); for(int i = 0; i < 6; i++) { P[i].r = P[i].g = P[i].b = P[i].a = _color; if(offset > 0.0f) { R[i] = offset; } else { R[i] = width; } } n_to_render += 2; use_radius = true; }
void geometry_batcher::draw_bitmap(vertex *pnt, float rad, float angle, float depth) { float radius = rad; rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and height rad extern float Physics_viewer_bank; angle -= Physics_viewer_bank; if ( angle < 0.0f ) angle += PI2; else if ( angle > PI2 ) angle -= PI2; vec3d PNT(pnt->world); vec3d p[4]; vec3d fvec, rvec, uvec; vertex *P = &vert[n_to_render * 3]; float *R = &radius_list[n_to_render * 3]; vm_vec_sub(&fvec, &View_position, &PNT); vm_vec_normalize_safe(&fvec); vm_rot_point_around_line(&uvec, &View_matrix.vec.uvec, angle, &vmd_zero_vector, &View_matrix.vec.fvec); vm_vec_crossprod(&rvec, &View_matrix.vec.fvec, &uvec); vm_vec_normalize_safe(&rvec); vm_vec_crossprod(&uvec, &View_matrix.vec.fvec, &rvec); vm_vec_scale_add(&PNT, &PNT, &fvec, depth); vm_vec_scale_add(&p[0], &PNT, &rvec, rad); vm_vec_scale_add(&p[2], &PNT, &rvec, -rad); vm_vec_scale_add(&p[1], &p[2], &uvec, rad); vm_vec_scale_add(&p[3], &p[0], &uvec, -rad); vm_vec_scale_add(&p[0], &p[0], &uvec, rad); vm_vec_scale_add(&p[2], &p[2], &uvec, -rad); //move all the data from the vecs into the verts //tri 1 g3_transfer_vertex(&P[5], &p[3]); g3_transfer_vertex(&P[4], &p[2]); g3_transfer_vertex(&P[3], &p[1]); //tri 2 g3_transfer_vertex(&P[2], &p[3]); g3_transfer_vertex(&P[1], &p[1]); g3_transfer_vertex(&P[0], &p[0]); //tri 1 P[5].texture_position.u = 0.0f; P[5].texture_position.v = 0.0f; P[4].texture_position.u = 1.0f; P[4].texture_position.v = 0.0f; P[3].texture_position.u = 1.0f; P[3].texture_position.v = 1.0f; //tri 2 P[2].texture_position.u = 0.0f; P[2].texture_position.v = 0.0f; P[1].texture_position.u = 1.0f; P[1].texture_position.v = 1.0f; P[0].texture_position.u = 0.0f; P[0].texture_position.v = 1.0f; for (int i = 0; i < 6 ; i++) { P[i].r = pnt->r; P[i].g = pnt->g; P[i].b = pnt->b; P[i].a = pnt->a; R[i] = radius; } n_to_render += 2; }
/* 0----1 |\ | | \ | 3----2 */ void geometry_batcher::draw_bitmap(vertex *pnt, int orient, float rad, float depth) { float radius = rad; rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and height rad vec3d PNT(pnt->world); vec3d p[4]; vec3d fvec, rvec, uvec; vertex *P = &vert[n_to_render * 3]; float *R = &radius_list[n_to_render * 3]; // get the direction from the point to the eye vm_vec_sub(&fvec, &View_position, &PNT); vm_vec_normalize_safe(&fvec); // get an up vector in the general direction of what we want uvec = View_matrix.vec.uvec; // make a right vector from the f and up vector, this r vec is exactly what we want, so... vm_vec_crossprod(&rvec, &View_matrix.vec.fvec, &uvec); vm_vec_normalize_safe(&rvec); // fix the u vec with it vm_vec_crossprod(&uvec, &View_matrix.vec.fvec, &rvec); // move the center of the sprite based on the depth parameter if ( depth != 0.0f ) vm_vec_scale_add(&PNT, &PNT, &fvec, depth); // move one of the verts to the left vm_vec_scale_add(&p[0], &PNT, &rvec, rad); // and one to the right vm_vec_scale_add(&p[2], &PNT, &rvec, -rad); // now move all oof the verts to were they need to be vm_vec_scale_add(&p[1], &p[2], &uvec, rad); vm_vec_scale_add(&p[3], &p[0], &uvec, -rad); vm_vec_scale_add(&p[0], &p[0], &uvec, rad); vm_vec_scale_add(&p[2], &p[2], &uvec, -rad); //move all the data from the vecs into the verts //tri 1 g3_transfer_vertex(&P[5], &p[3]); g3_transfer_vertex(&P[4], &p[2]); g3_transfer_vertex(&P[3], &p[1]); //tri 2 g3_transfer_vertex(&P[2], &p[3]); g3_transfer_vertex(&P[1], &p[1]); g3_transfer_vertex(&P[0], &p[0]); // set up the UV coords if ( orient & 1 ) { // tri 1 P[5].texture_position.u = 1.0f; P[4].texture_position.u = 0.0f; P[3].texture_position.u = 0.0f; // tri 2 P[2].texture_position.u = 1.0f; P[1].texture_position.u = 0.0f; P[0].texture_position.u = 1.0f; } else { // tri 1 P[5].texture_position.u = 0.0f; P[4].texture_position.u = 1.0f; P[3].texture_position.u = 1.0f; // tri 2 P[2].texture_position.u = 0.0f; P[1].texture_position.u = 1.0f; P[0].texture_position.u = 0.0f; } if ( orient & 2 ) { // tri 1 P[5].texture_position.v = 1.0f; P[4].texture_position.v = 1.0f; P[3].texture_position.v = 0.0f; // tri 2 P[2].texture_position.v = 1.0f; P[1].texture_position.v = 0.0f; P[0].texture_position.v = 0.0f; } else { // tri 1 P[5].texture_position.v = 0.0f; P[4].texture_position.v = 0.0f; P[3].texture_position.v = 1.0f; // tri 2 P[2].texture_position.v = 0.0f; P[1].texture_position.v = 1.0f; P[0].texture_position.v = 1.0f; } for (int i = 0; i < 6 ; i++) { P[i].r = pnt->r; P[i].g = pnt->g; P[i].b = pnt->b; P[i].a = pnt->a; R[i] = radius; } n_to_render += 2; }
float g3_draw_laser_htl(vec3d *p0,float width1,vec3d *p1,float width2, int r, int g, int b, uint tmap_flags) { width1 *= 0.5f; width2 *= 0.5f; vec3d uvec, fvec, rvec, center, reye, rfvec; vm_vec_sub( &fvec, p0, p1 ); vm_vec_normalize_safe( &fvec ); vm_vec_copy_scale(&rfvec, &fvec, -1.0f); vm_vec_avg( ¢er, p0, p1 ); //needed for the return value only vm_vec_sub(&reye, &Eye_position, ¢er); vm_vec_normalize(&reye); // code intended to prevent possible null vector normalize issue - start if (vm_test_parallel(&reye,&fvec)){ fvec.xyz.x = -reye.xyz.z; fvec.xyz.y = 0.0f; fvec.xyz.z = -reye.xyz.x; } if (vm_test_parallel(&reye,&rfvec)){ fvec.xyz.x = reye.xyz.z; fvec.xyz.y = 0.0f; fvec.xyz.z = reye.xyz.x; } // code intended to prevent possible null vector normalize issue - end vm_vec_crossprod(&uvec,&fvec,&reye); vm_vec_normalize(&uvec); vm_vec_crossprod(&fvec,&uvec,&reye); vm_vec_normalize(&fvec); //now recompute right vector, in case it wasn't entirely perpendiclar vm_vec_crossprod(&rvec,&uvec,&fvec); // Now have uvec, which is up vector and rvec which is the normal // of the face. int i; vec3d start, end; vm_vec_scale_add(&start, p0, &fvec, -width1); vm_vec_scale_add(&end, p1, &fvec, width2); vec3d vecs[4]; vertex pts[4]; vertex *ptlist[8] = { &pts[3], &pts[2], &pts[1], &pts[0], &pts[0], &pts[1], &pts[2], &pts[3]}; vm_vec_scale_add( &vecs[0], &start, &uvec, width1 ); vm_vec_scale_add( &vecs[1], &end, &uvec, width2 ); vm_vec_scale_add( &vecs[2], &end, &uvec, -width2 ); vm_vec_scale_add( &vecs[3], &start, &uvec, -width1 ); for (i=0; i<4; i++ ) { g3_transfer_vertex( &pts[i], &vecs[i] ); } ptlist[0]->texture_position.u = 0.0f; ptlist[0]->texture_position.v = 0.0f; ptlist[1]->texture_position.u = 1.0f; ptlist[1]->texture_position.v = 0.0f; ptlist[2]->texture_position.u = 1.0f; ptlist[2]->texture_position.v = 1.0f; ptlist[3]->texture_position.u = 0.0f; ptlist[3]->texture_position.v = 1.0f; ptlist[0]->r = (ubyte)r; ptlist[0]->g = (ubyte)g; ptlist[0]->b = (ubyte)b; ptlist[0]->a = 255; ptlist[1]->r = (ubyte)r; ptlist[1]->g = (ubyte)g; ptlist[1]->b = (ubyte)b; ptlist[1]->a = 255; ptlist[2]->r = (ubyte)r; ptlist[2]->g = (ubyte)g; ptlist[2]->b = (ubyte)b; ptlist[2]->a = 255; ptlist[3]->r = (ubyte)r; ptlist[3]->g = (ubyte)g; ptlist[3]->b = (ubyte)b; ptlist[3]->a = 255; gr_tmapper(4, ptlist,tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); return center.xyz.z; }