void HudGaugeRadarOrb::drawContact(vec3d *pnt, int rad) { vertex verts[2]; vec3d p; p=*pnt; vm_vec_normalize(&p); g3_rotate_vertex(&verts[0], &p); g3_project_vertex(&verts[0]); g3_rotate_vertex(&verts[1], pnt); g3_project_vertex(&verts[1]); float size = fl_sqrt(vm_vec_dist(&Orb_eye_position, pnt) * 8.0f); if (size < i2fl(rad)) size = i2fl(rad); if (rad == Radar_blip_radius_target) { g3_draw_sphere(&verts[1],size/100.0f); } else { g3_draw_sphere(&verts[1],size/300.0f); } g3_draw_line(&verts[0],&verts[1]); }
// Rotate and project points and draw a line. void rpd_line(vector *v0, vector *v1) { vertex tv0, tv1; g3_rotate_vertex(&tv0, v0); g3_rotate_vertex(&tv1, v1); g3_draw_line(&tv0, &tv1); }
// render a bezier void herm_spline::herm_render(int divs, color *clc) { int idx; int s_idx; float inc = 1.0f / (float)divs; vertex a, b, c; vec3d pt, d_pt; // draw in red gr_set_color_fast(clc); // render each section for(idx=0; idx<num_pts-1; idx++){ // render this piece herm_get_point(&pt, 0.0f, idx); g3_rotate_vertex(&a, &pt); // draw the deriv herm_get_deriv(&d_pt, 0.0f, idx); vm_vec_add2(&d_pt, &pt); g3_rotate_vertex(&c, &d_pt); g3_draw_line(&a, &c); for(s_idx=1; s_idx<divs * 2; s_idx++){ // second point herm_get_point(&pt, (float)s_idx * inc, idx); // 2nd point on the line g3_rotate_vertex(&b, &pt); // draw the line g3_draw_line(&a, &b); // draw the deriv line herm_get_deriv(&d_pt, (float)s_idx * inc, idx); vm_vec_add2(&d_pt, &pt); g3_rotate_vertex(&c, &d_pt); g3_draw_line(&b, &c); // store b a = b; } } // draw the control points gr_set_color_fast(&Color_bright_green); for(idx=0; idx<num_pts; idx++){ g3_draw_sphere_ez(&pts[idx], 0.75f); } }
/** * Render one triangle of a shield hit effect on one ship. * Each frame, the triangle needs to be rotated into global coords. * * @param trip pointer to triangle in global array * @param orient orientation of object shield is associated with * @param pos center point of object * @param r Red colour * @param g Green colour * @param b Blue colour */ void render_shield_triangle(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b) { int j; vec3d pnt; vertex *verts[3]; vertex points[3]; if (trip->trinum == -1) return; // Means this is a quad, must have switched detail_level. for (j=0; j<3; j++ ) { // Rotate point into world coordinates vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient); vm_vec_add2(&pnt, pos); // Pnt is now the x,y,z world coordinates of this vert. // For this example, I am just drawing a sphere at that point. if (!Cmdline_nohtl) g3_transfer_vertex(&points[j],&pnt); else g3_rotate_vertex(&points[j], &pnt); points[j].texture_position.u = trip->verts[j].u; points[j].texture_position.v = trip->verts[j].v; Assert((trip->verts[j].u >= 0.0f) && (trip->verts[j].u <= UV_MAX)); Assert((trip->verts[j].v >= 0.0f) && (trip->verts[j].v <= UV_MAX)); verts[j] = &points[j]; } verts[0]->r = r; verts[0]->g = g; verts[0]->b = b; verts[1]->r = r; verts[1]->g = g; verts[1]->b = b; verts[2]->r = r; verts[2]->g = g; verts[2]->b = b; vec3d norm; Poly_count++; vm_vec_perp(&norm,&verts[0]->world,&verts[1]->world,&verts[2]->world); int flags=TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD; if (!Cmdline_nohtl) flags |= TMAP_HTL_3D_UNLIT; if ( vm_vec_dot(&norm,&verts[1]->world ) >= 0.0 ) { vertex *vertlist[3]; vertlist[0] = verts[2]; vertlist[1] = verts[1]; vertlist[2] = verts[0]; g3_draw_poly( 3, vertlist, flags); } else { g3_draw_poly( 3, verts, flags); } }
// render a bezier void bez_spline::bez_render(int divs, color *c) { float inc; int idx; vertex a, b; vec3d pt; // bleh if(divs <= 0){ return; } inc = 1.0f / (float)divs; // draw in red gr_set_color_fast(c); // draw that many divisions bez_get_point(&pt, 0.0f); g3_rotate_vertex(&a, &pt); for(idx=1; idx<=divs; idx++){ // second point bez_get_point(&pt, (float)idx * inc); g3_rotate_vertex(&b, &pt); // draw the line g3_draw_line(&a, &b); // store b a = b; } // draw the control points gr_set_color_fast(&Color_bright_green); for(idx=0; idx<num_pts; idx++){ g3_draw_sphere_ez(&pts[idx], 0.75f); } }
void render_low_detail_shield_bitmap(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b) { int j; vec3d pnt; vertex verts[4]; for (j=0; j<4; j++ ) { // Rotate point into world coordinates vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient); vm_vec_add2(&pnt, pos); // Pnt is now the x,y,z world coordinates of this vert. if(!Cmdline_nohtl) g3_transfer_vertex(&verts[j], &pnt); else g3_rotate_vertex(&verts[j], &pnt); verts[j].texture_position.u = trip->verts[j].u; verts[j].texture_position.v = trip->verts[j].v; } verts[0].r = r; verts[0].g = g; verts[0].b = b; verts[1].r = r; verts[1].g = g; verts[1].b = b; verts[2].r = r; verts[2].g = g; verts[2].b = b; verts[3].r = r; verts[3].g = g; verts[3].b = b; vec3d norm; vm_vec_perp(&norm, &trip->verts[0].pos, &trip->verts[1].pos, &trip->verts[2].pos); vertex *vertlist[4]; if ( vm_vec_dot(&norm, &trip->verts[1].pos ) < 0.0 ) { vertlist[0] = &verts[3]; vertlist[1] = &verts[2]; vertlist[2] = &verts[1]; vertlist[3] = &verts[0]; g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_HTL_3D_UNLIT); } else { vertlist[0] = &verts[0]; vertlist[1] = &verts[1]; vertlist[2] = &verts[2]; vertlist[3] = &verts[3]; g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_HTL_3D_UNLIT); } }
void HudGaugeRadarOrb::drawOutlines() { int i; vertex center; // vertex extents[6]; vertex proj_orb_lines_xy[NUM_ORB_RING_SLICES]; vertex proj_orb_lines_xz[NUM_ORB_RING_SLICES]; vertex proj_orb_lines_yz[NUM_ORB_RING_SLICES]; g3_start_instance_matrix(&vmd_zero_vector, &view_perturb, false); g3_start_instance_matrix(&vmd_zero_vector, &Player_obj->orient, false); g3_rotate_vertex(¢er, &vmd_zero_vector); g3_rotate_vertex(&proj_orb_lines_xy[0], &orb_ring_xy[0]); g3_rotate_vertex(&proj_orb_lines_yz[0], &orb_ring_yz[0]); g3_rotate_vertex(&proj_orb_lines_xz[0], &orb_ring_xz[0]); g3_project_vertex(¢er); gr_set_color(255,255,255); g3_draw_sphere(¢er, .05f); g3_project_vertex(&proj_orb_lines_xy[0]); g3_project_vertex(&proj_orb_lines_yz[0]); g3_project_vertex(&proj_orb_lines_xz[0]); for (i=1; i < NUM_ORB_RING_SLICES; i++) { g3_rotate_vertex(&proj_orb_lines_xy[i], &orb_ring_xy[i]); g3_rotate_vertex(&proj_orb_lines_yz[i], &orb_ring_yz[i]); g3_rotate_vertex(&proj_orb_lines_xz[i], &orb_ring_xz[i]); g3_project_vertex(&proj_orb_lines_xy[i]); g3_project_vertex(&proj_orb_lines_yz[i]); g3_project_vertex(&proj_orb_lines_xz[i]); gr_set_color(192,96,32); g3_draw_sphere(&proj_orb_lines_xy[i-1], .01f); g3_draw_sphere(&proj_orb_lines_xz[i-1], .01f); g3_draw_line(&proj_orb_lines_xy[i-1],&proj_orb_lines_xy[i]); g3_draw_line(&proj_orb_lines_xz[i-1],&proj_orb_lines_xz[i]); gr_set_color(112,16,192); g3_draw_sphere(&proj_orb_lines_yz[i-1], .01f); g3_draw_line(&proj_orb_lines_yz[i-1],&proj_orb_lines_yz[i]); } g3_done_instance(false); }
// ------------------------------------------------------------------------------------ // shockwave_render() // // Draw the shockwave identified by handle // // input: objp => pointer to shockwave object // void shockwave_render(object *objp) { shockwave *sw; shockwave_info *si; vertex p; Assert(objp->type == OBJ_SHOCKWAVE); Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES); sw = &Shockwaves[objp->instance]; si = &Shockwave_info[sw->shockwave_info_index]; if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){ return; } if ( (sw->current_bitmap < 0) && (sw->model_id < 0) ) return; // turn off fogging if(The_mission.flags & MISSION_FLAG_FULLNEB){ gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0); } if (sw->model_id > -1) { float model_Interp_scale_xyz = sw->radius / 50.0f; model_set_warp_globals( model_Interp_scale_xyz, model_Interp_scale_xyz, model_Interp_scale_xyz, -1, 1.0f - (sw->radius/sw->outer_radius) ); float dist = vm_vec_dist_quick( &sw->pos, &Eye_position ); model_set_detail_level((int)(dist / (sw->radius * 10.0f))); model_render( sw->model_id, &Objects[sw->objnum].orient, &sw->pos, MR_NO_LIGHTING | MR_NO_FOGGING | MR_NORMAL | MR_CENTER_ALPHA | MR_NO_CULL, sw->objnum); model_set_warp_globals(); }else{ if (!Cmdline_nohtl) { g3_transfer_vertex(&p, &sw->pos); } else { g3_rotate_vertex(&p, &sw->pos); } gr_set_bitmap(sw->current_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.3f ); g3_draw_rotated_bitmap(&p, fl_radian(sw->rot_angles.p), sw->radius, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT); } }
// Decide which point lock should be homing on void hud_lock_determine_lock_point(vector *lock_world_pos_out) { vector lock_world_pos; vertex lock_point; object *target_objp; Assert(Player_ai->target_objnum >= 0); target_objp = &Objects[Player_ai->target_objnum]; Player->current_target_sx = -1; Player->current_target_sx = -1; // If subsystem is targeted, we must try to lock on that if ( Player_ai->targeted_subsys ) { hud_lock_update_lock_pos(target_objp, &lock_world_pos); Player->locking_on_center=0; Player->locking_subsys=NULL; Player->locking_subsys_parent=-1; } else { // See if we already have a successful locked point if ( hud_lock_has_homing_point() ) { hud_lock_update_lock_pos(target_objp, &lock_world_pos); } else { hud_lock_get_new_lock_pos(target_objp, &lock_world_pos); } } *lock_world_pos_out=lock_world_pos; g3_rotate_vertex(&lock_point,&lock_world_pos); g3_project_vertex(&lock_point); if (!(lock_point.flags & PF_OVERFLOW)) { // make sure point projected Player->current_target_sx = (int)lock_point.sx; Player->current_target_sy = (int)lock_point.sy; } }
void warpin_render(object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d) { vec3d center; vec3d vecs[5]; vertex verts[5]; int saved_gr_zbuffering = gr_zbuffer_get(); gr_zbuffer_set(GR_ZBUFF_READ); vm_vec_scale_add( ¢er, pos, &orient->vec.fvec, -(max_radius/2.5f)/3.0f ); if (Warp_glow_bitmap >= 0) { float r = radius; bool render_it = true; #define OUT_PERCENT1 0.80f #define OUT_PERCENT2 0.90f #define IN_PERCENT1 0.10f #define IN_PERCENT2 0.20f if (Cmdline_warp_flash) { if ( (life_percent >= IN_PERCENT1) && (life_percent < IN_PERCENT2) ) { r *= (life_percent - IN_PERCENT1) / (IN_PERCENT2 - IN_PERCENT1); //render_it = true; } else if ( (life_percent >= OUT_PERCENT1) && (life_percent < OUT_PERCENT2) ) { r *= (OUT_PERCENT2 - life_percent) / (OUT_PERCENT2 - OUT_PERCENT1); //render_it = true; } } if (render_it) { // Add in noise int noise_frame = fl2i(Missiontime/15.0f) % NOISE_NUM_FRAMES; r *= (0.40f + Noise[noise_frame] * 0.30f); // Bobboau's warp thingie, toggled by cmdline if (Cmdline_warp_flash) { r += powf((2.0f * life_percent) - 1.0f, 24.0f) * max_radius * 1.5f; } vecs[4] = center; verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f; if (Cmdline_nohtl) { g3_rotate_vertex( &verts[4], &vecs[4] ); } else { g3_transfer_vertex( &verts[4], &vecs[4] ); } float alpha = (The_mission.flags & MISSION_FLAG_FULLNEB) ? (1.0f - neb2_get_fog_intensity(obj)) : 1.0f; gr_set_bitmap( Warp_glow_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha ); g3_draw_bitmap( &verts[4], 0, r, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT ); } } if ( (Warp_model >= 0) && (warp_3d || Cmdline_3dwarp) ) { float scale = radius / 25.0f; model_set_warp_globals(scale, scale, scale, texture_bitmap_num, (radius/max_radius) ); float dist = vm_vec_dist_quick( pos, &Eye_position ); model_set_detail_level((int)(dist / (radius * 10.0f))); model_render( Warp_model, orient, pos, MR_LOCK_DETAIL | MR_NO_LIGHTING | MR_NORMAL | MR_NO_FOGGING | MR_NO_CULL ); model_set_warp_globals(); } else { float Grid_depth = radius/2.5f; gr_set_bitmap( texture_bitmap_num, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f ); vm_vec_scale_add( &vecs[0], ¢er, &orient->vec.uvec, radius ); vm_vec_scale_add2( &vecs[0], &orient->vec.rvec, -radius ); vm_vec_scale_add2( &vecs[0], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[1], ¢er, &orient->vec.uvec, radius ); vm_vec_scale_add2( &vecs[1], &orient->vec.rvec, radius ); vm_vec_scale_add2( &vecs[1], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[2], ¢er, &orient->vec.uvec, -radius ); vm_vec_scale_add2( &vecs[2], &orient->vec.rvec, radius ); vm_vec_scale_add2( &vecs[2], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[3], ¢er, &orient->vec.uvec, -radius ); vm_vec_scale_add2( &vecs[3], &orient->vec.rvec, -radius ); vm_vec_scale_add2( &vecs[3], &orient->vec.fvec, Grid_depth ); // vm_vec_scale_add( &vecs[4], ¢er, &orient->vec.fvec, -Grid_depth ); vecs[4] = center; verts[0].texture_position.u = 0.01f; verts[0].texture_position.v = 0.01f; verts[1].texture_position.u = 0.99f; verts[1].texture_position.v = 0.01f; verts[2].texture_position.u = 0.99f; verts[2].texture_position.v = 0.99f; verts[3].texture_position.u = 0.01f; verts[3].texture_position.v = 0.99f; verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f; if (Cmdline_nohtl) { g3_rotate_vertex( &verts[0], &vecs[0] ); g3_rotate_vertex( &verts[1], &vecs[1] ); g3_rotate_vertex( &verts[2], &vecs[2] ); g3_rotate_vertex( &verts[3], &vecs[3] ); g3_rotate_vertex( &verts[4], &vecs[4] ); } else { g3_transfer_vertex( &verts[0], &vecs[0] ); g3_transfer_vertex( &verts[1], &vecs[1] ); g3_transfer_vertex( &verts[2], &vecs[2] ); g3_transfer_vertex( &verts[3], &vecs[3] ); g3_transfer_vertex( &verts[4], &vecs[4] ); } int cull = gr_set_cull(0); // fixes rendering problem in D3D - taylor draw_face( &verts[0], &verts[4], &verts[1] ); draw_face( &verts[1], &verts[4], &verts[2] ); draw_face( &verts[4], &verts[3], &verts[2] ); draw_face( &verts[0], &verts[3], &verts[4] ); gr_set_cull(cull); } if (Warp_ball_bitmap > -1 && Cmdline_warp_flash == 1) { flash_ball warp_ball(20, .1f,.25f, &vmd_z_vector, &vmd_zero_vector, 4.0f, 0.5f); float adg = (2.0f * life_percent) - 1.0f; float pct = (powf(adg, 4.0f) - powf(adg, 128.0f)) * 4.0f; if (pct > 0.00001f) { g3_start_instance_matrix(pos, orient, true); gr_set_bitmap(Warp_ball_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.9999f); warp_ball.render(max_radius * pct * 0.5f, adg * adg, adg * adg * 6.0f); g3_done_instance(true); } } gr_zbuffer_set( saved_gr_zbuffering ); }
void shockwave_render(object *objp, draw_list *scene) { shockwave *sw; vertex p; Assert(objp->type == OBJ_SHOCKWAVE); Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES); sw = &Shockwaves[objp->instance]; if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){ return; } if ( (sw->current_bitmap < 0) && (sw->model_id < 0) ) return; if (sw->model_id > -1) { vec3d scale; scale.xyz.x = scale.xyz.y = scale.xyz.z = sw->radius / 50.0f; model_render_params render_info; render_info.set_warp_params(-1, 1.0f - (sw->radius/sw->outer_radius), scale); float dist = vm_vec_dist_quick( &sw->pos, &Eye_position ); render_info.set_detail_level_lock((int)(dist / (sw->radius * 10.0f))); render_info.set_flags(MR_NO_LIGHTING | MR_NO_FOGGING | MR_NORMAL | MR_CENTER_ALPHA | MR_NO_CULL | MR_NO_BATCH); render_info.set_object_number(sw->objnum); model_render_queue( &render_info, scene, sw->model_id, &Objects[sw->objnum].orient, &sw->pos); if ( Cmdline_fb_explosions ) { g3_transfer_vertex(&p, &sw->pos); distortion_add_bitmap_rotated( Shockwave_info[1].bitmap_id+shockwave_get_framenum(objp->instance, 94), TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } } else { if (!Cmdline_nohtl) { g3_transfer_vertex(&p, &sw->pos); } else { g3_rotate_vertex(&p, &sw->pos); } if ( Cmdline_fb_explosions ) { distortion_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } batch_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD, &p, fl_radians(sw->rot_angles.p), sw->radius ); } }
/** * Draw the shockwave identified by handle * * @param objp pointer to shockwave object */ void shockwave_render_DEPRECATED(object *objp) { shockwave *sw; vertex p; Assert(objp->type == OBJ_SHOCKWAVE); Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES); memset(&p, 0, sizeof(p)); sw = &Shockwaves[objp->instance]; if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){ return; } if ( (sw->current_bitmap < 0) && (sw->model_id < 0) ) return; // turn off fogging if(The_mission.flags & MISSION_FLAG_FULLNEB){ gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0); } if (sw->model_id > -1) { float model_Interp_scale_xyz = sw->radius / 50.0f; model_set_warp_globals( model_Interp_scale_xyz, model_Interp_scale_xyz, model_Interp_scale_xyz, -1, 1.0f - (sw->radius/sw->outer_radius) ); float dist = vm_vec_dist_quick( &sw->pos, &Eye_position ); model_set_detail_level((int)(dist / (sw->radius * 10.0f))); model_render_DEPRECATED( sw->model_id, &Objects[sw->objnum].orient, &sw->pos, MR_DEPRECATED_NO_LIGHTING | MR_DEPRECATED_NO_FOGGING | MR_DEPRECATED_NORMAL | MR_DEPRECATED_CENTER_ALPHA | MR_DEPRECATED_NO_CULL, sw->objnum); model_set_warp_globals(); if(Cmdline_fb_explosions) { g3_transfer_vertex(&p, &sw->pos); distortion_add_bitmap_rotated( Shockwave_info[1].bitmap_id+shockwave_get_framenum(objp->instance, 94), TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } }else{ if (!Cmdline_nohtl) { g3_transfer_vertex(&p, &sw->pos); } else { g3_rotate_vertex(&p, &sw->pos); } if(Cmdline_fb_explosions) { distortion_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } batch_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD, &p, fl_radians(sw->rot_angles.p), sw->radius ); } }
// This assumes you have already set a color with gr_set_color or gr_set_color_fast // and a bitmap with gr_set_bitmap. If it is very far away, it draws the laser // as flat-shaded using current color, else textured using current texture. // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels. float g3_draw_laser(vec3d *headp, float head_width, vec3d *tailp, float tail_width, uint tmap_flags, float max_len ) { if (!Lasers) { return 0.0f; } if ( !Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT) ) { return g3_draw_laser_htl(headp, head_width, tailp, tail_width, 255,255,255, tmap_flags | TMAP_HTL_3D_UNLIT); } float headx, heady, headr, tailx, taily, tailr; vertex pt1, pt2; float depth; Assert( G3_count == 1 ); g3_rotate_vertex(&pt1,headp); g3_project_vertex(&pt1); if (pt1.flags & PF_OVERFLOW) return 0.0f; g3_rotate_vertex(&pt2,tailp); g3_project_vertex(&pt2); if (pt2.flags & PF_OVERFLOW) return 0.0f; if ( (pt1.codes & pt2.codes) != 0 ) { // Both off the same side return 0.0f; } headx = pt1.screen.xyw.x; heady = pt1.screen.xyw.y; headr = (head_width*Matrix_scale.xyz.x*Canv_w2*pt1.screen.xyw.w); tailx = pt2.screen.xyw.x; taily = pt2.screen.xyw.y; tailr = (tail_width*Matrix_scale.xyz.x*Canv_w2*pt2.screen.xyw.w); float len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) ); // Cap the length if needed. if ( (max_len > 1.0f) && (len_2d > max_len) ) { float ratio = max_len / len_2d; tailx = headx + ( tailx - headx ) * ratio; taily = heady + ( taily - heady ) * ratio; tailr = headr + ( tailr - headr ) * ratio; len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) ); } depth = (pt1.world.xyz.z+pt2.world.xyz.z)*0.5f; float max_r = headr; float a; if ( tailr > max_r ) max_r = tailr; if ( max_r < 1.0f ) max_r = 1.0f; float mx, my, w, h1,h2; if ( len_2d < max_r ) { h1 = headr + (max_r-len_2d); if ( h1 > max_r ) h1 = max_r; h2 = tailr + (max_r-len_2d); if ( h2 > max_r ) h2 = max_r; len_2d = max_r; if ( fl_abs(tailx - headx) > 0.01f ) { a = (float)atan2( taily-heady, tailx-headx ); } else { a = 0.0f; } w = len_2d; } else { a = atan2_safe( taily-heady, tailx-headx ); w = len_2d; h1 = headr; h2 = tailr; } mx = (tailx+headx)/2.0f; my = (taily+heady)/2.0f; // Draw box with width 'w' and height 'h' at angle 'a' from horizontal // centered around mx, my if ( h1 < 1.0f ) h1 = 1.0f; if ( h2 < 1.0f ) h2 = 1.0f; float sa, ca; sa = (float)sin(a); ca = (float)cos(a); vertex v[4]; vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] }; memset(v,0,sizeof(vertex)*4); if ( depth < 0.0f ) depth = 0.0f; v[0].screen.xyw.x = (-w/2.0f)*ca + (-h1/2.0f)*sa + mx; v[0].screen.xyw.y = (-w/2.0f)*sa - (-h1/2.0f)*ca + my; v[0].world.xyz.z = pt1.world.xyz.z; v[0].screen.xyw.w = pt1.screen.xyw.w; v[0].texture_position.u = 0.0f; v[0].texture_position.v = 0.0f; v[0].b = 191; v[1].screen.xyw.x = (w/2.0f)*ca + (-h2/2.0f)*sa + mx; v[1].screen.xyw.y = (w/2.0f)*sa - (-h2/2.0f)*ca + my; v[1].world.xyz.z = pt2.world.xyz.z; v[1].screen.xyw.w = pt2.screen.xyw.w; v[1].texture_position.u = 1.0f; v[1].texture_position.v = 0.0f; v[1].b = 191; v[2].screen.xyw.x = (w/2.0f)*ca + (h2/2.0f)*sa + mx; v[2].screen.xyw.y = (w/2.0f)*sa - (h2/2.0f)*ca + my; v[2].world.xyz.z = pt2.world.xyz.z; v[2].screen.xyw.w = pt2.screen.xyw.w; v[2].texture_position.u = 1.0f; v[2].texture_position.v = 1.0f; v[2].b = 191; v[3].screen.xyw.x = (-w/2.0f)*ca + (h1/2.0f)*sa + mx; v[3].screen.xyw.y = (-w/2.0f)*sa - (h1/2.0f)*ca + my; v[3].world.xyz.z = pt1.world.xyz.z; v[3].screen.xyw.w = pt1.screen.xyw.w; v[3].texture_position.u = 0.0f; v[3].texture_position.v = 1.0f; v[3].b = 191; gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_CORRECT); return depth; }
// Draw a laser shaped 3d looking thing using vertex coloring (useful for things like colored laser glows) // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels float g3_draw_laser_rgb(vec3d* headp, float head_width, vec3d* tailp, float tail_width, int r, int g, int b, uint tmap_flags, float max_len) { if (!Lasers) { return 0.0f; } if ((!Cmdline_nohtl) && tmap_flags & TMAP_HTL_3D_UNLIT ) { // &&(gr_screen.mode==GR_OPENGL)) { return g3_draw_laser_htl(headp, head_width, tailp, tail_width, r, g, b, tmap_flags | TMAP_HTL_3D_UNLIT); } float headx, heady, headr, tailx, taily, tailr; vertex pt1, pt2; float depth; int head_on = 0; Assert(G3_count == 1); g3_rotate_vertex(&pt1, headp); g3_project_vertex(&pt1); if (pt1.flags & PF_OVERFLOW) return 0.0f; g3_rotate_vertex(&pt2, tailp); g3_project_vertex(&pt2); if (pt2.flags & PF_OVERFLOW) return 0.0f; if ((pt1.codes & pt2.codes) != 0) { // Both off the same side return 0.0f; } headx = pt1.sx; heady = pt1.sy; headr = (head_width * Matrix_scale.xyz.x * Canv_w2 * pt1.sw); tailx = pt2.sx; taily = pt2.sy; tailr = (tail_width * Matrix_scale.xyz.x * Canv_w2 * pt2.sw); float len_2d = fl_sqrt((tailx - headx) * (tailx - headx) + (taily - heady) * (taily - heady)); // Cap the length if needed. if ((max_len > 1.0f) && (len_2d > max_len)) { float ratio = max_len / len_2d; tailx = headx + (tailx - headx) * ratio; taily = heady + (taily - heady) * ratio; tailr = headr + (tailr - headr) * ratio; len_2d = fl_sqrt((tailx - headx) * (tailx - headx) + (taily - heady) * (taily - heady)); } depth = (pt1.z + pt2.z) * 0.5f; float max_r = headr; float a; if (tailr > max_r) max_r = tailr; if (max_r < 1.0f) max_r = 1.0f; float mx, my, w, h1, h2; if (len_2d < max_r) { h1 = headr + (max_r - len_2d); if (h1 > max_r) h1 = max_r; h2 = tailr + (max_r - len_2d); if (h2 > max_r) h2 = max_r; len_2d = max_r; if (fl_abs(tailx - headx) > 0.01f) { a = (float)atan2(taily - heady, tailx - headx); } else { a = 0.0f; } w = len_2d; head_on = 1; } else { a = atan2_safe(taily - heady, tailx - headx); w = len_2d; h1 = headr; h2 = tailr; head_on = 0; } mx = (tailx + headx) / 2.0f; my = (taily + heady) / 2.0f; // gr_set_color(255,0,0); // g3_draw_line( &pt1, &pt2 ); // gr_set_color( 255, 0, 0 ); // gr_pixel( fl2i(mx),fl2i(my) ); // Draw box with width 'w' and height 'h' at angle 'a' from horizontal // centered around mx, my if (h1 < 1.0f) h1 = 1.0f; if (h2 < 1.0f) h2 = 1.0f; float sa, ca; sa = (float)sin(a); ca = (float)cos(a); vertex v[4]; vertex* vertlist[4] = { &v[3], &v[2], &v[1], &v[0] }; memset(v, 0, sizeof(vertex) * 4); float sw; if (depth < 0.0f) depth = 0.0f; sw = 1.0f / depth; v[0].sx = (-w / 2.0f) * ca + (-h1 / 2.0f) * sa + mx; v[0].sy = (-w / 2.0f) * sa - (-h1 / 2.0f) * ca + my; v[0].z = pt1.z; v[0].sw = pt1.sw; v[0].u = 0.0f; v[0].v = 0.0f; v[0].r = (ubyte)r; v[0].g = (ubyte)g; v[0].b = (ubyte)b; v[0].a = 255; v[1].sx = (w / 2.0f) * ca + (-h2 / 2.0f) * sa + mx; v[1].sy = (w / 2.0f) * sa - (-h2 / 2.0f) * ca + my; v[1].z = pt2.z; v[1].sw = pt2.sw; v[1].u = 1.0f; v[1].v = 0.0f; v[1].r = (ubyte)r; v[1].g = (ubyte)g; v[1].b = (ubyte)b; v[1].a = 255; v[2].sx = (w / 2.0f) * ca + (h2 / 2.0f) * sa + mx; v[2].sy = (w / 2.0f) * sa - (h2 / 2.0f) * ca + my; v[2].z = pt2.z; v[2].sw = pt2.sw; v[2].u = 1.0f; v[2].v = 1.0f; v[2].r = (ubyte)r; v[2].g = (ubyte)g; v[2].b = (ubyte)b; v[2].a = 255; v[3].sx = (-w / 2.0f) * ca + (h1 / 2.0f) * sa + mx; v[3].sy = (-w / 2.0f) * sa - (h1 / 2.0f) * ca + my; v[3].z = pt1.z; v[3].sw = pt1.sw; v[3].u = 0.0f; v[3].v = 1.0f; v[3].r = (ubyte)r; v[3].g = (ubyte)g; v[3].b = (ubyte)b; v[3].a = 255; gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); return depth; }
// hud_show_lock_indicator() will display the lock indicator for homing missiles. // lock_point_pos should be the world coordinates of the target being locked. Assuming all the // necessary locking calculations are done for this frame, this function will compute // where the indicator should be relative to the player's viewpoint and will render accordingly. void hud_show_lock_indicator(float frametime, vec3d* lock_point_pos) { int target_objnum, sx, sy; object* targetp; vertex lock_point; if (!Players[Player_num].lock_indicator_visible) { return; } target_objnum = Player_ai->target_objnum; Assert(target_objnum != -1); targetp = &Objects[target_objnum]; // check to see if there are any missile to fire.. we don't want to show the // lock indicator if there are missiles to fire. if (!ship_secondary_bank_has_ammo(Player_obj->instance)) { return; } // Get the target's current position on the screen. If he's not on there, // we're not going to draw the lock indicator even if he's in front // of our ship, so bail out. g3_rotate_vertex(&lock_point, lock_point_pos); g3_project_vertex(&lock_point); if (lock_point.codes & PF_OVERFLOW) return; hud_set_iff_color(targetp); // nprintf(("Alan","lockx: %d, locky: %d TargetX: %d, TargetY: %d\n", Players[Player_num].lock_indicator_x, Players[Player_num].lock_indicator_y, Player->current_target_sx, Player->current_target_sy)); // We have the coordinates of the lock indicator relative to the target in our "virtual frame" // so, we calculate where it should be drawn based on the player's viewpoint. if (Player_ai->current_target_is_locked) { sx = fl2i(lock_point.sx); sy = fl2i(lock_point.sy); gr_unsize_screen_pos(&sx, &sy); // show the rotating triangles if target is locked hud_draw_lock_triangles(sx, sy, frametime); } else { sx = fl2i(lock_point.sx) - (Player->current_target_sx - Players[Player_num].lock_indicator_x); sy = fl2i(lock_point.sy) - (Player->current_target_sy - Players[Player_num].lock_indicator_y); gr_unsize_screen_pos(&sx, &sy); } // show locked indicator /* if ( Lock_gauge.first_frame >= 0 ) { gr_set_bitmap(Lock_gauge.first_frame); gr_aabitmap(sx - Lock_gauge_half_w[gr_screen.res], sy - Lock_gauge_half_h[gr_screen.res]); } else { hud_draw_diamond(sx, sy, Lock_target_box_width[gr_screen.res], Lock_target_box_height[gr_screen.res]); } */ Lock_gauge.sx = sx - Lock_gauge_half_w[Hud_reticle_style][gr_screen.res]; Lock_gauge.sy = sy - Lock_gauge_half_h[gr_screen.res]; if (Player_ai->current_target_is_locked) { Lock_gauge.time_elapsed = 0.0f; hud_anim_render(&Lock_gauge, 0.0f, 1); } else { hud_anim_render(&Lock_gauge, frametime, 1); } }
/** * @brief This function is called to blit the next frame of an anim instance to the screen. * This is normally called by the anim_render_all() function. * * @param instance Pointer to animation instance * @param frametime Time elapsed since last call, in seconds */ int anim_show_next_frame(anim_instance *instance, float frametime) { int bitmap_id, bitmap_flags=0, new_frame_num, frame_diff=0, i, n_frames=0,frame_save; float percent_through, time; vertex image_vertex; int aabitmap = 0; int bpp = 16; Assert( instance != NULL ); instance->time_elapsed += frametime; // Advance to the next frame, if we determine enough time has elapsed. if(instance->direction == ANIM_DIRECT_FORWARD) n_frames = instance->stop_at - instance->start_at + 1; else if(instance->direction == ANIM_DIRECT_REVERSE) n_frames = instance->start_at - instance->stop_at + 1; time = n_frames / i2fl(instance->parent->fps); percent_through = instance->time_elapsed / time; if(instance->direction == ANIM_DIRECT_FORWARD) new_frame_num = instance->start_at - 1 + fl2i(percent_through * n_frames + 0.5f); else new_frame_num = instance->start_at - 1 - fl2i(percent_through * n_frames + 0.5f); frame_save = instance->frame_num; // If framerate independent, use the new_frame_num... unless instance->skip_frames is // FALSE, then only advance a maximum of one frame (this is needed since some big animations // should just play slower rather than taking the hit of decompressing multiple frames and // creating an even greater slowdown if (instance->framerate_independent) { if(instance->direction == ANIM_DIRECT_FORWARD){ if ( new_frame_num > instance->last_frame_num) { if ( instance->skip_frames ) instance->frame_num = new_frame_num; else instance->frame_num++; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if( new_frame_num < instance->last_frame_num) { if ( instance->skip_frames ) instance->frame_num = new_frame_num; else instance->frame_num--; } } } else { if(instance->direction == ANIM_DIRECT_FORWARD){ if ( new_frame_num > instance->last_frame_num) { instance->frame_num++; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if ( new_frame_num < instance->last_frame_num) { instance->frame_num--; } } } if(instance->direction == ANIM_DIRECT_FORWARD){ if ( instance->frame_num < instance->start_at ) { instance->frame_num = instance->start_at; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if ( instance->frame_num > instance->start_at ) { instance->frame_num = instance->start_at; } } if ( instance->stop_now == TRUE ) { return -1; } // If past the last frame, clamp to the last frame and then set the stop_now flag in the // anim instance. The next iteration, the animation will stop. if(instance->direction == ANIM_DIRECT_FORWARD){ if (instance->frame_num >= instance->stop_at ) { if (instance->looped) { // looped animations instance->frame_num = instance->stop_at; instance->time_elapsed = 0.0f; } else if(instance->ping_pong) { // pingponged animations instance->frame_num = instance->stop_at; anim_reverse_direction(instance); } else { // one-shot animations instance->frame_num = instance->stop_at; instance->last_frame_num = instance->frame_num; instance->stop_now = TRUE; } } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if (instance->frame_num <= instance->stop_at ) { if (instance->looped) { // looped animations instance->frame_num = instance->stop_at; instance->time_elapsed = 0.0f; } else if(instance->ping_pong) { // pingponged animations instance->frame_num = instance->stop_at; anim_reverse_direction(instance); } else { // one-shot animations instance->frame_num = instance->stop_at+1; instance->last_frame_num = instance->frame_num; instance->stop_now = TRUE; } } } if(instance->direction == ANIM_DIRECT_FORWARD){ if( instance->last_frame_num >= instance->start_at ) { frame_diff = instance->frame_num - instance->last_frame_num; } else { frame_diff = 1; } } else if(instance->direction == ANIM_DIRECT_REVERSE){ if( instance->last_frame_num <= instance->start_at ) { frame_diff = instance->last_frame_num - instance->frame_num; } else { frame_diff = 1; } } Assert(frame_diff >= 0); Assert( instance->frame_num >= 0 && instance->frame_num < instance->parent->total_frames ); // if the anim is paused, ignore all the above changes and still display this frame if(instance->paused || Anim_paused){ instance->frame_num = frame_save; instance->time_elapsed -= frametime; frame_diff = 0; } if (instance->parent->flags & ANF_XPARENT){ bitmap_flags = 0; } bpp = 16; if(instance->aa_color != NULL){ bitmap_flags |= BMP_AABITMAP; aabitmap = 1; bpp = 8; } if ( frame_diff > 0 ) { instance->last_frame_num = instance->frame_num; t1 = timer_get_fixed_seconds(); for ( i = 0; i < frame_diff; i++ ) { anim_check_for_palette_change(instance); // if we're playing backwards, every frame must be a keyframe and we set the data ptr here if(instance->direction == ANIM_DIRECT_REVERSE){ if ( anim_instance_is_streamed(instance) ) { instance->file_offset = instance->parent->file_offset + instance->parent->keys[instance->frame_num-1].offset; } else { instance->data = instance->parent->data + instance->parent->keys[instance->frame_num-1].offset; } } ubyte *temp = NULL; int temp_file_offset = -1; // if we're using bitmap polys BM_SELECT_TEX_FORMAT(); if ( anim_instance_is_streamed(instance) ) { if ( instance->xlate_pal ){ temp_file_offset = unpack_frame_from_file(instance, instance->frame, instance->parent->width*instance->parent->height, instance->parent->palette_translation, aabitmap, bpp); } else { temp_file_offset = unpack_frame_from_file(instance, instance->frame, instance->parent->width*instance->parent->height, NULL, aabitmap, bpp); } } else { if ( instance->xlate_pal ){ temp = unpack_frame(instance, instance->data, instance->frame, instance->parent->width*instance->parent->height, instance->parent->palette_translation, aabitmap, bpp); } else { temp = unpack_frame(instance, instance->data, instance->frame, instance->parent->width*instance->parent->height, NULL, aabitmap, bpp); } } // always go back to screen format BM_SELECT_SCREEN_FORMAT(); // see if we had an error during decode (corrupted anim stream) if ( (temp == NULL) && (temp_file_offset < 0) ) { mprintf(("ANI: Fatal ERROR at frame %i!! Aborting playback of \"%s\"...\n", instance->frame_num, instance->parent->name)); // return -1 to end all playing of this anim instanc return -1; } if(instance->direction == ANIM_DIRECT_FORWARD){ if ( anim_instance_is_streamed(instance) ) { instance->file_offset = temp_file_offset; } else { instance->data = temp; } } } t2 = timer_get_fixed_seconds(); } else { t2=t1=0; } // this only happens when the anim is being looped, we need to reset the last_frame_num if ( (instance->time_elapsed == 0) && (instance->looped) ) { instance->last_frame_num = -1; instance->frame_num = -1; instance->data = instance->parent->data; instance->file_offset = instance->parent->file_offset; instance->loop_count++; } t1 = timer_get_fixed_seconds(); if ( frame_diff == 0 && instance->last_bitmap != -1 ) { bitmap_id = instance->last_bitmap; } else { if ( instance->last_bitmap != -1 ){ bm_release(instance->last_bitmap); } bitmap_id = bm_create(bpp, instance->parent->width, instance->parent->height, instance->frame, bitmap_flags); } if ( bitmap_id == -1 ) { // anim has finsished playing, free the instance frame data anim_release_render_instance(instance); return -1; // NOTE: there is no need to free the instance, since it was pre-allocated as // part of the anim_free_list } else { gr_set_bitmap(bitmap_id); // determine x,y to display the bitmap at if ( instance->world_pos == NULL ) { int old_max_w_unscaled = gr_screen.max_w_unscaled; int old_max_h_unscaled = gr_screen.max_h_unscaled; int old_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed; int old_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed; gr_set_screen_scale(instance->base_w, instance->base_h); gr_set_clip(0, 0, instance->base_w, instance->base_h, GR_RESIZE_MENU); if ( instance->aa_color == NULL ) { gr_bitmap(instance->x, instance->y, GR_RESIZE_MENU_NO_OFFSET); } else { gr_set_color_fast( (color*)instance->aa_color ); gr_aabitmap(instance->x, instance->y, GR_RESIZE_MENU_NO_OFFSET); } gr_set_screen_scale(old_max_w_unscaled, old_max_h_unscaled, old_max_w_unscaled_zoomed, old_max_h_unscaled_zoomed); gr_reset_clip(); } else { g3_rotate_vertex(&image_vertex,instance->world_pos); Assert(instance->radius != 0.0f); //g3_draw_bitmap(&image_vertex, 0, instance->radius*1.5f, TMAP_FLAG_TEXTURED | TMAP_HTL_2D); material mat_params; material_set_unlit(&mat_params, bitmap_id, 1.0f, false, false); g3_render_rect_screen_aligned_2d(&mat_params, &image_vertex, 0, instance->radius*1.5f); } instance->last_bitmap = bitmap_id; } t2 = timer_get_fixed_seconds(); return 0; }
void trail_add_batch(trail * trailp) { int sections[NUM_TRAIL_SECTIONS]; int num_sections = 0; int i; vec3d topv, botv, *fvec, last_pos, tmp_fvec; vertex top, bot, top_prev, bot_prev; float w; ubyte l; vec3d centerv; if (trailp->tail == trailp->head) return; // if this trail is on the player ship, and he's in any padlock view except rear view, don't draw if ((Player_ship != NULL) && trail_is_on_ship(trailp, Player_ship) && (Viewer_mode & (VM_PADLOCK_UP | VM_PADLOCK_LEFT | VM_PADLOCK_RIGHT))) { return; } trail_info *ti = &trailp->info; int n = trailp->tail; do { n--; if (n < 0) n = NUM_TRAIL_SECTIONS - 1; if (trailp->val[n] > 1.0f) break; sections[num_sections++] = n; } while (n != trailp->head); if (num_sections <= 0) return; Assertion(ti->texture.bitmap_id != -1, "Weapon trail %s could not be loaded", ti->texture.filename); // We can leave this as an assert, but tell them how to fix it. --Chief memset(&top, 0, sizeof(vertex)); memset(&bot, 0, sizeof(vertex)); memset(&top_prev, 0, sizeof(vertex)); memset(&bot_prev, 0, sizeof(vertex)); float w_size = (ti->w_end - ti->w_start); float a_size = (ti->a_end - ti->a_start); int num_faded_sections = ti->n_fade_out_sections; for (i = 0; i < num_sections; i++) { n = sections[i]; float init_fade_out = 1.0f; if ((num_faded_sections > 0) && (i < num_faded_sections)) { init_fade_out = ((float)i) / (float)num_faded_sections; } w = trailp->val[n] * w_size + ti->w_start; if (init_fade_out != 1.0f) { l = (ubyte)fl2i((trailp->val[n] * a_size + ti->a_start) * 255.0f * init_fade_out * init_fade_out); } else { l = (ubyte)fl2i((trailp->val[n] * a_size + ti->a_start) * 255.0f); } if (i == 0) { if (num_sections > 1) { vm_vec_sub(&tmp_fvec, &trailp->pos[n], &trailp->pos[sections[i + 1]]); vm_vec_normalize_safe(&tmp_fvec); fvec = &tmp_fvec; } else { fvec = &tmp_fvec; fvec->xyz.x = 0.0f; fvec->xyz.y = 0.0f; fvec->xyz.z = 1.0f; } } else { vm_vec_sub(&tmp_fvec, &last_pos, &trailp->pos[n]); vm_vec_normalize_safe(&tmp_fvec); fvec = &tmp_fvec; } trail_calc_facing_pts(&topv, &botv, fvec, &trailp->pos[n], w); if (!Cmdline_nohtl) { g3_transfer_vertex(&top, &topv); g3_transfer_vertex(&bot, &botv); } else { g3_rotate_vertex(&top, &topv); g3_rotate_vertex(&bot, &botv); } top.r = top.g = top.b = l; bot.r = bot.g = bot.b = l; top.a = bot.a = l; float U = i2fl(i); top.texture_position.u = U; top.texture_position.v = 1.0f; bot.texture_position.u = U; bot.texture_position.v = 0.0f; if (i > 0) { if (i == num_sections - 1) { // Last one... vm_vec_avg(¢erv, &topv, &botv); vertex center_vert = vertex(); if (!Cmdline_nohtl) g3_transfer_vertex(¢er_vert, ¢erv); else g3_rotate_vertex(¢er_vert, ¢erv); center_vert.texture_position.u = U + 1.0f; center_vert.texture_position.v = 0.5f; center_vert.a = center_vert.r = center_vert.g = center_vert.b = l; vertex tri[3]; tri[1] = top_prev; tri[2] = bot_prev; tri[0] = center_vert; batch_add_tri( ti->texture.bitmap_id, TMAP_FLAG_TEXTURED | TMAP_FLAG_ALPHA | TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_HTL_3D_UNLIT, tri, 1.0f ); } else { vertex quad[4]; quad[0] = top_prev; quad[1] = bot_prev; quad[2] = bot; quad[3] = top; batch_add_quad( ti->texture.bitmap_id, TMAP_FLAG_TEXTURED | TMAP_FLAG_ALPHA | TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_HTL_3D_UNLIT, quad, 1.0f ); } } last_pos = trailp->pos[n]; top_prev = top; bot_prev = bot; } }
void trail_render( trail * trailp ) { int sections[NUM_TRAIL_SECTIONS]; int num_sections = 0; int i; vec3d topv, botv, *fvec, last_pos, tmp_fvec; vertex top, bot; int nv = 0; float w; ubyte l; vec3d centerv; if (trailp->tail == trailp->head) return; // if this trail is on the player ship, and he's in any padlock view except rear view, don't draw if ( (Player_ship != NULL) && trail_is_on_ship(trailp, Player_ship) && (Viewer_mode & (VM_PADLOCK_UP | VM_PADLOCK_LEFT | VM_PADLOCK_RIGHT)) ) { return; } trail_info *ti = &trailp->info; int n = trailp->tail; do { n--; if (n < 0) n = NUM_TRAIL_SECTIONS-1; if (trailp->val[n] > 1.0f) break; sections[num_sections++] = n; } while ( n != trailp->head ); if (num_sections <= 0) return; Assertion(ti->texture.bitmap_id != -1, "Weapon trail %s could not be loaded", ti->texture.filename); // We can leave this as an assert, but tell them how to fix it. --Chief memset( &top, 0, sizeof(vertex) ); memset( &bot, 0, sizeof(vertex) ); // it's a tristrip, so allocate for 2+1 allocate_trail_verts((num_sections * 2) + 1); float w_size = (ti->w_end - ti->w_start); float a_size = (ti->a_end - ti->a_start); int num_faded_sections = ti->n_fade_out_sections; for (i = 0; i < num_sections; i++) { n = sections[i]; float init_fade_out = 1.0f; if ((num_faded_sections > 0) && (i < num_faded_sections)) { init_fade_out = ((float) i) / (float) num_faded_sections; } w = trailp->val[n] * w_size + ti->w_start; if (init_fade_out != 1.0f) { l = (ubyte)fl2i((trailp->val[n] * a_size + ti->a_start) * 255.0f * init_fade_out * init_fade_out); } else { l = (ubyte)fl2i((trailp->val[n] * a_size + ti->a_start) * 255.0f); } if ( i == 0 ) { if ( num_sections > 1 ) { vm_vec_sub(&tmp_fvec, &trailp->pos[n], &trailp->pos[sections[i+1]] ); vm_vec_normalize_safe(&tmp_fvec); fvec = &tmp_fvec; } else { fvec = &tmp_fvec; fvec->xyz.x = 0.0f; fvec->xyz.y = 0.0f; fvec->xyz.z = 1.0f; } } else { vm_vec_sub(&tmp_fvec, &last_pos, &trailp->pos[n] ); vm_vec_normalize_safe(&tmp_fvec); fvec = &tmp_fvec; } trail_calc_facing_pts( &topv, &botv, fvec, &trailp->pos[n], w ); if ( !Cmdline_nohtl ) { g3_transfer_vertex( &top, &topv ); g3_transfer_vertex( &bot, &botv ); } else { g3_rotate_vertex( &top, &topv ); g3_rotate_vertex( &bot, &botv ); } top.a = bot.a = l; if (i > 0) { float U = i2fl(i); if (i == num_sections-1) { // Last one... vm_vec_avg( ¢erv, &topv, &botv ); if ( !Cmdline_nohtl ) g3_transfer_vertex( &Trail_v_list[nv+2], ¢erv ); else g3_rotate_vertex( &Trail_v_list[nv+2], ¢erv ); Trail_v_list[nv].a = l; Trail_v_list[nv].texture_position.u = U; Trail_v_list[nv].texture_position.v = 1.0f; Trail_v_list[nv].r = Trail_v_list[nv].g = Trail_v_list[nv].b = l; nv++; Trail_v_list[nv].texture_position.u = U; Trail_v_list[nv].texture_position.v = 0.0f; Trail_v_list[nv].r = Trail_v_list[nv].g = Trail_v_list[nv].b = l; nv++; Trail_v_list[nv].texture_position.u = U + 1.0f; Trail_v_list[nv].texture_position.v = 0.5f; Trail_v_list[nv].r = Trail_v_list[nv].g = Trail_v_list[nv].b = 0; nv++; } else { Trail_v_list[nv].texture_position.u = U; Trail_v_list[nv].texture_position.v = 1.0f; Trail_v_list[nv].r = Trail_v_list[nv].g = Trail_v_list[nv].b = l; nv++; Trail_v_list[nv].texture_position.u = U; Trail_v_list[nv].texture_position.v = 0.0f; Trail_v_list[nv].r = Trail_v_list[nv].g = Trail_v_list[nv].b = l; nv++; } } last_pos = trailp->pos[n]; Trail_v_list[nv] = top; Trail_v_list[nv+1] = bot; } if ( !nv ) return; if (nv < 3) Error( LOCATION, "too few verts in trail render\n" ); // there should always be three verts in the last section and 2 everyware else, therefore there should always be an odd number of verts if ( (nv % 2) != 1 ) Warning( LOCATION, "even number of verts in trail render\n" ); profile_begin("Trail Draw"); gr_set_bitmap( ti->texture.bitmap_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f ); gr_render(nv, Trail_v_list, TMAP_FLAG_TEXTURED | TMAP_FLAG_ALPHA | TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_HTL_3D_UNLIT | TMAP_FLAG_TRISTRIP); profile_end("Trail Draw"); }
void ship_draw_shield( object *objp) { int model_num; int i; vec3d pnt; polymodel * pm; if (objp->flags & OF_NO_SHIELDS) return; Assert(objp->instance >= 0); model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num; if ( Fred_running ) return; pm = model_get(model_num); if (pm->shield.ntris<1) return; // Scan all the triangles in the mesh. for (i=0; i<pm->shield.ntris; i++ ) { int j; vec3d gnorm, v2f, tri_point; vertex prev_pnt, pnt0; shield_tri *tri; tri = &pm->shield.tris[i]; if (i == Break_value) Int3(); // Hack! Only works for object in identity orientation. // Need to rotate eye position into object's reference frame. // Only draw facing triangles. vm_vec_rotate(&tri_point, &pm->shield.verts[tri->verts[0]].pos, &Eye_matrix); vm_vec_add2(&tri_point, &objp->pos); vm_vec_sub(&v2f, &tri_point, &Eye_position); vm_vec_unrotate(&gnorm, &tri->norm, &objp->orient); if (vm_vec_dot(&gnorm, &v2f) < 0.0f) { int intensity; intensity = (int) (Ships[objp->instance].shield_integrity[i] * 255); if (intensity < 0) intensity = 0; else if (intensity > 255) intensity = 255; gr_set_color(0, 0, intensity); // Process the vertices. // Note this rotates each vertex each time it's needed, very dumb. for (j=0; j<3; j++ ) { vertex tmp; // Rotate point into world coordinates vm_vec_unrotate(&pnt, &pm->shield.verts[tri->verts[j]].pos, &objp->orient); vm_vec_add2(&pnt, &objp->pos); // Pnt is now the x,y,z world coordinates of this vert. // For this example, I am just drawing a sphere at that // point. g3_rotate_vertex(&tmp, &pnt); if (j) g3_draw_line(&prev_pnt, &tmp); else pnt0 = tmp; prev_pnt = tmp; } g3_draw_line(&pnt0, &prev_pnt); } } }
// hud_show_lock_indicator() will display the lock indicator for homing missiles. // lock_point_pos should be the world coordinates of the target being locked. Assuming all the // necessary locking calculations are done for this frame, this function will compute // where the indicator should be relative to the player's viewpoint and will render accordingly. void HudGaugeLock::render(float frametime) { int target_objnum, sx, sy; object *targetp; vertex lock_point; bool locked = Player_ai->current_target_is_locked ? true : false; bool reset_timers = false; if ( locked != Last_lock_status ) { // check if player lock status has changed since the last frame. reset_timers = true; Last_lock_status = locked; } if (Player_ai->target_objnum == -1) { return; } if (Player->target_is_dying) { return; } if (!Players[Player_num].lock_indicator_visible){ return; } target_objnum = Player_ai->target_objnum; Assert(target_objnum != -1); targetp = &Objects[target_objnum]; // check to see if there are any missile to fire.. we don't want to show the // lock indicator if there are missiles to fire. if ( !ship_secondary_bank_has_ammo(Player_obj->instance) ) { return; } bool in_frame = g3_in_frame() > 0; if(!in_frame) g3_start_frame(0); gr_set_screen_scale(base_w, base_h); // Get the target's current position on the screen. If he's not on there, // we're not going to draw the lock indicator even if he's in front // of our ship, so bail out. g3_rotate_vertex(&lock_point, &lock_world_pos); g3_project_vertex(&lock_point); if (lock_point.codes & PF_OVERFLOW) { gr_reset_screen_scale(); if(!in_frame) g3_end_frame(); return; } hud_set_iff_color(targetp); // nprintf(("Alan","lockx: %d, locky: %d TargetX: %d, TargetY: %d\n", Players[Player_num].lock_indicator_x, Players[Player_num].lock_indicator_y, Player->current_target_sx, Player->current_target_sy)); // We have the coordinates of the lock indicator relative to the target in our "virtual frame" // so, we calculate where it should be drawn based on the player's viewpoint. if (Player_ai->current_target_is_locked) { sx = fl2i(lock_point.screen.xyw.x); sy = fl2i(lock_point.screen.xyw.y); gr_unsize_screen_pos(&sx, &sy); // show the rotating triangles if target is locked renderLockTriangles(sx, sy, frametime); if ( reset_timers ) { Lock_gauge.time_elapsed = 0.0f; } } else { const float scaling_factor = (gr_screen.clip_center_x < gr_screen.clip_center_y) ? (gr_screen.clip_center_x / VIRTUAL_FRAME_HALF_WIDTH) : (gr_screen.clip_center_y / VIRTUAL_FRAME_HALF_HEIGHT); sx = fl2i(lock_point.screen.xyw.x) - fl2i(i2fl(Player->current_target_sx - Players[Player_num].lock_indicator_x) * scaling_factor); sy = fl2i(lock_point.screen.xyw.y) - fl2i(i2fl(Player->current_target_sy - Players[Player_num].lock_indicator_y) * scaling_factor); gr_unsize_screen_pos(&sx, &sy); if ( reset_timers ) { Lock_gauge_draw_stamp = -1; Lock_gauge_draw = 0; Lock_anim.time_elapsed = 0.0f; } } // show locked indicator Lock_gauge.sx = sx - Lock_gauge_half_w; Lock_gauge.sy = sy - Lock_gauge_half_h; if (Player_ai->current_target_is_locked) { hud_anim_render(&Lock_gauge, 0.0f, 1); } else { hud_anim_render(&Lock_gauge, frametime, 1); } gr_reset_screen_scale(); if(!in_frame) g3_end_frame(); }
void particle_render_all() { ubyte flags; float pct_complete; float alpha; vertex pos; vec3d ts, te, temp; int rotate = 1; int framenum, cur_frame; bool render_batch = false; int tmap_flags = TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD; if ( !Particles_enabled ) return; MONITOR_INC( NumParticlesRend, Num_particles ); if ( Particles.empty() ) return; for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); ++p) { particle* part = *p; // skip back-facing particles (ripped from fullneb code) // Wanderer - add support for attached particles vec3d p_pos; if (part->attached_objnum >= 0) { vm_vec_unrotate(&p_pos, &part->pos, &Objects[part->attached_objnum].orient); vm_vec_add2(&p_pos, &Objects[part->attached_objnum].pos); } else { p_pos = part->pos; } if ( vm_vec_dot_to_point(&Eye_matrix.vec.fvec, &Eye_position, &p_pos) <= 0.0f ) { continue; } // calculate the alpha to draw at alpha = get_current_alpha(&p_pos); // if it's transparent then just skip it if (alpha <= 0.0f) { continue; } // make sure "rotate" is enabled for this particle rotate = 1; // if this is a tracer style particle, calculate tracer vectors if (part->tracer_length > 0.0f) { ts = p_pos; temp = part->velocity; vm_vec_normalize_quick(&temp); vm_vec_scale_add(&te, &ts, &temp, part->tracer_length); // don't bother rotating rotate = 0; } // rotate the vertex if (rotate) { flags = g3_rotate_vertex( &pos, &p_pos ); if ( flags ) { continue; } if (!Cmdline_nohtl) g3_transfer_vertex(&pos, &p_pos); } // pct complete for the particle pct_complete = part->age / part->max_life; // figure out which frame we should be using if (part->nframes > 1) { framenum = fl2i(pct_complete * part->nframes + 0.5); CLAMP(framenum, 0, part->nframes-1); cur_frame = part->reverse ? (part->nframes - framenum - 1) : framenum; } else { cur_frame = 0; } if (part->type == PARTICLE_DEBUG) { gr_set_color( 255, 0, 0 ); g3_draw_sphere_ez( &p_pos, part->radius ); } else { framenum = part->optional_data; Assert( cur_frame < part->nframes ); // if this is a tracer style particle if (part->tracer_length > 0.0f) { batch_add_laser( framenum + cur_frame, &ts, part->radius, &te, part->radius ); } // draw as a regular bitmap else { batch_add_bitmap( framenum + cur_frame, tmap_flags, &pos, part->particle_index % 8, part->radius, alpha ); } render_batch = true; } } profile_begin("Batch Render"); if (render_batch) { batch_render_all(Particle_buffer_object); } profile_end("Batch Render"); }