int geometry_batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orient, float rad, float alpha, float depth) { if (texture < 0) { Int3(); return 1; } g_sdr_batch_item *item = NULL; SCP_map<int, g_sdr_batch_item>::iterator it = geometry_shader_map.find(texture); if ( !geometry_shader_map.empty() && it != geometry_shader_map.end() ) { item = &it->second; } else { item = &geometry_shader_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = alpha; item->batch.draw_bitmap(pnt, orient, rad, depth); return 0; }
int batch_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, float angle, float rad, float alpha, float depth) { if (texture < 0) { Int3(); return 1; } if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && ( !Cmdline_softparticles || GLSL_version <= 120 ) ) { // don't render this as a soft particle if we don't support soft particles tmap_flags &= ~(TMAP_FLAG_SOFT_QUAD); } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = geometry_map.find(texture); if ( !geometry_map.empty() && it != geometry_map.end() ) { item = &it->second; } else { item = &geometry_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = alpha; item->batch.add_allocate(1); item->batch.draw_bitmap(pnt, rad, angle, depth); return 0; }
float batch_add_laser(int texture, vec3d *p0, float width1, vec3d *p1, float width2, int r, int g, int b) { if (texture < 0) { Int3(); return 1; } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = geometry_map.find(texture); if ( !geometry_map.empty() && it != geometry_map.end() ) { item = &it->second; } else { item = &geometry_map[texture]; item->texture = texture; } item->laser = true; item->batch.add_allocate(1); float num = item->batch.draw_laser(p0, width1, p1, width2, r, g, b); return num; }
int distortion_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, float width, float intensity, float offset) { if (texture < 0) { Int3(); return 1; } if ( GLSL_version < 120 || !Is_Extension_Enabled(OGL_EXT_FRAMEBUFFER_OBJECT) ) { // don't render distortions if we can't support them. return 0; } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = distortion_map.find(texture); if ( !distortion_map.empty() && it != distortion_map.end() ) { item = &it->second; } else { item = &distortion_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Distortion particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = intensity; item->batch.add_allocate(1); item->batch.draw_beam(start,end,width,intensity,offset); return 0; }
int batch_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, float width, float intensity) { if (texture < 0) { Int3(); return 1; } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = geometry_map.find(texture); if ( !geometry_map.empty() && it != geometry_map.end() ) { item = &it->second; } else { item = &geometry_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = intensity; item->batch.add_allocate(1); item->batch.draw_beam(start, end, width, intensity); return 0; }
int distortion_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, float angle, float rad, float alpha, float depth) { if (texture < 0) { Int3(); return 1; } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = distortion_map.find(texture); if ( !distortion_map.empty() && it != distortion_map.end() ) { item = &it->second; } else { item = &distortion_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Distortion particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = alpha; item->batch.add_allocate(1); item->batch.draw_bitmap(pnt, rad, angle, depth); return 0; }
int batch_add_quad(int texture, int tmap_flags, vertex *verts, float alpha) { if (texture < 0) { Int3(); return 1; } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = geometry_map.find(texture); if ( !geometry_map.empty() && it != geometry_map.end() ) { item = &it->second; } else { item = &geometry_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = alpha; item->batch.add_allocate(1); item->batch.draw_quad(verts); return 0; }
void batching_shutdown() { for ( auto buffer_iter = Batching_buffers.begin(); buffer_iter != Batching_buffers.end(); ++buffer_iter ) { primitive_batch_buffer *batch_buffer = &buffer_iter->second; if ( batch_buffer->buffer_ptr != NULL ) { vm_free(batch_buffer->buffer_ptr); batch_buffer->buffer_ptr = nullptr; } } }
int geometry_batch_get_size() { int n_to_render = 0; SCP_map<int, g_sdr_batch_item>::iterator bi; for (bi = geometry_shader_map.begin(); bi != geometry_shader_map.end(); ++bi) { n_to_render += bi->second.batch.need_to_render(); } return n_to_render; }
void batch_load_buffer_distortion_map_bitmaps(effect_vertex* buffer, int *n_verts) { for (SCP_map<int, batch_item>::iterator bi = distortion_map.begin(); bi != distortion_map.end(); ++bi) { if ( bi->second.laser ) continue; if ( !bi->second.batch.need_to_render() ) continue; Assert( bi->second.texture >= 0 ); bi->second.batch.load_buffer(buffer, n_verts); } }
void batching_render_all(bool render_distortions) { GR_DEBUG_SCOPE("Batching render all"); TRACE_SCOPE(tracing::DrawEffects); batching_load_buffers(render_distortions); SCP_map<batch_buffer_key, primitive_batch_buffer>::iterator bi; for ( bi = Batching_buffers.begin(); bi != Batching_buffers.end(); ++bi ) { batching_render_buffer(&bi->second); } gr_clear_states(); }
primitive_batch* batching_find_batch(int texture, batch_info::material_type material_id, primitive_type prim_type, bool thruster) { batch_info query(material_id, texture, prim_type, thruster); SCP_map<batch_info, primitive_batch>::iterator iter = Batching_primitives.find(query); if ( iter == Batching_primitives.end() ) { primitive_batch* batch = &Batching_primitives[query]; *batch = primitive_batch(query); return batch; } else { return &iter->second; } }
primitive_batch_buffer* batching_find_buffer(uint vertex_mask, primitive_type prim_type) { batch_buffer_key query(vertex_mask, prim_type); SCP_map<batch_buffer_key, primitive_batch_buffer>::iterator iter = Batching_buffers.find(query); if ( iter == Batching_buffers.end() ) { primitive_batch_buffer *buffer = &Batching_buffers[query]; batching_init_buffer(buffer, prim_type, vertex_mask); return buffer; } else { return &iter->second; } }
int batch_get_size() { int n_to_render = 0; SCP_map<int, batch_item>::iterator bi; for (bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) { n_to_render += bi->second.batch.need_to_render(); } for (bi = distortion_map.begin(); bi != distortion_map.end(); ++bi) { if ( bi->second.laser ) continue; n_to_render += bi->second.batch.need_to_render(); } return n_to_render * 3; }
void batch_render_geometry_map_bitmaps(int buffer_handle) { for (SCP_map<int, batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) { if ( bi->second.laser ) continue; if ( !bi->second.batch.need_to_render() ) continue; Assert( bi->second.texture >= 0 ); gr_set_bitmap(bi->second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi->second.alpha); if ( buffer_handle >= 0 ) { bi->second.batch.render_buffer(buffer_handle, bi->second.tmap_flags); } else { bi->second.batch.render( bi->second.tmap_flags); } } }
void batch_render_lasers(int buffer_handle) { for (SCP_map<int, batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) { if ( !bi->second.laser ) continue; if ( !bi->second.batch.need_to_render() ) continue; Assert( bi->second.texture >= 0 ); gr_set_bitmap(bi->second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.99999f); if ( buffer_handle >= 0 ) { bi->second.batch.render_buffer(buffer_handle, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); } else { bi->second.batch.render(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT); } } }
primitive_batch* batching_find_batch(int texture, batch_info::material_type material_id, primitive_type prim_type, bool thruster) { // Use the base texture for finding the batch item since all items can reuse the same texture array auto base_tex = bm_get_base_frame(texture); batch_info query(material_id, base_tex, prim_type, thruster); SCP_map<batch_info, primitive_batch>::iterator iter = Batching_primitives.find(query); if ( iter == Batching_primitives.end() ) { primitive_batch* batch = &Batching_primitives[query]; *batch = primitive_batch(query); return batch; } else { return &iter->second; } }
int batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orient, float rad, float alpha, float depth) { if (texture < 0) { Int3(); return 1; } if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && ( !Cmdline_softparticles || GLSL_version <= 120 ) ) { // don't render this as a soft particle if we don't support soft particles tmap_flags &= ~(TMAP_FLAG_SOFT_QUAD); } if ( GLSL_version > 120 && Cmdline_softparticles && !Cmdline_no_geo_sdr_effects && Is_Extension_Enabled(OGL_EXT_GEOMETRY_SHADER4) && (tmap_flags & TMAP_FLAG_VERTEX_GEN) ) { geometry_batch_add_bitmap(texture, tmap_flags, pnt, orient, rad, alpha, depth); return 0; } else if ( tmap_flags & TMAP_FLAG_VERTEX_GEN ) { tmap_flags &= ~(TMAP_FLAG_VERTEX_GEN); } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = geometry_map.find(texture); if ( !geometry_map.empty() && it != geometry_map.end() ) { item = &it->second; } else { item = &geometry_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = alpha; item->batch.add_allocate(1); item->batch.draw_bitmap(pnt, orient, rad, depth); return 0; }
void batch_load_buffer_geometry_shader_map_bitmaps(particle_pnt* buffer, int *n_verts) { for (SCP_map<int, g_sdr_batch_item>::iterator bi = geometry_shader_map.begin(); bi != geometry_shader_map.end(); ++bi) { if ( bi->second.laser ) continue; if ( !bi->second.batch.need_to_render() ) continue; Assert( bi->second.texture >= 0 ); bi->second.batch.load_buffer(buffer, n_verts); } }
void batching_load_buffers(bool distortion) { GR_DEBUG_SCOPE("Batching load buffers"); TRACE_SCOPE(tracing::LoadBatchingBuffers); SCP_map<batch_info, primitive_batch>::iterator bi; SCP_map<batch_buffer_key, primitive_batch_buffer>::iterator buffer_iter; for ( buffer_iter = Batching_buffers.begin(); buffer_iter != Batching_buffers.end(); ++buffer_iter ) { // zero out the buffers buffer_iter->second.desired_buffer_size = 0; } // assign primitive batch items for ( bi = Batching_primitives.begin(); bi != Batching_primitives.end(); ++bi ) { if ( bi->first.mat_type == batch_info::DISTORTION ) { if ( !distortion ) { continue; } } else { if ( distortion ) { continue; } } size_t num_verts = bi->second.num_verts(); if ( num_verts > 0 ) { batch_info render_info = bi->second.get_render_info(); uint vertex_mask = batching_determine_vertex_layout(&render_info); primitive_batch_buffer *buffer = batching_find_buffer(vertex_mask, render_info.prim_type); primitive_batch_item draw_item; draw_item.batch_item_info = render_info; draw_item.offset = 0; draw_item.n_verts = num_verts; draw_item.batch = &bi->second; buffer->desired_buffer_size += num_verts * sizeof(batch_vertex); buffer->items.push_back(draw_item); } } for ( buffer_iter = Batching_buffers.begin(); buffer_iter != Batching_buffers.end(); ++buffer_iter ) { batching_allocate_and_load_buffer(&buffer_iter->second); } }
void parse_everything_else(const char *filename) { Assertion(filename != NULL, "parse_everything_else() called on NULL; get a coder!\n"); read_file_text(filename, CF_TYPE_TABLES); int err_code; if ((err_code = setjmp(parse_abort)) != 0) { mprintf(("TABLES: Unable to parse '%s'! Error code = %d.\n", filename, err_code)); return; } reset_parse(); int rgba[4] = {0,0,0,0}; // reusable temp vars int i, j; SCP_string temp; if (optional_string("#Start Colors")) { // Skip this section; we already parsed it in every file. skip_to_string("#End", NULL); } //Team coloring if (optional_string("#Team Colors")) { while (required_string_either("#End", "$Team Name:")) { required_string("$Team Name:"); // required to move the parse pointer forward team_color temp_color; char temp2[NAME_LENGTH]; stuff_string(temp2, F_NAME, NAME_LENGTH); temp = temp2; if (!stricmp(temp2, "none")) { Warning(LOCATION, "Team color in '%s' defined with a name of '%s'; this won't be usable due to 'None' being used for a lack of a team color by the engine.\n", filename, temp2); } if (required_string("$Team Stripe Color:")) { int rgb[3]; stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { CLAMP(rgb[i], 0, 255); } temp_color.stripe.r = rgb[0] / 255.0f; temp_color.stripe.g = rgb[1] / 255.0f; temp_color.stripe.b = rgb[2] / 255.0f; } if (required_string("$Team Base Color:")) { int rgb[3]; stuff_int_list(rgb, 3, RAW_INTEGER_TYPE); for (i = 0; i < 3; i++) { CLAMP(rgb[i], 0, 255); } temp_color.base.r = rgb[0] / 255.0f; temp_color.base.g = rgb[1] / 255.0f; temp_color.base.b = rgb[2] / 255.0f; } if (Team_Colors.find(temp) == Team_Colors.end()) { // Only push to the vector if the team isn't already defined. Team_Names.push_back(temp); } Team_Colors[temp] = temp_color; } required_string("#End"); } // Previously-hardcoded interface colors if (optional_string("#Interface Colors")) { char *color_names[INTERFACE_COLORS] = { "$Text Normal:", "$Text Subselected:", "$Text Selected:", "$Text Error:", "$Text Error Highlighted:", "$Text Active:", "$Text Active Highlighted:", "$Text Heading:", "$More Indicator:", "$Bright More Indicator:", "$Bright:", "$Normal:", }; // now for each color, check if its corresponding string is there for (i = 0; i < INTERFACE_COLORS; i++) { if (optional_string(color_names[i])) { // if so, get its rgba values and initialise it using them mprintf(("'%s' has been redefined.\n", color_names[i])); if ( check_for_string("(") ) { // If we have a list of integers, use them. stuff_int_list(rgba, 4, RAW_INTEGER_TYPE); for (j = 0; j < 4; j++) { if (rgba[j] < 0) { Warning(LOCATION, "RGBA value for '%s' in %s too low (%d), capping to 0.\n", color_names[i], filename, rgba[j]); rgba[j] = 0; } else if (rgba[j] > 255) { Warning(LOCATION, "RGBA value for '%s' in %s too high (%d), capping to 255.\n", color_names[i], filename, rgba[j]); rgba[j] = 255; } } gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]); //} else if (check_for_string("#")) { // stuff_hex_list(rgba, 4); // gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]); } else { // We have a string; it should be the name of a color to use. stuff_string(temp, F_NAME); for (j = 0; j < TOTAL_COLORS; j++) { if ( !temp.compare(COLOR_NAMES[j]) ) { break; } } if ( j == TOTAL_COLORS ) { Warning(LOCATION, "Unknown color '%s' in %s, for definition of '%s'; using default ('%s').\n", temp.c_str(), filename, color_names[i], COLOR_NAMES[interface_defaults[i]]); } else { Assertion(j >= 0 && j < TOTAL_COLORS, "Attempting to copy nonexistant color (%d out of 0-%d)!\n", j, TOTAL_COLORS-1); memcpy(interface_colors[i], COLOR_LIST[j], sizeof(color)); } } } } required_string("#End"); } // Text color tags; for briefings, command briefings, debriefings, and the fiction viewer if (optional_string("#Color Tags")) { while (required_string_either("$Tag:", "#End") < 1) { required_string("$Tag:"); color temp_color; char tag; stuff_string(temp, F_RAW); if (temp[0] == '$') { if (temp[1] == '\0') { Error(LOCATION, "%s - found a '$Tag:' entry with a solitary '$'.\n", filename); } tag = temp[1]; if (temp[2] != '\0') { Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag); } } else if (temp[0] == '\0') { Error(LOCATION, "%s - found a '$Tag:' entry with no tag.\n", filename); } else { tag = temp[0]; if (temp[1] != '\0') { Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag); } } if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // Only push the tag to our list of tags if it's actually new, not just a redefinition. Color_Tags.push_back(tag); } switch(required_string_one_of(4, "+Color:", "+Friendly", "+Hostile", "+Neutral")) { case 0: // +Color required_string("+Color:"); rgba[0] = rgba[1] = rgba[2] = 0; rgba[3] = 255; // Odds are pretty high you want it to have full alpha... if ( check_for_string("(") ) { stuff_int_list(rgba, 4, RAW_INTEGER_TYPE); for (j = 0; j < 4; j++) { if (rgba[j] < 0) { Warning(LOCATION, "RGBA value for '$%c' in %s too low (%d), capping to 0.\n", tag, filename, rgba[j]); rgba[j] = 0; } else if (rgba[j] > 255) { Warning(LOCATION, "RGBA value for '$%c' in %s too high (%d), capping to 255.\n", tag, filename, rgba[j]); rgba[j] = 255; } } gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]); Custom_Colors[tag] = temp_color; Tagged_Colors[tag] = &Custom_Colors[tag]; //} else if ( check_for_string ("#") ) { // stuff_hex_list(rgba, 4); // gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]); // Custom_Colors[tag] = temp_color; // Tagged_Colors[tag] = &Custom_Colors[tag]; } else { // We have a string; it should be the name of a color to use. stuff_string(temp, F_NAME); for (j = 0; j < TOTAL_COLORS; j++) { if ( !temp.compare(COLOR_NAMES[j]) ) { break; } } if ( j == TOTAL_COLORS ) { Error(LOCATION, "Unknown color '%s' in %s, for definition of tag '$%c'.\n", temp.c_str(), filename, tag); } Tagged_Colors[tag] = COLOR_LIST[j]; } break; case 1: // +Friendly required_string("+Friendly"); Tagged_Colors[tag] = &Brief_color_green; break; case 2: // +Hostile required_string("+Hostile"); Tagged_Colors[tag] = &Brief_color_red; break; case 3: // +Neutral required_string("+Neutral"); Tagged_Colors[tag] = &Brief_color_legacy_neutral; break; case -1: // -noparseerrors is set if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // It was a new color, but since we haven't actually defined it... Color_Tags.pop_back(); } break; default: Assertion(false, "MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n"); break; } } required_string("#End"); } Assertion(Color_Tags.size() == Tagged_Colors.size(), "Color_Tags and Tagged_Colors size mismatch; get a coder!\n"); if (optional_string("#Default Text Colors")) { char* color_names[MAX_DEFAULT_TEXT_COLORS] = { "$Fiction Viewer:", "$Command Briefing:", "$Briefing:", "$Redalert Briefing:", "$Debriefing:", "$Recommendation:", "$Loop Briefing:", }; char *color_value[MAX_DEFAULT_TEXT_COLORS] = { &default_fiction_viewer_color, &default_command_briefing_color, &default_briefing_color, &default_redalert_briefing_color, &default_debriefing_color, &default_recommendation_color, &default_loop_briefing_color, }; for (i = 0; i < MAX_DEFAULT_TEXT_COLORS; i++) { if ( optional_string(color_names[i]) ) { stuff_string(temp, F_RAW); if (temp[0] == '$') { if (temp[1] == '\0') { Error(LOCATION, "%s - default text color '%s' entry with a solitary '$'.\n", filename, color_names[i]); } *color_value[i] = temp[1]; if (temp[2] != '\0') { Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]); } } else if (temp[0] == '\0') { Error(LOCATION, "%s - default text color '%s' entry with no tag.\n", filename, color_names[i]); } else { *color_value[i] = temp[0]; if (temp[1] != '\0') { Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]); } } if (Tagged_Colors.find(*color_value[i]) == Tagged_Colors.end()) { // Just mprintf() this information instead of complaining with a Warning(); the tag might be defined in a later-loading TBM, and if it isn't, nothing too terrible will happen. mprintf(("%s - default text color '%s' set to non-existant tag '$%c'.\n", filename, color_names[i], *color_value[i])); } } } required_string("#End"); } }
// ******************************************************************************************** // Engages autopilot // This does: // * Control switched from player to AI // * Time compression to 32x // * Lock time compression -WMC // * Tell AI to fly to targeted Nav Point (for all nav-status wings/ships) // * Sets max waypoint speed to the best-speed of the slowest ship tagged bool StartAutopilot() { // Check for support ship and dismiss it if it is not doing anything. // If the support ship is doing something then tell the user such. for ( object *objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) { if ((objp->type == OBJ_SHIP) && !(objp->flags & OF_SHOULD_BE_DEAD)) { Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS), "objp does not have a valid pointer to a ship. Pointer is %d, which is smaller than 0 or bigger than %d", objp->instance, MAX_SHIPS); ship *shipp = &Ships[objp->instance]; if (shipp->team != Player_ship->team) continue; Assertion((shipp->ship_info_index >= 0) && (shipp->ship_info_index < MAX_SHIP_CLASSES), "Ship '%s' does not have a valid pointer to a ship class. Pointer is %d, which is smaller than 0 or bigger than %d", shipp->ship_name, shipp->ship_info_index, MAX_SHIP_CLASSES); ship_info *sip = &Ship_info[shipp->ship_info_index]; if ( !(sip->flags & SIF_SUPPORT) ) continue; // don't deal with dying or departing support ships if ( shipp->flags & (SF_DYING | SF_DEPARTING) ) continue; Assert(shipp->ai_index != -1); ai_info* support_ship_aip = &(Ai_info[Ships[objp->instance].ai_index]); // is support ship trying to rearm-repair if ( ai_find_goal_index( support_ship_aip->goals, AI_GOAL_REARM_REPAIR ) == -1 ) { // no, so tell it to depart ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WARP, -1, NULL, support_ship_aip ); } else { // yes send_autopilot_msgID(NP_MSG_FAIL_SUPPORT_WORKING); return false; } } } if (!CanAutopilot()) return false; AutoPilotEngaged = true; // find the ship that is "leading" all of the ships when the player starts // autopilot // by default the ship that is leading the autopilot session the player's // wing leader (if the player is the wing leader then it will be the // player). // TODO:implement a way to allow a FREDer to say a different ship is leader Autopilot_flight_leader = get_wing_leader(Player_ship->wingnum); if ( Autopilot_flight_leader == NULL ) { // force player to be the leader if he doesn't have a wing Autopilot_flight_leader = Player_obj; } if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) LockAPConv = timestamp(); // lock convergence instantly else LockAPConv = timestamp(3000); // 3 seconds before we lock convergence Player_use_ai = 1; set_time_compression(1); lock_time_compression(true); // determine speed cap int i,j, wcount=1, tc_factor=1; float speed_cap = 1000000.0; // 1m is a safe starting point float radius = Player_obj->radius, distance = 0.0f, ftemp; bool capshipPresent = false; int capship_counts[3]; // three size classes capship_counts[0] = 0; capship_counts[1] = 0; capship_counts[2] = 0; int capship_placed[3]; // three size classes capship_placed[0] = 0; capship_placed[1] = 0; capship_placed[2] = 0; float capship_spreads[3]; capship_spreads[0] = 0.0f; capship_spreads[1] = 0.0f; capship_spreads[2] = 0.0f; SCP_vector<int> capIndexes; // empty the autopilot wings map autopilot_wings.clear(); // vars for usage w/ cinematic vec3d pos, norm1, perp, tpos, rpos = Player_obj->pos, zero; memset(&zero, 0, sizeof(vec3d)); // instantly turn player toward tpos if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) { vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos); vm_vector_2_matrix(&Player_obj->orient, &norm1, NULL, NULL); } for (i = 0; i < MAX_SHIPS; i++) { if (Ships[i].objnum != -1 && (Ships[i].flags2 & SF2_NAVPOINT_CARRY || (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) ) ) { if (speed_cap > vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel)) speed_cap = vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel); } } // damp speed_cap to 90% of actual -- to make sure ships stay in formation if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) speed_cap = 0.90f * speed_cap; if ( speed_cap < 1.0f ) { /* We need to deal with this so that incorrectly flagged ships will not cause the engine to fail to limit all the ships speeds correctly. */ Warning(LOCATION, "Ship speed cap is way too small (%f)!\n" "This is normally caused by a ship that has nav-carry-status set, but cannot move itself (like a Cargo container).\n" "Speed cap has been set to 1.0 m/s.", speed_cap); speed_cap = 1.0f; } ramp_bias = speed_cap/50.0f; // assign ship goals // when assigning goals to individual ships only do so if Ships[shipnum].wingnum != -1 // we will assign wing goals below for (i = 0; i < MAX_SHIPS; i++) { if (Ships[i].objnum != -1 && (Ships[i].flags2 & SF2_NAVPOINT_CARRY || (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) ) ) { // do we have capital ships in the area? if (Ship_info[Ships[i].ship_info_index].flags & ( SIF_CRUISER | SIF_CAPITAL | SIF_SUPERCAP | SIF_CORVETTE | SIF_AWACS | SIF_GAS_MINER | SIF_FREIGHTER | SIF_TRANSPORT)) { capshipPresent = true; capIndexes.push_back(i); // ok.. what size class if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP)) { capship_counts[0]++; if (capship_spreads[0] < Objects[Ships[i].objnum].radius) capship_spreads[0] = Objects[Ships[i].objnum].radius; } else if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CORVETTE)) { capship_counts[1]++; if (capship_spreads[1] < Objects[Ships[i].objnum].radius) capship_spreads[1] = Objects[Ships[i].objnum].radius; } else { capship_counts[2]++; if (capship_spreads[2] < Objects[Ships[i].objnum].radius) capship_spreads[2] = Objects[Ships[i].objnum].radius; } } // check for bigger radius for usage later /*if (!vm_vec_cmp(&rpos, &Player_obj->pos)) // want to make sure rpos isn't player pos - we can worry about it being largest object's later { rpos = Objects[Ships[i].objnum].pos; }*/ if (Objects[Ships[i].objnum].radius > radius) { rpos = Objects[Ships[i].objnum].pos; radius = Objects[Ships[i].objnum].radius; } if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) {// instantly turn the ship to match the direction player is looking //vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos); vm_vector_2_matrix(&Objects[Ships[i].objnum].orient, &norm1, NULL, NULL); } // snap wings into formation if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS && // only if using cinematics (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) // only if in a wing && Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object { ai_info *aip = &Ai_info[Ships[i].ai_index]; int wingnum = aip->wing, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum); vec3d goal_point; object *leader_objp = get_wing_leader(wingnum); if (leader_objp != &Objects[Ships[i].objnum]) { // not leader.. get our position relative to leader get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT); } else { ai_clear_wing_goals(wingnum); j = 1+int( (float)floor(double(wcount-1)/2.0) ); switch (wcount % 2) { case 1: // back-left vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec); //vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec); vm_vec_normalize(&perp); vm_vec_scale(&perp, -166.0f*j); // 166m is supposedly the optimal range according to tolwyn vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp); break; default: //back-right case 0: vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec); //vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec); vm_vec_normalize(&perp); vm_vec_scale(&perp, 166.0f*j); vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp); break; } autopilot_wings[wingnum] = wcount; wcount++; } Objects[Ships[i].objnum].pos = goal_point; if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos) > distance) { distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos); } } // lock primary and secondary weapons if ( LockWeaponsDuringAutopilot ) Ships[i].flags2 |= (SF2_PRIMARIES_LOCKED | SF2_SECONDARIES_LOCKED); // clear the ship goals and cap the waypoint speed ai_clear_ship_goals(&Ai_info[Ships[i].ai_index]); Ai_info[Ships[i].ai_index].waypoint_speed_cap = (int)speed_cap; // if they're not part of a wing set their goal if (Ships[i].wingnum == -1 || The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) { if (Navs[CurrentNav].flags & NP_WAYPOINT) { ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), &Ai_info[Ships[i].ai_index] ); //fixup has to wait until after wing goals } else { ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, &Ai_info[Ships[i].ai_index] ); } } } } // assign wing goals if (!(The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)) { for (i = 0; i < MAX_WINGS; i++) { if (Wings[i].flags & WF_NAV_CARRY ) { //ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip ); //ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum ); //ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum ); //ai_clear_ship_goals( &(Ai_info[Ships[num].ai_index]) ); ai_clear_wing_goals( i ); if (Navs[CurrentNav].flags & NP_WAYPOINT) { ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), i ); // "fix up" the goal for (j = 0; j < MAX_AI_GOALS; j++) { if (Wings[i].ai_goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE || Wings[i].ai_goals[j].ai_mode == AIM_WAYPOINTS ) { autopilot_ai_waypoint_goal_fixup(&(Wings[i].ai_goals[j])); } } } else { ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, i ); } } } } // fixup has to go down here because ships are assigned goals during wing goals as well for (i = 0; i < MAX_SHIPS; i++) { if (Ships[i].objnum != -1) { if (Ships[i].flags2 & SF2_NAVPOINT_CARRY || (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)) for (j = 0; j < MAX_AI_GOALS; j++) { if (Ai_info[Ships[i].ai_index].goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE || Ai_info[Ships[i].ai_index].goals[j].ai_mode == AIM_WAYPOINTS) { autopilot_ai_waypoint_goal_fixup( &(Ai_info[Ships[i].ai_index].goals[j]) ); // formation fixup //ai_form_on_wing(&Objects[Ships[i].objnum], &Objects[Player_ship->objnum]); } } } } start_dist = DistanceTo(CurrentNav); // ----------------------------- setup cinematic ----------------------------- if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) { if (capshipPresent) { // position capships vec3d right, front, up, offset; for (SCP_vector<int>::iterator idx = capIndexes.begin(); idx != capIndexes.end(); ++idx) { vm_vec_add(&right, &Autopilot_flight_leader->orient.vec.rvec, &zero); vm_vec_add(&front, &Autopilot_flight_leader->orient.vec.fvec, &zero); vm_vec_add(&up, &Autopilot_flight_leader->orient.vec.uvec, &zero); vm_vec_add(&offset, &zero, &zero); if (Ship_info[Ships[*idx].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP)) { //0 - below - three lines of position // front/back to zero vm_vec_add(&front, &zero, &zero); // position below vm_vec_scale(&up, capship_spreads[0]); // scale the up vector by the radius of the largest ship in this formation part switch (capship_placed[0] % 3) { case 1: // right vm_vec_scale(&right, capship_spreads[0]); break; case 2: // left vm_vec_scale(&right, -capship_spreads[0]); break; default: // straight case 0: vm_vec_add(&right, &zero, &zero); vm_vec_scale(&up, 1.5); // add an extra half-radius break; } // scale by row vm_vec_scale(&right, (1+((float)floor((float)capship_placed[0]/3)))); vm_vec_scale(&up, -(1+((float)floor((float)capship_placed[0]/3)))); capship_placed[0]++; } else if (Ship_info[Ships[*idx].ship_info_index].flags & SIF_CORVETTE) { //1 above - 3 lines of position // front/back to zero vm_vec_add(&front, &zero, &zero); // position below vm_vec_scale(&up, capship_spreads[1]); // scale the up vector by the radius of the largest ship in this formation part switch (capship_placed[1] % 3) { case 1: // right vm_vec_scale(&right, capship_spreads[1]); break; case 2: // left vm_vec_scale(&right, -capship_spreads[1]); break; default: // straight case 0: vm_vec_add(&right, &zero, &zero); vm_vec_scale(&up, 1.5); // add an extra half-radius break; } // scale by row vm_vec_scale(&right, (1+((float)floor((float)capship_placed[1]/3)))); vm_vec_scale(&up, (1+((float)floor((float)capship_placed[1]/3)))); // move ourselves up and out of the way of the smaller ships vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.uvec, &zero); vm_vec_scale(&perp, capship_spreads[2]); vm_vec_add(&up, &up, &perp); capship_placed[1]++; } else { //2 either side - 6 lines of position (right (dir, front, back), left (dir, front, back) ) // placing pattern: right, left, front right, front left, rear right, rear left // up/down to zero vm_vec_add(&up, &zero, &zero); switch (capship_placed[2] % 6) { case 5: // rear left vm_vec_scale(&right, -capship_spreads[2]); vm_vec_scale(&front, -capship_spreads[2]); break; case 4: // rear right vm_vec_scale(&right, capship_spreads[2]); vm_vec_scale(&front, -capship_spreads[2]); break; case 3: // front left vm_vec_scale(&right, -capship_spreads[2]); vm_vec_scale(&front, capship_spreads[2]); break; case 2: // front right vm_vec_scale(&right, capship_spreads[2]); vm_vec_scale(&front, capship_spreads[2]); break; case 1: // straight left vm_vec_scale(&right, 1.5); vm_vec_scale(&right, -capship_spreads[2]); vm_vec_add(&front, &zero, &zero); break; default: // straight right case 0: vm_vec_scale(&right, 1.5); vm_vec_scale(&right, capship_spreads[2]); vm_vec_add(&front, &zero, &zero); break; } // these ships seem to pack a little too tightly vm_vec_scale(&right, 2*(1+((float)floor((float)capship_placed[2]/3)))); vm_vec_scale(&front, 2*(1+((float)floor((float)capship_placed[2]/3)))); // move "out" by 166*(wcount-1) so we don't bump into fighters vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.rvec, &zero); vm_vec_scale(&perp, 166.0f*float(wcount-1)); if ( (capship_placed[2] % 2) == 0) vm_vec_add(&right, &right, &perp); else vm_vec_sub(&right, &right, &perp); capship_placed[2]++; } // integrate the up/down componant vm_vec_add(&offset, &offset, &up); //integrate the left/right componant vm_vec_add(&offset, &offset, &right); //integrate the left/right componant vm_vec_add(&offset, &offset, &front); // global scale the position by 50% //vm_vec_scale(&offset, 1.5); vm_vec_add(&Objects[Ships[*idx].objnum].pos, &Autopilot_flight_leader->pos, &offset); if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos) > distance) { distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos); } } } ftemp = floor(Autopilot_flight_leader->phys_info.max_vel.xyz.z/speed_cap); if (ftemp >= 2.0f && ftemp < 4.0f) tc_factor = 2; else if (ftemp >= 4.0f && ftemp < 8.0f) tc_factor = 4; else if (ftemp >= 8.0f) tc_factor = 8; tpos = *Navs[CurrentNav].GetPosition(); // determine distance toward nav at which camera will be vm_vec_sub(&pos, &tpos, &Autopilot_flight_leader->pos); vm_vec_normalize(&pos); // pos is now a unit vector in the direction we will be moving the camera //norm1 = pos; vm_vec_scale(&pos, 5*speed_cap*tc_factor); // pos is now scaled by 5 times the speed (5 seconds ahead) vm_vec_add(&pos, &pos, &Autopilot_flight_leader->pos); // pos is now 5*speed cap in front of player ship switch (myrand()%24) // 8 different ways of getting perp points // 4 of which will not be used when capships are present (anything below, or straight above) { case 1: // down case 9: case 16: if (capship_placed[0] == 0) vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec); else { // become up-left vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec); vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec); } break; case 2: // up case 10: case 23: vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec); if (capshipPresent) // become up-right vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec); break; case 3: // left case 11: case 22: vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec); break; case 4: // up-left case 12: case 21: vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec); vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec); break; case 5: // up-right case 13: case 20: vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec); vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec); break; case 6: // down-left case 14: case 19: vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec); if (capship_placed[0] < 2) vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec); else vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec); break; case 7: // down-right case 15: case 18: vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec); if (capship_placed[0] < 1) vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec); else vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec); break; default: case 0: // right case 8: case 17: perp = Autopilot_flight_leader->orient.vec.rvec; break; } vm_vec_normalize(&perp); //vm_vec_scale(&perp, 2*radius+distance); vm_vec_scale(&perp, Autopilot_flight_leader->radius+radius); // randomly scale up/down by up to 20% j = 20-myrand()%40; // [-20,20] vm_vec_scale(&perp, 1.0f+(float(j)/100.0f)); vm_vec_add(&cameraPos, &pos, &perp); if (capshipPresent) { vm_vec_normalize(&perp); // place it behind //vm_vec_copy_scale(&norm1, &Player_obj->orient.vec.fvec, -2*(Player_obj->radius+radius*(1.0f+(float(j)/100.0f)))); //vm_vec_add(&cameraTarget, &cameraTarget, &norm1); vm_vec_copy_scale(&cameraTarget,&perp, radius/5.0f); //vm_vec_scale(&cameraTarget, Player_obj->radius+radius*(1.0f+(float(j)/100.0f))); //vm_vec_add(&cameraTarget, &pos, &cameraTarget); //CameraSpeed = (radius+distance)/25; //vm_vec_add(&cameraTarget, &zero, &perp); //vm_vec_scale(&CameraVelocity, (radius+distance/100.f)); //vm_vec_scale(&CameraVelocity, 1.0f/float(NPS_TICKRATE*tc_factor)); } else { vm_vec_add(&cameraTarget, &zero, &zero); //CameraSpeed = 0; } //CameraMoving = false; EndAPCinematic = timestamp((10000*tc_factor)+NPS_TICKRATE); // 10 objective seconds before end of cinematic MoveCamera = timestamp((5500*tc_factor)+NPS_TICKRATE); camMovingTime = int(4.5*float(tc_factor)); set_time_compression((float)tc_factor); } return true; }
void batch_reset() { geometry_map.clear(); distortion_map.clear(); }
int batch_add_polygon(int texture, int tmap_flags, vec3d *pos, matrix *orient, float width, float height, float alpha) { //idiot-proof if(width == 0 || height == 0) return 0; Assert(pos != NULL); Assert(orient != NULL); //Let's begin. const int NUM_VERTICES = 4; vec3d p[NUM_VERTICES] = { ZERO_VECTOR }; vertex v[NUM_VERTICES] = { vertex() }; p[0].xyz.x = width; p[0].xyz.y = height; p[1].xyz.x = -width; p[1].xyz.y = height; p[2].xyz.x = -width; p[2].xyz.y = -height; p[3].xyz.x = width; p[3].xyz.y = -height; for(int i = 0; i < NUM_VERTICES; i++) { vec3d tmp = vmd_zero_vector; //Rotate correctly vm_vec_unrotate(&tmp, &p[i], orient); //Move to point in space vm_vec_add2(&tmp, pos); //Convert to vertex g3_transfer_vertex(&v[i], &tmp); } v[0].texture_position.u = 1.0f; v[0].texture_position.v = 0.0f; v[1].texture_position.u = 0.0f; v[1].texture_position.v = 0.0f; v[2].texture_position.u = 0.0f; v[2].texture_position.v = 1.0f; v[3].texture_position.u = 1.0f; v[3].texture_position.v = 1.0f; if (texture < 0) { Int3(); return 1; } batch_item *item = NULL; SCP_map<int, batch_item>::iterator it = geometry_map.find(texture); if ( !geometry_map.empty() && it != geometry_map.end() ) { item = &it->second; } else { item = &geometry_map[texture]; item->texture = texture; } Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) ); item->tmap_flags = tmap_flags; item->alpha = alpha; item->batch.add_allocate(1); item->batch.draw_quad(v); return 0; }