mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 07:28:22 -10:00
Compare commits
156
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a07486866 | ||
|
|
28f60df7fa | ||
|
|
bed18012d6 | ||
|
|
d43f30053d | ||
|
|
76dccbe07d | ||
|
|
3eafcde138 | ||
|
|
ca7065df46 | ||
|
|
cedf66cb31 | ||
|
|
03a3fbdc1c | ||
|
|
9c6661e0e8 | ||
|
|
6bea921fbe | ||
|
|
79f5eda0d6 | ||
|
|
3aa61dfccb | ||
|
|
0febfb3545 | ||
|
|
e1c8f5d2ed | ||
|
|
44343f8d1e | ||
|
|
424c69d1e5 | ||
|
|
6d1354f1f6 | ||
|
|
d5c4f3e5c7 | ||
|
|
89bd64f4ab | ||
|
|
417739665c | ||
|
|
e236a79773 | ||
|
|
d523f0aef3 | ||
|
|
697c009fb3 | ||
|
|
1f918fd4c6 | ||
|
|
3ea7a6d1ba | ||
|
|
633cd88e83 | ||
|
|
7431aba995 | ||
|
|
328bebe83a | ||
|
|
94e4f3d4cd | ||
|
|
b57573c439 | ||
|
|
0b1d1eed56 | ||
|
|
123feba557 | ||
|
|
8c64d73a18 | ||
|
|
e156f15561 | ||
|
|
3e1d89ba53 | ||
|
|
4f7bad2a5c | ||
|
|
dd621e8904 | ||
|
|
396d2c55a9 | ||
|
|
782f6f100d | ||
|
|
4f76c441d6 | ||
|
|
a2bd895b7b | ||
|
|
a4cf53694d | ||
|
|
6bd7a43e3d | ||
|
|
fffc0ebf8b | ||
|
|
f2426de80b | ||
|
|
27f6088117 | ||
|
|
30c76f36ce | ||
|
|
35094851f2 | ||
|
|
b562cf822e | ||
|
|
62942557d5 | ||
|
|
4d68bed436 | ||
|
|
19d5b8e68e | ||
|
|
9dc50706a7 | ||
|
|
f2a0e35959 | ||
|
|
e637eea2fb | ||
|
|
f3e3769056 | ||
|
|
e218f687a9 | ||
|
|
5e10fccdbf | ||
|
|
12672d0c2b | ||
|
|
de7081fbb3 | ||
|
|
d73e4d4dec | ||
|
|
aeefcb4657 | ||
|
|
023dcfca76 | ||
|
|
c6e9f954f0 | ||
|
|
961d5eb171 | ||
|
|
1a66c97c2e | ||
|
|
00e2c2ad52 | ||
|
|
8991fc67cd | ||
|
|
7641abf41c | ||
|
|
871f7a822e | ||
|
|
ca66664eac | ||
|
|
4c1b3551b4 | ||
|
|
07d47cb984 | ||
|
|
ce9ee8c264 | ||
|
|
8039650248 | ||
|
|
cd2b578a1b | ||
|
|
85ec8251e3 | ||
|
|
7e51a13c3a | ||
|
|
538b2c6c95 | ||
|
|
d3a70e8ed6 | ||
|
|
9dc68849d6 | ||
|
|
b6bab87601 | ||
|
|
b8d868f828 | ||
|
|
01e6a57aaa | ||
|
|
e0fe9227aa | ||
|
|
803751959a | ||
|
|
9597b5962e | ||
|
|
792f74b33e | ||
|
|
5181e71dab | ||
|
|
3d0e0f80ae | ||
|
|
251125913a | ||
|
|
89d2d6ed46 | ||
|
|
06f198afc1 | ||
|
|
19a289539a | ||
|
|
c14653b391 | ||
|
|
2527bf31c7 | ||
|
|
184107283a | ||
|
|
42c19cdfee | ||
|
|
3830534978 | ||
|
|
48eef6566d | ||
|
|
b253442545 | ||
|
|
1d5e9794d6 | ||
|
|
b7a9f545fd | ||
|
|
9541e244d1 | ||
|
|
f12d202afe | ||
|
|
507a5f1de8 | ||
|
|
3810b039f5 | ||
|
|
827754d6de | ||
|
|
d455e17e34 | ||
|
|
db360820a9 | ||
|
|
804a222041 | ||
|
|
6dab1e464f | ||
|
|
86c45309e8 | ||
|
|
4f4690a482 | ||
|
|
1ca60e1d2f | ||
|
|
011f7e4d6c | ||
|
|
eb538ffba8 | ||
|
|
2a73fb340f | ||
|
|
ad60240eb6 | ||
|
|
f8df97b489 | ||
|
|
d5feddfb8a | ||
|
|
f5e32fa1a2 | ||
|
|
9fa3baa458 | ||
|
|
4b3760dfb4 | ||
|
|
142d586a1c | ||
|
|
95103dfcb8 | ||
|
|
f50ea26051 | ||
|
|
983dd0b6ca | ||
|
|
3bdc5e0c27 | ||
|
|
ba6a471054 | ||
|
|
ce44e3522b | ||
|
|
c1b87bc2b6 | ||
|
|
1f164dbb64 | ||
|
|
1275cbfd83 | ||
|
|
20cccdbf20 | ||
|
|
077338086a | ||
|
|
0b2ee5f76b | ||
|
|
3f9218e671 | ||
|
|
3003d0589d | ||
|
|
4bd15d43da | ||
|
|
8df62e99f5 | ||
|
|
d93c9c4220 | ||
|
|
1b5fd3c5fd | ||
|
|
8292d8c44a | ||
|
|
78c79ac88d | ||
|
|
6e54ed3dfc | ||
|
|
3c53b74e5e | ||
|
|
829e0b8b7c | ||
|
|
4b60ca467c | ||
|
|
b45cb19f3c | ||
|
|
e30c919286 | ||
|
|
2ee128cd88 | ||
|
|
a2b349855e | ||
|
|
1239ec47e3 | ||
|
|
eb1814e303 |
No files matched your search
@@ -26,6 +26,7 @@ TARGET_LINK_LIBRARIES(code PUBLIC openal)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC lz4)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
|
||||
|
||||
|
||||
+1
-1
@@ -1448,7 +1448,7 @@ void ai_big_strafe_attack()
|
||||
if (ai_new_maybe_reposition_attack_subsys())
|
||||
return;
|
||||
} else if (ai_big_maybe_follow_subsys_path(0))
|
||||
return
|
||||
return;
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
|
||||
+66
-141
@@ -87,6 +87,18 @@ typedef struct eval_enemy_obj_struct {
|
||||
int nearest_objnum;
|
||||
} eval_enemy_obj_struct;
|
||||
|
||||
// the current world orientation of the turret matrix, corresponding to its fvec and uvec defined in the model
|
||||
// is NOT affected by the turret's current aiming
|
||||
void turret_instance_find_world_orient(matrix* out_mat, int model_instance_num, int submodel_num, const matrix* objorient)
|
||||
{
|
||||
auto pmi = model_get_instance(model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
vec3d fvec, uvec;
|
||||
model_instance_find_world_dir(&fvec, &pm->submodel[submodel_num].frame_of_reference.vec.fvec, pm, pmi, pm->submodel[submodel_num].parent, objorient);
|
||||
model_instance_find_world_dir(&uvec, &pm->submodel[submodel_num].frame_of_reference.vec.uvec, pm, pmi, pm->submodel[submodel_num].parent, objorient);
|
||||
vm_vector_2_matrix_norm(out_mat, &fvec, &uvec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is object in turret field of view?
|
||||
*
|
||||
@@ -98,124 +110,53 @@ typedef struct eval_enemy_obj_struct {
|
||||
*
|
||||
* @return 1 if objp is in fov of the specified turret. Otherwise return 0.
|
||||
*/
|
||||
int object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
|
||||
bool object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
|
||||
{
|
||||
vec3d v2e;
|
||||
float size_mod;
|
||||
bool in_fov;
|
||||
bool in_fov = false;
|
||||
|
||||
if (ss->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
|
||||
int model_num;
|
||||
switch (objp->type) {
|
||||
case OBJ_SHIP:
|
||||
model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
|
||||
break;
|
||||
case OBJ_ASTEROID:
|
||||
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
|
||||
break;
|
||||
default:
|
||||
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
|
||||
size_mod = objp->radius / (dist + objp->radius);
|
||||
|
||||
in_fov = turret_fov_test(ss, tvec, &v2e, size_mod);
|
||||
|
||||
return in_fov;
|
||||
}
|
||||
|
||||
auto pm = model_get(model_num);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
vec3d bbox_point;
|
||||
vm_vec_unrotate(&bbox_point, &pm->bounding_box[i], &objp->orient);
|
||||
bbox_point += objp->pos;
|
||||
|
||||
vm_vec_normalized_dir(&v2e, &bbox_point, tpos);
|
||||
in_fov = turret_fov_test(ss, tvec, &v2e, -0.2f);
|
||||
|
||||
if (in_fov)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// if the bbox points method didn't work (or fov_edge_checks isn't on)
|
||||
// try the normal method
|
||||
|
||||
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
|
||||
size_mod = objp->radius / (dist + objp->radius);
|
||||
|
||||
in_fov = turret_fov_test(ss, tvec, &v2e, size_mod);
|
||||
|
||||
if ( in_fov ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_object_radius_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, vec3d *v2e, vec3d *predicted_pos, float distance)
|
||||
{
|
||||
float target_dist = distance;
|
||||
if (distance == 0.0f)
|
||||
target_dist = vm_vec_dist(predicted_pos,tpos);
|
||||
|
||||
if (object_in_turret_fov(objp, ss, tvec, tpos, target_dist + objp->radius)) {
|
||||
// so the targeted spot in not in fov but the enemy + radius is
|
||||
// lets align the darn gun and try shooting there
|
||||
vec3d temp_vec;
|
||||
float multiplier = 0;
|
||||
model_subsystem *tp = ss->system_info;
|
||||
|
||||
// project v2e_from_turret to turret normal
|
||||
// substract resultant vector from the temp_vec (v2e_from_turret)
|
||||
// adjust z component as necessary
|
||||
// calculate multiplier for the resultant vector
|
||||
// use multiplier and the z component and compose a new vector
|
||||
float dot = vm_vec_dot(v2e, tvec);
|
||||
|
||||
vm_vec_scale_add(&temp_vec, v2e, tvec, -dot);
|
||||
|
||||
if (IS_VEC_NULL_SQ_SAFE(&temp_vec)) {
|
||||
// return false, target is perfectly aligned over or below the turret
|
||||
// safe bet is to allow turret to reacquire better target
|
||||
return false;
|
||||
}
|
||||
|
||||
// normalize the vec, it needs to be done regardless
|
||||
vm_vec_normalize(&temp_vec);
|
||||
bool fix_elevation = false;
|
||||
bool fix_base_rot = false;
|
||||
|
||||
if (dot < tp->turret_fov) {
|
||||
dot = tp->turret_fov;
|
||||
fix_elevation = true;
|
||||
}
|
||||
if (dot > tp->turret_max_fov) {
|
||||
dot = tp->turret_max_fov;
|
||||
fix_elevation = true;
|
||||
}
|
||||
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
|
||||
// Since we no longer maintain world_to_turret_matrix, regenerate it here.
|
||||
vec3d turret_norm;
|
||||
matrix turret_matrix, world_to_turret_matrix;
|
||||
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->subobj_num, &vmd_identity_matrix);
|
||||
vm_vector_2_matrix(&turret_matrix, &turret_norm, nullptr, nullptr);
|
||||
vm_matrix_x_matrix(&world_to_turret_matrix, &objp->orient, &turret_matrix);
|
||||
|
||||
vec3d temp_vec2;
|
||||
vm_vec_rotate(&temp_vec2, &temp_vec, &world_to_turret_matrix);
|
||||
|
||||
// now in turrets frame of reference
|
||||
// check if math is actually possible
|
||||
if (!((temp_vec2.xyz.x == 0) && (temp_vec2.xyz.y == 0))) {
|
||||
float temp_z = temp_vec2.xyz.z;
|
||||
temp_vec2.xyz.z = 0.0f;
|
||||
// make sure null vecs wont happen
|
||||
if (!IS_VEC_NULL_SQ_SAFE(&temp_vec2)) {
|
||||
vm_vec_normalize(&temp_vec2);
|
||||
// only do this if it actually is required
|
||||
if (-temp_vec2.xyz.y < tp->turret_y_fov) {
|
||||
float check_pos = 1;
|
||||
|
||||
fix_base_rot = true;
|
||||
temp_vec2.xyz.y = -tp->turret_y_fov;
|
||||
if (temp_vec2.xyz.x < 0)
|
||||
check_pos = -1;
|
||||
temp_vec2.xyz.x = check_pos * sqrtf(1 - (temp_vec2.xyz.y*temp_vec2.xyz.y));
|
||||
|
||||
// restore z component
|
||||
float scaler = sqrtf(1 - (temp_z*temp_z));
|
||||
vm_vec_scale(&temp_vec2,scaler);
|
||||
temp_vec2.xyz.z = temp_z;
|
||||
// back to world frame
|
||||
vm_vec_unrotate(&temp_vec, &temp_vec2, &world_to_turret_matrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fix_elevation || fix_base_rot) {
|
||||
if (fix_elevation) {
|
||||
multiplier = sqrtf(1 - (dot*dot));
|
||||
// keep the temp_vec scaled with the tweaked vector
|
||||
vm_vec_scale(&temp_vec, multiplier);
|
||||
}
|
||||
vm_vec_scale_add(v2e, &temp_vec, tvec, dot);
|
||||
// and we are done with v2e...
|
||||
vm_vec_scale_add(predicted_pos, tpos, v2e, target_dist);
|
||||
// and we are done with predicted position
|
||||
return true;
|
||||
} else {
|
||||
mprintf(("Warning: Function 'is_object_radius_in_turret_fov' was called\nwithout need to fix turret alignments\n"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// outside of the expanded radii, unable to align, return false
|
||||
return false;
|
||||
return in_fov;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1196,17 +1137,11 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
|
||||
if ( tagged_only_flag && ship_is_tagged(&Objects[aip->target_objnum]) ) {
|
||||
// select new target if aip->target_objnum is out of field of view
|
||||
vec3d v2e;
|
||||
float dist;
|
||||
bool in_fov;
|
||||
dist = vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, tpos);
|
||||
vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, tpos);
|
||||
|
||||
in_fov = turret_fov_test(turret_subsys, tvec, &v2e);
|
||||
|
||||
if (turret_subsys->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
|
||||
if (in_fov == false)
|
||||
if (object_in_turret_fov(&Objects[aip->target_objnum], turret_subsys, tvec, tpos, dist + Objects[aip->target_objnum].radius))
|
||||
in_fov = true;
|
||||
}
|
||||
// MODIFY FOR ATTACKING BIG SHIP
|
||||
// dot += (0.5f * Objects[aip->target_objnum].radius / dist);
|
||||
if (in_fov) {
|
||||
@@ -1256,7 +1191,7 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
|
||||
if (gpos)
|
||||
model_instance_find_world_point(gpos, &vmd_zero_vector, model_instance_num, tp->subobj_num, &objp->orient, &objp->pos);
|
||||
if (gvec)
|
||||
model_instance_find_world_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient);
|
||||
model_instance_find_world_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient, true);
|
||||
}
|
||||
|
||||
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
|
||||
@@ -1317,7 +1252,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
} else {
|
||||
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
|
||||
// the turret norm here is from the perspective of the base submodel, not the gun submodel
|
||||
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, pm, pmi, tp->subobj_num, &objp->orient);
|
||||
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, pm, pmi, pm->submodel[tp->subobj_num].parent, &objp->orient);
|
||||
ai_big_pick_attack_point_turret(lep, ssp, &tmp_pos, &turret_norm, &enemy_point, MIN(wip->max_speed * wip->lifetime, wip->weapon_range), tp->turret_fov);
|
||||
}
|
||||
else {
|
||||
@@ -1448,18 +1383,13 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
|
||||
|
||||
in_fov = turret_fov_test(ss, gvec, &v2e);
|
||||
|
||||
if (ss->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
|
||||
if (in_fov == false)
|
||||
in_fov = is_object_radius_in_turret_fov(&Objects[ss->turret_enemy_objnum], ss, gvec, &gun_pos, &v2e, predicted_enemy_pos, 0.0f);
|
||||
}
|
||||
|
||||
if (in_fov) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, tp, predicted_enemy_pos);
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
|
||||
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, tp, predicted_enemy_pos, true);
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
}
|
||||
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss->system_info, predicted_enemy_pos, true);
|
||||
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
|
||||
}
|
||||
|
||||
// by default "ret_val" should be set to 1 for multi-part turrets, and 0 for single-part turrets
|
||||
@@ -1491,7 +1421,7 @@ float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunp
|
||||
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, 1, &dot_out, &vector_out)) {
|
||||
vec3d turret_norm;
|
||||
|
||||
model_instance_find_world_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient);
|
||||
model_instance_find_world_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient, true);
|
||||
float dot_return = vm_vec_dot(&turret_norm, &vector_out);
|
||||
|
||||
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Smart_subsystem_targeting_for_turrets]) {
|
||||
@@ -2812,25 +2742,20 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
|
||||
model_subsystem *tp = ss->system_info;
|
||||
float dot = vm_vec_dot(v2e, gvec);
|
||||
if (((dot + size_mod) >= tp->turret_fov) && ((dot - size_mod) <= tp->turret_max_fov)) {
|
||||
|
||||
// Since we no longer maintain world_to_turret_matrix, regenerate it here.
|
||||
object *objp = &Objects[ss->parent_objnum];
|
||||
vec3d turret_norm;
|
||||
matrix turret_matrix, world_to_turret_matrix;
|
||||
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->subobj_num, &vmd_identity_matrix);
|
||||
vm_vector_2_matrix(&turret_matrix, &turret_norm, nullptr, nullptr);
|
||||
vm_matrix_x_matrix(&world_to_turret_matrix, &objp->orient, &turret_matrix);
|
||||
object* objp = &Objects[ss->parent_objnum];
|
||||
matrix turret_matrix;
|
||||
turret_instance_find_world_orient(&turret_matrix, Ships[objp->instance].model_instance_num, tp->subobj_num, &objp->orient);
|
||||
|
||||
vec3d of_dst;
|
||||
vm_vec_rotate( &of_dst, v2e, &world_to_turret_matrix );
|
||||
if ((of_dst.xyz.x == 0) && (of_dst.xyz.y == 0)) {
|
||||
return true;
|
||||
} else {
|
||||
of_dst.xyz.z = 0;
|
||||
vm_vec_rotate(&of_dst, v2e, &turret_matrix);
|
||||
if ((of_dst.xyz.x == 0) && (of_dst.xyz.z == 0))
|
||||
return true;
|
||||
else {
|
||||
of_dst.xyz.y = 0;
|
||||
if (!IS_VEC_NULL_SQ_SAFE(&of_dst)) {
|
||||
vm_vec_normalize(&of_dst);
|
||||
// now we have 2d vector with lenght of 1 that points at the targets direction after being rotated to turrets FOR
|
||||
if ((-of_dst.xyz.y + size_mod) >= tp->turret_y_fov)
|
||||
if ((of_dst.xyz.z + size_mod) >= tp->turret_base_fov)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2841,7 +2766,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
|
||||
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
|
||||
{
|
||||
bool in_fov = false;
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_alt_math])
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_restricted_fov])
|
||||
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
|
||||
else
|
||||
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
|
||||
|
||||
@@ -866,6 +866,7 @@ static int cfget_cfile_block()
|
||||
cfile->data = nullptr;
|
||||
cfile->fp = nullptr;
|
||||
cfile->type = CFILE_BLOCK_USED;
|
||||
cf_clear_compression_info(cfile);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -921,7 +922,7 @@ int cfclose( CFILE * cfile )
|
||||
} else {
|
||||
// VP do nothing
|
||||
}
|
||||
|
||||
cf_clear_compression_info(cfile);
|
||||
cfile->type = CFILE_BLOCK_UNUSED;
|
||||
return result;
|
||||
}
|
||||
@@ -973,7 +974,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
|
||||
if(pos == -1L)
|
||||
pos = 0;
|
||||
cf_init_lowlevel_read_code(cfp,0,filelength(fileno(fp)), 0 );
|
||||
|
||||
cf_check_compression(cfp);
|
||||
return cfp;
|
||||
}
|
||||
}
|
||||
@@ -1008,7 +1009,7 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* o
|
||||
cfp->line_num = line;
|
||||
|
||||
cf_init_lowlevel_read_code(cfp,offset, size, 0 );
|
||||
|
||||
cf_check_compression(cfp);
|
||||
return cfp;
|
||||
}
|
||||
|
||||
@@ -1052,6 +1053,7 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const ch
|
||||
cfp->line_num = line;
|
||||
|
||||
cf_init_lowlevel_read_code(cfp, 0, 0, 0 );
|
||||
|
||||
#if defined _WIN32
|
||||
cfp->hMapFile = CreateFileMapping(cfp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (cfp->hMapFile == NULL) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "cfile/cfilearchive.h"
|
||||
#include "cfile/cfilecompression.h"
|
||||
#include "luaconf.h"
|
||||
|
||||
#include <sstream>
|
||||
@@ -33,7 +34,6 @@
|
||||
#define CHECK_POSITION
|
||||
|
||||
// Called once to setup the low-level reading code.
|
||||
|
||||
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos )
|
||||
{
|
||||
Assert(cfile != nullptr);
|
||||
@@ -54,6 +54,33 @@ void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size,
|
||||
}
|
||||
}
|
||||
|
||||
//This function checks the file header to see if the file is compressed, if so it fills the correct compression info.
|
||||
void cf_check_compression(CFILE* cfile)
|
||||
{
|
||||
if (cfile->size <= 16)
|
||||
return;
|
||||
int header=cfread_int(cfile);
|
||||
cfseek(cfile, 0, SEEK_SET);
|
||||
if (comp_check_header(header) == COMP_HEADER_MATCH)
|
||||
comp_create_ci(cfile, header);
|
||||
}
|
||||
|
||||
//This function is called to cleanup compression info when the cfile handle is reused.
|
||||
void cf_clear_compression_info(CFILE* cfile)
|
||||
{
|
||||
if (cfile->compression_info.header != 0)
|
||||
{
|
||||
free(cfile->compression_info.offsets);
|
||||
free(cfile->compression_info.decoder_buffer);
|
||||
cfile->compression_info.offsets = nullptr;
|
||||
cfile->compression_info.decoder_buffer = nullptr;
|
||||
cfile->compression_info.header = 0;
|
||||
cfile->compression_info.block_size = 0;
|
||||
cfile->compression_info.last_decoded_block_pos = 0;
|
||||
cfile->compression_info.last_decoded_block_bytes = 0;
|
||||
cfile->compression_info.num_offsets = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// cfeof() Tests for end-of-file on a stream
|
||||
@@ -61,11 +88,11 @@ void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size,
|
||||
// returns a nonzero value after the first read operation that attempts to read
|
||||
// past the end of the file. It returns 0 if the current position is not end of file.
|
||||
// There is no error return.
|
||||
|
||||
int cfeof(CFILE *cfile)
|
||||
{
|
||||
Assert(cfile != NULL);
|
||||
|
||||
if (cfile->compression_info.header != 0)
|
||||
return comp_feof(cfile);
|
||||
int result = 0;
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
@@ -92,6 +119,8 @@ int cfeof(CFILE *cfile)
|
||||
int cftell( CFILE * cfile )
|
||||
{
|
||||
Assert(cfile != NULL);
|
||||
if (cfile->compression_info.header != 0)
|
||||
return (int)comp_ftell(cfile);
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
if (cfile->fp) {
|
||||
@@ -117,6 +146,9 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
|
||||
Assert(cfile != NULL);
|
||||
|
||||
if (cfile->compression_info.header != 0)
|
||||
return comp_fseek(cfile, offset, where);
|
||||
|
||||
// TODO: seek to offset in memory mapped file
|
||||
Assert( !cfile->mem_mapped );
|
||||
|
||||
@@ -202,23 +234,31 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
// This is a file from memory
|
||||
bytes_read = size;
|
||||
memcpy(buf, reinterpret_cast<const char*>(cfile->data) + cfile->raw_position, size);
|
||||
} else if (cfile->compression_info.header != 0) {
|
||||
bytes_read = comp_fread(cfile, reinterpret_cast<char*>(buf),size);
|
||||
if (bytes_read != size)
|
||||
{
|
||||
mprintf(("\nFile: %s decompression error. Result was: %d expected: %d\n", cfile->original_filename.c_str(), (int)bytes_read, (int)size));
|
||||
Assertion(bytes_read == size, "File decompression error!");
|
||||
}
|
||||
} else {
|
||||
bytes_read = fread( buf, 1, size, cfile->fp );
|
||||
bytes_read = fread(buf, 1, size, cfile->fp);
|
||||
}
|
||||
|
||||
if ( bytes_read > 0 ) {
|
||||
cfile->raw_position += bytes_read;
|
||||
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
|
||||
}
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
if (cfile->fp) {
|
||||
//Raw position is not the fp position with compressed files
|
||||
if (cfile->fp && cfile->compression_info.header == 0) {
|
||||
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
|
||||
Assert(tmp_offset==cfile->raw_position);
|
||||
Assert(tmp_offset == cfile->raw_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (int)(bytes_read / elsize);
|
||||
|
||||
}
|
||||
|
||||
int cfread_lua_number(double *buf, CFILE *cfile)
|
||||
@@ -266,4 +306,3 @@ int cfread_lua_number(double *buf, CFILE *cfile)
|
||||
return items_read;
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CFILEARCHIVE_H
|
||||
#define _CFILEARCHIVE_H
|
||||
|
||||
@@ -23,6 +22,17 @@
|
||||
#define CFILE_BLOCK_UNUSED 0
|
||||
#define CFILE_BLOCK_USED 1
|
||||
|
||||
struct COMPRESSION_INFO {
|
||||
int header = 0;
|
||||
size_t compressed_size = 0;
|
||||
int block_size = 0;
|
||||
int num_offsets = 0;
|
||||
int* offsets = nullptr;
|
||||
char* decoder_buffer = nullptr;
|
||||
int last_decoded_block_pos = 0;
|
||||
int last_decoded_block_bytes = 0;
|
||||
};
|
||||
|
||||
struct CFILE {
|
||||
int type = CFILE_BLOCK_UNUSED; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
|
||||
int dir_type; // directory location
|
||||
@@ -44,12 +54,19 @@ struct CFILE {
|
||||
SCP_string original_filename;
|
||||
const char* source_file;
|
||||
int line_num;
|
||||
COMPRESSION_INFO compression_info;
|
||||
};
|
||||
|
||||
#define MAX_CFILE_BLOCKS 64
|
||||
extern std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
|
||||
|
||||
// Called once to setup the low-level reading code.
|
||||
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos );
|
||||
void cf_init_lowlevel_read_code(CFILE* cfile, size_t lib_offset, size_t size, size_t pos);
|
||||
|
||||
// This checks if the file is compressed or not, and creates the proper compression info if so.
|
||||
void cf_check_compression(CFILE* cfile);
|
||||
|
||||
// Used to clear compression info data and free dynamic memory used by compression
|
||||
void cf_clear_compression_info(CFILE* cfile);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
#define _CFILE_INTERNAL
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#include "lz4.h"
|
||||
#include "cfilecompression.h"
|
||||
#include "cfilearchive.h"
|
||||
|
||||
/*INTERNAL FUNCTIONS*/
|
||||
/*LZ41*/
|
||||
void lz41_load_offsets(CFILE* cf);
|
||||
size_t lz41_stream_random_access(CFILE* cf, char* bytes_out, size_t offset, size_t length);
|
||||
void lz41_create_ci(CFILE* cf, int header);
|
||||
/*MISC*/
|
||||
int fso_fseek(CFILE* cfile, int offset, int where);
|
||||
/*END OF INTERNAL FUNCTIONS*/
|
||||
|
||||
int comp_check_header(int header)
|
||||
{
|
||||
if (LZ41_FILE_HEADER == header)
|
||||
return COMP_HEADER_MATCH;
|
||||
|
||||
return COMP_HEADER_MISMATCH;
|
||||
}
|
||||
|
||||
void comp_create_ci(CFILE* cf, int header)
|
||||
{
|
||||
//mprintf(("(CI)Compressed File Opened: %s \n", cf->original_filename.c_str()));
|
||||
|
||||
if (LZ41_FILE_HEADER == header)
|
||||
lz41_create_ci(cf, header);
|
||||
|
||||
//mprintf(("(CI)Uncompressed FileSize: %d \n", cf->size));
|
||||
//mprintf(("(CI)Compressed FileSize: %d \n", cf->compression_info.compressed_size));
|
||||
//mprintf(("(CI)Block Size: %d \n", cf->compression_info.block_size));
|
||||
}
|
||||
|
||||
size_t comp_fread(CFILE* cf, char* buffer, size_t length)
|
||||
{
|
||||
/* Check the request to be at least 1 byte */
|
||||
Assertion(length > 0, "Invalid length requested.");
|
||||
|
||||
/* Check that we are not requesting to read beyond end of file */
|
||||
Assertion(cf->raw_position + length <= cf->size, "Invalid length requested.");
|
||||
|
||||
if (LZ41_FILE_HEADER == cf->compression_info.header)
|
||||
return lz41_stream_random_access(cf, buffer, cf->raw_position, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t comp_ftell(CFILE* cf)
|
||||
{
|
||||
return cf->raw_position;
|
||||
}
|
||||
|
||||
int comp_feof(CFILE* cf)
|
||||
{
|
||||
if (cf->raw_position >= cf->size)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int comp_fseek(CFILE* cf, int offset, int where)
|
||||
{
|
||||
size_t goal_position;
|
||||
switch (where) {
|
||||
case SEEK_SET: goal_position = offset; break;
|
||||
case SEEK_CUR: goal_position = cf->raw_position + offset; break;
|
||||
case SEEK_END: goal_position = cf->size + offset; break;
|
||||
default: return 1;
|
||||
}
|
||||
|
||||
// Make sure we don't seek beyond the end of the file
|
||||
CAP(goal_position,(size_t)0, cf->size);
|
||||
|
||||
cf->raw_position = goal_position;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Special fseek for compressed files handled by FSO, only SEEK_SET and SEEK_END is supported.
|
||||
int fso_fseek(CFILE* cfile, int offset, int where)
|
||||
{
|
||||
size_t goal_position;
|
||||
|
||||
switch (where) {
|
||||
case SEEK_SET: goal_position = offset + cfile->lib_offset; break;
|
||||
case SEEK_END: goal_position = cfile->compression_info.compressed_size + offset + cfile->lib_offset; break;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
// Make sure we don't seek beyond the end of the file
|
||||
CAP(goal_position, cfile->lib_offset, cfile->lib_offset + cfile->compression_info.compressed_size);
|
||||
|
||||
int result = 0;
|
||||
if (cfile->fp)
|
||||
{
|
||||
result = fseek(cfile->fp, (long)goal_position, SEEK_SET);
|
||||
Assertion(goal_position >= cfile->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cfile->lib_offset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void lz41_create_ci(CFILE* cf, int header)
|
||||
{
|
||||
cf->compression_info.header = header;
|
||||
cf->compression_info.compressed_size = cf->size;
|
||||
fso_fseek(cf, (int)sizeof(int)*-3, SEEK_END);
|
||||
auto fNumoffsets = fread(&cf->compression_info.num_offsets, sizeof(int), 1, cf->fp);
|
||||
auto fSize = fread(&cf->size, sizeof(int), 1, cf->fp);
|
||||
auto fBsize = fread(&cf->compression_info.block_size, sizeof(int), 1, cf->fp);
|
||||
|
||||
Assertion(cf->compression_info.num_offsets > 0, "Invalid number of offsets, compressed file is possibly in the wrong format or corrupted.");
|
||||
#if !defined(NDEBUG)
|
||||
Assertion(cf->size > 4, "Invalid filesize, compressed file is possibly in the wrong format or corrupted.");
|
||||
Assertion(cf->compression_info.block_size > 16, "Invalid block size, compressed file is possibly in the wrong format or corrupted.");
|
||||
Assertion(fNumoffsets == 1, "Error while reading the number of offsets, compressed file is possibly in the wrong format or corrupted.");
|
||||
Assertion(fSize == 1, "Error while reading original filesize, compressed file is possibly in the wrong format or corrupted.");
|
||||
Assertion(fBsize == 1, "Error while reading block size, compressed file is possibly in the wrong format or corrupted.");
|
||||
#endif
|
||||
|
||||
cf->compression_info.decoder_buffer = (char*)malloc(LZ4_compressBound(cf->compression_info.block_size));
|
||||
cf->compression_info.last_decoded_block_pos = 0;
|
||||
cf->compression_info.last_decoded_block_bytes = 0;
|
||||
lz41_load_offsets(cf);
|
||||
}
|
||||
|
||||
void lz41_load_offsets(CFILE* cf)
|
||||
{
|
||||
cf->compression_info.offsets = (int*)malloc(cf->compression_info.num_offsets * sizeof(int));
|
||||
int block;
|
||||
int* offsets_ptr = cf->compression_info.offsets;
|
||||
|
||||
/* Seek to the first offset position, remember to consider the trailing ints */
|
||||
fso_fseek(cf, ( ( sizeof(int) * cf->compression_info.num_offsets ) * -1 ) - (sizeof(int)*3 ), SEEK_END);
|
||||
for (block = 0; block < cf->compression_info.num_offsets; ++block)
|
||||
{
|
||||
auto bytes_read = fread(offsets_ptr++, sizeof(int), 1, cf->fp);
|
||||
Assertion(bytes_read == 1, "Error reading offset list.");
|
||||
}
|
||||
}
|
||||
|
||||
size_t lz41_stream_random_access(CFILE* cf, char* bytes_out, size_t offset, size_t length)
|
||||
{
|
||||
LZ4_streamDecode_t lz4_stream_decode_body;
|
||||
LZ4_streamDecode_t* lz4_stream_decode = &lz4_stream_decode_body;
|
||||
/* The blocks (current_block to end_block) contain the data we want */
|
||||
size_t current_block = offset / cf->compression_info.block_size;
|
||||
size_t end_block = ((offset + length - 1) / cf->compression_info.block_size) + 1;
|
||||
size_t written_bytes = 0;
|
||||
|
||||
if (cf->compression_info.num_offsets <= (int)end_block)
|
||||
return (size_t)LZ41_OFFSETS_MISMATCH;
|
||||
|
||||
/* Seek to the first block to read, if it matches the cached block, search the next one instead */
|
||||
if (cf->compression_info.last_decoded_block_pos == cf->compression_info.offsets[current_block] && current_block + 1 <= end_block)
|
||||
fso_fseek(cf, cf->compression_info.offsets[current_block+1], SEEK_SET);
|
||||
else
|
||||
fso_fseek(cf, cf->compression_info.offsets[current_block], SEEK_SET);
|
||||
|
||||
offset = offset % cf->compression_info.block_size;
|
||||
char* cmp_buf = (char*)malloc(LZ4_compressBound(cf->compression_info.block_size));
|
||||
|
||||
/* Start decoding */
|
||||
for (; current_block < end_block; ++current_block)
|
||||
{
|
||||
/* Only read and decode if the requested block is not the cached one */
|
||||
if (cf->compression_info.last_decoded_block_pos != cf->compression_info.offsets[current_block])
|
||||
{
|
||||
cf->compression_info.last_decoded_block_pos = cf->compression_info.offsets[current_block];
|
||||
|
||||
/* The difference in offsets is the size of the block */
|
||||
int cmp_bytes = cf->compression_info.offsets[current_block + 1] - cf->compression_info.offsets[current_block];
|
||||
auto bytes_read = fread(cmp_buf, cmp_bytes, 1, cf->fp);
|
||||
Assertion(bytes_read == 1, "Error reading from compressed file.");
|
||||
|
||||
cf->compression_info.last_decoded_block_bytes = LZ4_decompress_safe_continue(lz4_stream_decode, cmp_buf, cf->compression_info.decoder_buffer, cmp_bytes, cf->compression_info.block_size);
|
||||
if (cf->compression_info.last_decoded_block_bytes <= 0)
|
||||
{
|
||||
free(cmp_buf);
|
||||
return (size_t)LZ41_DECOMPRESSION_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write out the part of the data we care about from buffer */
|
||||
size_t block_length = (length < (cf->compression_info.last_decoded_block_bytes - offset) ? length : (cf->compression_info.last_decoded_block_bytes - offset));
|
||||
memcpy(bytes_out + written_bytes, cf->compression_info.decoder_buffer + offset, (size_t)block_length);
|
||||
written_bytes += block_length;
|
||||
offset = 0;
|
||||
length -= block_length;
|
||||
}
|
||||
|
||||
free(cmp_buf);
|
||||
return written_bytes;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
ShivanSpS - Compressed files support for FSO. Many thanks to ngld, taylor and everyone elsewho helped me in getting this done.
|
||||
|
||||
-The file header is a version, this is used to tell FSO how to decompress that file, always use 4 chars to mantain alignment.
|
||||
-The header ID can be used to add diferent revisions to LZ41 decompression system or to add other compression format supports whiout breaking compatibility.
|
||||
-The system uses a offset list to record the position of every block in file, this list, along with the number of offsets, original filesize,
|
||||
and block size, must be written by the compressor app.
|
||||
-A decoder cache is used to store the last decoded block, this ensures each block is read and decoded only once in sequential reads. This cache
|
||||
is a little bit bigger than the block size, a higher block size means less overhead added to the file, but it also means a little more ram will
|
||||
be used during decompression.
|
||||
-All this dynamic memory is assigned at cfopen() and it is cleared on cfclose().
|
||||
|
||||
................................char[4]..........(n ints)...(int)..........(int)..........(int)
|
||||
-COMPRESSED FILE DATA STUCTURE: HEADER|N BLOCKS|N OFFSETS|NUM_OFFSETS|ORIGINAL_FILESIZE|BLOCK_SIZE
|
||||
*/
|
||||
|
||||
#ifndef _CFILECOMPRESSION_H
|
||||
#define _CFILECOMPRESSION_H
|
||||
struct CFILE;
|
||||
|
||||
/*LZ41*/
|
||||
#define LZ41_FILE_HEADER 0x31345A4C // "14ZL" -> "LZ41", inverted
|
||||
#define LZ41_DECOMPRESSION_ERROR -1
|
||||
#define LZ41_MAX_BLOCKS_OVERFLOW -2
|
||||
#define LZ41_HEADER_MISMATCH -3
|
||||
#define LZ41_OFFSETS_MISMATCH -4
|
||||
/******/
|
||||
|
||||
#define COMP_HEADER_MATCH 1
|
||||
#define COMP_HEADER_MISMATCH 0
|
||||
|
||||
/*
|
||||
Returns COMP_HEADER_MATCH if header is a valid compressed file header,
|
||||
returns COMP_HEADER_MISMATCH if it dosent.
|
||||
*/
|
||||
int comp_check_header(int header);
|
||||
|
||||
/*
|
||||
This is called to generate the correct compression_info data
|
||||
after the file has been indentified as a compressed file.
|
||||
This must be done before calling any other function.
|
||||
*/
|
||||
void comp_create_ci(CFILE* cf, int header);
|
||||
|
||||
/*
|
||||
Read X bytes from the uncompressed file starting from X offset.
|
||||
Returns the amount of bytes read, and 0 or lower to indicate errors.
|
||||
*/
|
||||
size_t comp_fread(CFILE* cf, char* buffer, size_t length);
|
||||
|
||||
/*
|
||||
Returns the current uncompressed file position.
|
||||
*/
|
||||
size_t comp_ftell(CFILE* cf);
|
||||
|
||||
/*
|
||||
Returns 1 of the uncompressed file has been completely read, otherwise it returns a 0.
|
||||
*/
|
||||
int comp_feof(CFILE* cf);
|
||||
|
||||
/*
|
||||
Used to move the uncompressed file current position.
|
||||
*/
|
||||
int comp_fseek(CFILE* cf, int offset, int where);
|
||||
|
||||
#endif
|
||||
@@ -246,7 +246,7 @@ Flag exe_params[] =
|
||||
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
|
||||
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
|
||||
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
|
||||
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
|
||||
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
|
||||
{ "-profile_write_file", "Write profiling information to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
|
||||
{ "-json_profiling", "Generate JSON profiling output", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_profiling", },
|
||||
{ "-debug_window", "Enable the debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
|
||||
@@ -479,6 +479,7 @@ cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline
|
||||
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
|
||||
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
|
||||
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
|
||||
cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
|
||||
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
|
||||
cmdline_parm json_profiling("-json_profiling", NULL, AT_NONE); //Cmdline_json_profiling
|
||||
cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_video_info
|
||||
@@ -510,6 +511,7 @@ int Cmdline_reparse_mainhall = 0;
|
||||
bool Cmdline_profile_write_file = false;
|
||||
bool Cmdline_no_unfocus_pause = false;
|
||||
bool Cmdline_benchmark_mode = false;
|
||||
const char *Cmdline_pilot = nullptr;
|
||||
bool Cmdline_noninteractive = false;
|
||||
bool Cmdline_json_profiling = false;
|
||||
bool Cmdline_frame_profile = false;
|
||||
@@ -2123,6 +2125,11 @@ bool SetCmdlineParams()
|
||||
Cmdline_benchmark_mode = true;
|
||||
}
|
||||
|
||||
if (pilot_arg.found())
|
||||
{
|
||||
Cmdline_pilot = pilot_arg.str();
|
||||
}
|
||||
|
||||
if (noninteractive_arg.found())
|
||||
{
|
||||
Cmdline_noninteractive = true;
|
||||
|
||||
@@ -143,6 +143,7 @@ extern int Cmdline_reparse_mainhall;
|
||||
extern bool Cmdline_profile_write_file;
|
||||
extern bool Cmdline_no_unfocus_pause;
|
||||
extern bool Cmdline_benchmark_mode;
|
||||
extern const char *Cmdline_pilot;
|
||||
extern bool Cmdline_noninteractive;
|
||||
extern bool Cmdline_json_profiling;
|
||||
extern bool Cmdline_frame_profile;
|
||||
|
||||
@@ -1934,7 +1934,7 @@ void control_config_do_frame(float frametime)
|
||||
for (i=0; i<MOUSE_NUM_BUTTONS; i++) {
|
||||
if (mouse_down(1 << i)) {
|
||||
Assert(!(z & JOY_AXIS));
|
||||
control_config_bind_btn(z, CC_bind(CID_MOUSE, static_cast<short>(i)), 1);
|
||||
control_config_bind_btn(z, CC_bind(CID_JOY0, static_cast<short>(i)), 1);
|
||||
|
||||
strcpy_s(bound_string, Joy_button_text[i]);
|
||||
done = true;
|
||||
|
||||
+14
-13
@@ -424,17 +424,6 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
sip = &Ship_info[shipp->ship_info_index];
|
||||
vaporize = (shipp->flags[Ship::Ship_Flags::Vaporize]);
|
||||
|
||||
if ( !hull_flag ) {
|
||||
// Make vaporize debris seen from farther away
|
||||
float dist = vm_vec_dist_quick( pos, &Eye_position );
|
||||
if (vaporize) {
|
||||
dist /= 2.0f;
|
||||
}
|
||||
if ( dist > source_obj->radius * 20.0f ) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// try to maintain our soft limit
|
||||
if (hull_flag && (Num_hull_pieces >= SOFT_LIMIT_DEBRIS_PIECES)) {
|
||||
// cause oldest hull debris chunk to blow up
|
||||
@@ -480,6 +469,18 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
|
||||
float radius = submodel_get_radius(db->model_num, db->submodel_num);
|
||||
|
||||
// if its generic, maybe cull it if its too small and far
|
||||
if (!hull_flag) {
|
||||
float dist = vm_vec_dist_quick(pos, &Eye_position);
|
||||
// Make vaporize debris seen from farther away
|
||||
if (vaporize) {
|
||||
dist /= 2.0f;
|
||||
}
|
||||
if (dist > radius * 200.0f) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//WMC - We must survive until now, at least.
|
||||
db->must_survive_until = timestamp();
|
||||
|
||||
@@ -560,7 +561,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
|
||||
db->next_fireball = timestamp_rand(500,2000); //start one 1/2 - 2 secs later
|
||||
|
||||
if ( pos == NULL )
|
||||
if ( pos == nullptr )
|
||||
pos = &source_obj->pos;
|
||||
|
||||
flagset<Object::Object_Flags> default_flags;
|
||||
@@ -579,7 +580,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
objnum = obj_create( OBJ_DEBRIS, parent_objnum, n, &orient, pos, radius, default_flags);
|
||||
if ( objnum == -1 ) {
|
||||
mprintf(("Couldn't create debris object -- out of object slots\n"));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
db->objnum = objnum;
|
||||
|
||||
@@ -12,7 +12,7 @@ layout (std140) uniform genericData {
|
||||
vec3 fog_color;
|
||||
float fog_start;
|
||||
|
||||
float fog_scale;
|
||||
float fog_density;
|
||||
float zNear;
|
||||
float zFar;
|
||||
};
|
||||
@@ -31,9 +31,7 @@ void main()
|
||||
if (isinf(view_depth)) {
|
||||
fragOut0.rgb = color_in.rgb;
|
||||
} else {
|
||||
// This is the same formula that is also used by the main shader
|
||||
float fog_dist = clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
|
||||
|
||||
float fog_dist = clamp(1 - pow(fog_density, view_depth - fog_start) , 0.0, 1.0);
|
||||
vec3 finalFogColor = srgb_to_linear(fog_color);
|
||||
|
||||
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "graphics/tmapper.h"
|
||||
#include "localization/localize.h"
|
||||
#include "model/model.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "object/object.h"
|
||||
#include "options/Option.h"
|
||||
#include "parse/parselo.h"
|
||||
@@ -286,11 +287,13 @@ static void parse_fireball_tbl(const char *table_filename)
|
||||
}
|
||||
}
|
||||
|
||||
bool first_time;
|
||||
// now select our entry accordingly...
|
||||
// are we using a previous entry?
|
||||
if (existing_idx >= 0)
|
||||
{
|
||||
fi = &Fireball_info[existing_idx];
|
||||
first_time = false;
|
||||
}
|
||||
// we are creating a new entry, so set some defaults
|
||||
else
|
||||
@@ -314,6 +317,7 @@ static void parse_fireball_tbl(const char *table_filename)
|
||||
fireball_set_default_warp_attributes(Num_fireball_types);
|
||||
|
||||
Num_fireball_types++;
|
||||
first_time = true;
|
||||
}
|
||||
|
||||
// copy over what we already parsed
|
||||
@@ -321,6 +325,7 @@ static void parse_fireball_tbl(const char *table_filename)
|
||||
strcpy_s(fi->unique_id, unique_id);
|
||||
strcpy_s(fi->lod[0].filename, fireball_filename);
|
||||
|
||||
|
||||
// Do we have a LOD num?
|
||||
if (optional_string("$LOD:"))
|
||||
{
|
||||
@@ -328,6 +333,9 @@ static void parse_fireball_tbl(const char *table_filename)
|
||||
|
||||
if (fi->lod_count > MAX_FIREBALL_LOD)
|
||||
fi->lod_count = MAX_FIREBALL_LOD;
|
||||
} else if (first_time) {
|
||||
//assume a LOD of at least 1
|
||||
fi->lod_count = 1;
|
||||
}
|
||||
|
||||
// check for particular lighting color
|
||||
@@ -1037,19 +1045,24 @@ void fireball_render(object* obj, model_draw_list *scene)
|
||||
|
||||
if ( fb->current_bitmap < 0 )
|
||||
return;
|
||||
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_fireballs)
|
||||
alpha *= neb2_get_fog_visibility(&obj->pos, NEB_FOG_VISIBILITY_MULT_FIREBALL(obj->radius));
|
||||
|
||||
g3_transfer_vertex(&p, &obj->pos);
|
||||
|
||||
switch ( fb->fireball_render_type ) {
|
||||
|
||||
case FIREBALL_MEDIUM_EXPLOSION: {
|
||||
batching_add_volume_bitmap(fb->current_bitmap, &p, fb->orient, obj->radius);
|
||||
batching_add_volume_bitmap(fb->current_bitmap, &p, fb->orient, obj->radius, alpha);
|
||||
}
|
||||
break;
|
||||
|
||||
case FIREBALL_LARGE_EXPLOSION: {
|
||||
// Make the big explosions rotate with the viewer.
|
||||
batching_add_volume_bitmap_rotated(fb->current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius);
|
||||
batching_add_volume_bitmap_rotated(fb->current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius, alpha);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
|
||||
|
||||
g3_transfer_vertex( &verts[4], &vecs[4] );
|
||||
|
||||
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? (1.0f - neb2_get_fog_intensity(obj)) : 1.0f;
|
||||
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? neb2_get_fog_visibility(obj) : 1.0f;
|
||||
|
||||
//batch_add_bitmap(warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
|
||||
batching_add_bitmap(warp_glow_bitmap, &verts[4], 0, r, alpha);
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "scripting/scripting.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "utils/boost/hash_combine.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
|
||||
#ifdef WITH_OPENGL
|
||||
#include "graphics/opengl/gropengl.h"
|
||||
@@ -2547,7 +2548,8 @@ void gr_flip(bool execute_scripting)
|
||||
executor::OnFrameExecutor->process();
|
||||
|
||||
// m!m avoid running CHA_ONFRAME when the "Quit mission" popup is shown. See mantis 2446 for reference
|
||||
if (execute_scripting && !popup_active()) {
|
||||
// Cyborg - A similar bug will occur when a mission is restarted so check for that, too.
|
||||
if (execute_scripting && !popup_active() && GameState_Stack_Valid() && !((gameseq_get_state() == GS_STATE_GAME_PLAY) && !(Game_mode & GM_IN_MISSION))) {
|
||||
TRACE_SCOPE(tracing::LuaOnFrame);
|
||||
|
||||
// WMC - Do conditional hooks. Yippee!
|
||||
|
||||
@@ -301,8 +301,8 @@ void gr_opengl_deferred_lighting_finish()
|
||||
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Scene_emissive_texture);
|
||||
GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_depth_texture);
|
||||
|
||||
float fog_near, fog_far;
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, nullptr);
|
||||
float fog_near, fog_far, fog_density;
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density);
|
||||
unsigned char r, g, b;
|
||||
neb2_get_fog_color(&r, &g, &b);
|
||||
|
||||
@@ -311,7 +311,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
|
||||
opengl_set_generic_uniform_data<graphics::generic_data::fog_data>([&](graphics::generic_data::fog_data* data) {
|
||||
data->fog_start = fog_near;
|
||||
data->fog_scale = 1.0f / (fog_far - fog_near);
|
||||
data->fog_density = fog_density;
|
||||
data->fog_color.xyz.x = r / 255.f;
|
||||
data->fog_color.xyz.y = g / 255.f;
|
||||
data->fog_color.xyz.z = b / 255.f;
|
||||
|
||||
@@ -284,7 +284,7 @@ struct fog_data {
|
||||
vec3d fog_color;
|
||||
float fog_start;
|
||||
|
||||
float fog_scale;
|
||||
float fog_density;
|
||||
float zNear;
|
||||
float zFar;
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ void HudGaugeReticle::initBitmaps(char *fname)
|
||||
{
|
||||
crosshair.first_frame = bm_load_animation(fname, &crosshair.num_frames);
|
||||
if (crosshair.first_frame < 0) {
|
||||
mprintf(("Cannot load hud ani: %s\n", fname));
|
||||
Warning(LOCATION, "Cannot load hud ani: %s\n", fname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ void HudGaugeThrottle::initBitmaps(char *fname)
|
||||
throttle_frames.first_frame = bm_load_animation(fname, &throttle_frames.num_frames);
|
||||
|
||||
if (throttle_frames.first_frame < 0) {
|
||||
mprintf(("Cannot load hud ani: %s\n", fname));
|
||||
Warning(LOCATION, "Cannot load hud ani: %s\n", fname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,17 +748,17 @@ void HudGaugeThreatIndicator::initBitmaps(char *fname_arc, char *fname_laser, ch
|
||||
{
|
||||
threat_arc.first_frame = bm_load_animation(fname_arc, &threat_arc.num_frames);
|
||||
if (threat_arc.first_frame < 0) {
|
||||
mprintf(("Cannot load hud ani: %s\n", fname_arc));
|
||||
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_arc);
|
||||
}
|
||||
|
||||
laser_warn.first_frame = bm_load_animation(fname_laser, &laser_warn.num_frames);
|
||||
if (laser_warn.first_frame < 0) {
|
||||
mprintf(("Cannot load hud ani: %s\n", fname_laser));
|
||||
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_laser);
|
||||
}
|
||||
|
||||
lock_warn.first_frame = bm_load_animation(fname_lock, &lock_warn.num_frames);
|
||||
if (lock_warn.first_frame < 0) {
|
||||
mprintf(("Cannot load hud ani: %s\n", fname_lock));
|
||||
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -692,15 +692,6 @@ void process_debug_keys(int k)
|
||||
case KEY_DEBUGGED + KEY_H:
|
||||
hud_target_toggle_hidden_from_sensors();
|
||||
break;
|
||||
|
||||
case KEY_DEBUGGED + KEY_F:
|
||||
extern int wacky_scheme;
|
||||
if(wacky_scheme == 3){
|
||||
wacky_scheme = 0;
|
||||
} else {
|
||||
wacky_scheme++;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_DEBUGGED + KEY_ALTED + KEY_F:
|
||||
Framerate_delay += 10;
|
||||
|
||||
@@ -308,11 +308,22 @@ void LabRenderer::useBackground(const SCP_string& mission_name) {
|
||||
gr_set_ambient_light(ambient_light_level & 0xff, (ambient_light_level >> 8) & 0xff,
|
||||
(ambient_light_level >> 16) & 0xff);
|
||||
|
||||
strcpy_s(Neb2_texture_name, "Eraseme3");
|
||||
strcpy_s(Neb2_texture_name, "");
|
||||
Neb2_poof_flags = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5));
|
||||
bool nebula = false;
|
||||
if (optional_string("+Neb2:")) {
|
||||
nebula = true;
|
||||
stuff_string(Neb2_texture_name, F_NAME, MAX_FILENAME_LEN);
|
||||
} else if (optional_string("+Neb2Color:")) {
|
||||
nebula = true;
|
||||
int neb_colors[3];
|
||||
stuff_int_list(neb_colors, 3, RAW_INTEGER_TYPE);
|
||||
Neb2_fog_color[0] = (ubyte)neb_colors[0];
|
||||
Neb2_fog_color[1] = (ubyte)neb_colors[1];
|
||||
Neb2_fog_color[2] = (ubyte)neb_colors[2];
|
||||
}
|
||||
|
||||
if (nebula){
|
||||
required_string("+Neb2Flags:");
|
||||
stuff_int(&Neb2_poof_flags);
|
||||
|
||||
|
||||
@@ -955,8 +955,18 @@ const char *XSTR(const char *str, int index, bool force_lookup)
|
||||
// return translation of string
|
||||
if (Xstr_table[index].str)
|
||||
return Xstr_table[index].str;
|
||||
#ifndef NDEBUG
|
||||
else
|
||||
mprintf(("No XSTR entry in strings.tbl for index %d\n", index));
|
||||
{
|
||||
// make sure missing strings are only logged once
|
||||
static SCP_unordered_set<int> Warned_xstr_indexes;
|
||||
if (Warned_xstr_indexes.count(index) == 0)
|
||||
{
|
||||
Warned_xstr_indexes.insert(index);
|
||||
mprintf(("No XSTR entry in strings.tbl for index %d\n", index));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -413,6 +413,12 @@ void player_select_do()
|
||||
gr_set_bitmap(Player_select_background_bitmap);
|
||||
gr_bitmap(0,0,GR_RESIZE_MENU);
|
||||
|
||||
//skip this if pilot is given through cmdline, assuming single-player
|
||||
if (Cmdline_pilot) {
|
||||
player_finish_select(Cmdline_pilot, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// press the accept button
|
||||
if (Player_select_autoaccept) {
|
||||
Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].button.press_button();
|
||||
@@ -1444,7 +1450,7 @@ void player_finish_select(const char* callsign, bool is_multi) {
|
||||
|
||||
// now read in a the pilot data
|
||||
if ( !Pilot.load_player(callsign, Player) ) {
|
||||
Error(LOCATION,"Couldn't load pilot file, bailing");
|
||||
Error(LOCATION,"Couldn't load pilot file for pilot \"%s\", bailing", callsign);
|
||||
Player = nullptr;
|
||||
} else {
|
||||
// NOTE: this may fail if there is no current campaign, it's not fatal
|
||||
|
||||
@@ -25,13 +25,14 @@ namespace Mission {
|
||||
Red_alert, // a red-alert mission - Goober5000
|
||||
Scramble, // a scramble mission - Goober5000
|
||||
No_builtin_command, // turns off Command without turning off pilots - Karajorma
|
||||
Player_start_ai, // Player Starts mission under AI Control (NOT MULTI COMPATABLE) - Kazan
|
||||
Player_start_ai, // Player starts mission under AI Control (NOT MULTI COMPATABLE) - Kazan
|
||||
All_attack, // all teams at war - Goober5000
|
||||
Use_ap_cinematics, // use autopilot cinematics - Kazan
|
||||
Deactivate_ap, // deactivate autopilot - KeldorKatarn (patch approved by Kazan)
|
||||
Always_show_goals, // Show the mission goals, even for training missions - Karajorma
|
||||
End_to_mainhall, // Return to the mainhall after debrief - niffiwan
|
||||
Override_hashcommand, // Override #Command with the Command info in Mission Specs - Goober5000
|
||||
Player_start_chase_view, // Player starts mission in chase view - Goober5000
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
@@ -5065,6 +5065,9 @@ void parse_event(mission * /*pm*/)
|
||||
}
|
||||
}
|
||||
|
||||
// Need to set this to zero so that we don't accidentally reuse old data.
|
||||
event->flags = 0;
|
||||
|
||||
if (optional_string("+Event Flags:")) {
|
||||
parse_string_flag_list(&event->flags, Mission_event_flags, Num_mission_event_flags);
|
||||
}
|
||||
@@ -5485,11 +5488,21 @@ void parse_bitmaps(mission *pm)
|
||||
Mission_palette = 1;
|
||||
|
||||
// neb2 info
|
||||
strcpy_s(Neb2_texture_name, "Eraseme3");
|
||||
strcpy_s(Neb2_texture_name, "");
|
||||
Neb2_poof_flags = ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
|
||||
if(optional_string("+Neb2:")){
|
||||
bool nebula = false;
|
||||
if (optional_string("+Neb2:")) {
|
||||
nebula = true;
|
||||
stuff_string(Neb2_texture_name, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
} else if (optional_string("+Neb2Color:")) {
|
||||
nebula = true;
|
||||
int neb_colors[3];
|
||||
stuff_int_list(neb_colors, 3, RAW_INTEGER_TYPE);
|
||||
Neb2_fog_color[0] = (ubyte)neb_colors[0];
|
||||
Neb2_fog_color[1] = (ubyte)neb_colors[1];
|
||||
Neb2_fog_color[2] = (ubyte)neb_colors[2];
|
||||
}
|
||||
if (nebula) {
|
||||
required_string("+Neb2Flags:");
|
||||
stuff_int(&Neb2_poof_flags);
|
||||
|
||||
@@ -8164,20 +8177,8 @@ void mission_process_alt_types()
|
||||
// truncate at a single hash
|
||||
end_string_at_first_hash_symbol(Mission_alt_types[i], true);
|
||||
|
||||
// consolidate double hashes
|
||||
auto src = Mission_alt_types[i];
|
||||
auto dest = src;
|
||||
while (*src)
|
||||
{
|
||||
if (*src == '#' && *(src + 1) == '#')
|
||||
dest--;
|
||||
|
||||
++src;
|
||||
++dest;
|
||||
|
||||
if (src != dest)
|
||||
*dest = *src;
|
||||
}
|
||||
// ## -> #
|
||||
consolidate_double_characters(Mission_alt_types[i], '#');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,10 @@ bool Chase_view_default;
|
||||
SCP_vector<gr_capability> Required_render_ext;
|
||||
float Weapon_SS_Threshold_Turret_Inaccuracy;
|
||||
bool Render_player_mflash;
|
||||
bool Neb_affects_beams;
|
||||
bool Neb_affects_weapons;
|
||||
bool Neb_affects_particles;
|
||||
bool Neb_affects_fireballs;
|
||||
|
||||
SCP_vector<std::pair<SCP_string, gr_capability>> req_render_ext_pairs = {
|
||||
std::make_pair("BPTC Texture Compression", CAPABILITY_BPTC)
|
||||
@@ -377,6 +381,22 @@ void parse_mod_table(const char *filename)
|
||||
stuff_boolean(&Render_player_mflash);
|
||||
}
|
||||
|
||||
if (optional_string("$Beams affected by nebula visibility:")) {
|
||||
stuff_boolean(&Neb_affects_beams);
|
||||
}
|
||||
|
||||
if (optional_string("$Weapons affected by nebula visibility:")) {
|
||||
stuff_boolean(&Neb_affects_weapons);
|
||||
}
|
||||
|
||||
if (optional_string("$Particles affected by nebula visibility:")) {
|
||||
stuff_boolean(&Neb_affects_particles);
|
||||
}
|
||||
|
||||
if (optional_string("$Fireballs affected by nebula visibility:")) {
|
||||
stuff_boolean(&Neb_affects_fireballs);
|
||||
}
|
||||
|
||||
optional_string("#NETWORK SETTINGS");
|
||||
|
||||
if (optional_string("$FS2NetD port:")) {
|
||||
@@ -664,4 +684,8 @@ void mod_table_reset()
|
||||
Required_render_ext.clear();
|
||||
Weapon_SS_Threshold_Turret_Inaccuracy = 0.7f; // Defaults to retail value of 0.7 --wookieejedi
|
||||
Render_player_mflash = false;
|
||||
Neb_affects_beams = false;
|
||||
Neb_affects_weapons = false;
|
||||
Neb_affects_particles = false;
|
||||
Neb_affects_fireballs = false;
|
||||
}
|
||||
@@ -58,6 +58,10 @@ extern bool Framerate_independent_turning;
|
||||
extern bool Ai_respect_tabled_turntime_rotdamp;
|
||||
extern bool Chase_view_default;
|
||||
extern bool Render_player_mflash;
|
||||
extern bool Neb_affects_beams;
|
||||
extern bool Neb_affects_weapons;
|
||||
extern bool Neb_affects_particles;
|
||||
extern bool Neb_affects_fireballs;
|
||||
|
||||
void mod_table_init();
|
||||
|
||||
|
||||
+3
-3
@@ -159,7 +159,7 @@ public:
|
||||
vec3d turret_norm; // direction this turret faces (i.e. the normal to the turret base, or the center of the field of view)
|
||||
float turret_fov; // dot of turret_norm:vec_to_enemy > this means can see
|
||||
float turret_max_fov; // dot of turret_norm:vec_to_enemy <= this means barrels can elevate up to the target
|
||||
float turret_y_fov; // turret's base's fov
|
||||
float turret_base_fov; // turret's base's fov
|
||||
int turret_num_firing_points; // number of firing points on this turret
|
||||
vec3d turret_firing_point[MAX_TFP]; // in parent object's reference frame, point from which to fire.
|
||||
int turret_gun_sobj; // Which subobject in this model the firing points are linked to.
|
||||
@@ -914,7 +914,7 @@ extern int modelstats_num_sortnorms;
|
||||
#endif
|
||||
|
||||
// Tries to move joints so that the turret points to the point dst.
|
||||
extern int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, model_subsystem *turret, vec3d *dst, bool reset = false);
|
||||
extern int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_subsys *ss, vec3d *dst, bool reset = false);
|
||||
|
||||
// Rotates the angle of a submodel. Use this so the right unlocked axis
|
||||
// gets stuffed.
|
||||
@@ -962,7 +962,7 @@ void model_init_submodel_axis_pt(polymodel *pm, polymodel_instance *pmi, int sub
|
||||
// return the point in 3-space in outpnt.
|
||||
extern void model_find_world_dir(vec3d *out_dir, const vec3d *in_dir, int model_num, int submodel_num, const matrix *objorient);
|
||||
extern void model_find_world_dir(vec3d *out_dir, const vec3d *in_dir, const polymodel *pm, int submodel_num, const matrix *objorient);
|
||||
extern void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, int model_instance_num, int submodel_num, const matrix *objorient);
|
||||
extern void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, int model_instance_num, int submodel_num, const matrix *objorient, bool use_submodel_parent = false);
|
||||
extern void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const matrix *objorient);
|
||||
|
||||
// Clears all the submodel instances stored in a model to their defaults.
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Model {
|
||||
Fire_on_target, // prevents turret from firing unless it is pointing at the firingpoints are pointing at the target
|
||||
No_ss_targeting, // toggles the subsystem targeting for the turret
|
||||
Turret_reset_idle, // makes turret reset to their initial position if the target is out of field of view
|
||||
Turret_alt_math, // tells the game to use additional calculations should turret have a defined y fov
|
||||
Turret_restricted_fov, // tells the game to use additional calculations should turret have a limited base fov or elevation
|
||||
Dum_rotates, // Bobboau
|
||||
Carry_shockwave, // subsystem - even with 'carry no damage' flag - will carry shockwave damage to the hull
|
||||
Allow_landing, // This subsystem can be landed on
|
||||
|
||||
@@ -3727,10 +3727,9 @@ void submodel_rotate(bsp_info *sm, submodel_instance *smi)
|
||||
// Tries to move joints so that the turret points to the point dst.
|
||||
// turret1 is the angles of the turret, turret2 is the angles of the gun from turret
|
||||
// Returns 1 if rotated gun, 0 if no gun to rotate (rotation handled by AI)
|
||||
int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, model_subsystem *turret, vec3d *dst, bool reset)
|
||||
int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_subsys *ss, vec3d *dst, bool reset)
|
||||
{
|
||||
ship *shipp = &Ships[objp->instance];
|
||||
ship_subsys *ss = ship_get_subsys(shipp, turret->subobj_name);
|
||||
model_subsystem *turret = ss->system_info;
|
||||
|
||||
// This should not happen
|
||||
if ( turret->turret_gun_sobj < 0 || turret->subobj_num == turret->turret_gun_sobj ) {
|
||||
@@ -3813,7 +3812,7 @@ int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, model
|
||||
}
|
||||
}
|
||||
|
||||
if (turret->flags[Model::Subsystem_Flags::Turret_alt_math])
|
||||
if (turret->flags[Model::Subsystem_Flags::Turret_restricted_fov])
|
||||
limited_base_rotation = true;
|
||||
|
||||
//------------
|
||||
@@ -4237,11 +4236,11 @@ void model_find_world_dir(vec3d *out_dir, const vec3d *in_dir, const polymodel *
|
||||
}
|
||||
|
||||
// the same as model_find_world_dir - just taking model instance data into account
|
||||
void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, int model_instance_num, int submodel_num, const matrix *objorient)
|
||||
void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, int model_instance_num, int submodel_num, const matrix *objorient, bool use_submodel_parent)
|
||||
{
|
||||
auto pmi = model_get_instance(model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
model_instance_find_world_dir(out_dir, in_dir, pm, pmi, submodel_num, objorient);
|
||||
model_instance_find_world_dir(out_dir, in_dir, pm, pmi, use_submodel_parent ? pm->submodel[submodel_num].parent : submodel_num, objorient);
|
||||
}
|
||||
|
||||
void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const matrix *objorient)
|
||||
@@ -5370,7 +5369,7 @@ void model_subsystem::reset()
|
||||
|
||||
turret_fov = 0;
|
||||
turret_max_fov = 0;
|
||||
turret_y_fov = 0;
|
||||
turret_base_fov = 0;
|
||||
turret_num_firing_points = 0;
|
||||
for (auto it = std::begin(turret_firing_point); it != std::end(turret_firing_point); ++it)
|
||||
it->xyz.x = it->xyz.y = it->xyz.z = 0.0f;
|
||||
|
||||
@@ -1572,7 +1572,7 @@ void submodel_render_queue(model_render_params *render_info, model_draw_list *sc
|
||||
if (objnum >= 0)
|
||||
obj = &Objects[objnum];
|
||||
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, obj);
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, nullptr, obj);
|
||||
unsigned char r, g, b;
|
||||
neb2_get_fog_color(&r, &g, &b);
|
||||
|
||||
@@ -1685,7 +1685,7 @@ void model_render_glowpoint(int point_num, vec3d *pos, matrix *orient, glow_poin
|
||||
//vec3d npnt;
|
||||
//vm_vec_add(&npnt, &loc_offset, pos);
|
||||
|
||||
d *= (1.0f - neb2_get_fog_intensity(&world_pnt));
|
||||
d *= neb2_get_fog_visibility(&world_pnt, NEB_FOG_VISIBILITY_MULT_GLOWPOINT);
|
||||
w *= 1.5; //make it bigger in a nebula
|
||||
}
|
||||
|
||||
@@ -2145,7 +2145,7 @@ void model_queue_render_thrusters(model_render_params *interp, polymodel *pm, in
|
||||
vm_vec_unrotate(&npnt, &gpt->pnt, orient);
|
||||
vm_vec_add2(&npnt, pos);
|
||||
|
||||
fog_int = (1.0f - (neb2_get_fog_intensity(&npnt)));
|
||||
fog_int = neb2_get_fog_visibility(&npnt, NEB_FOG_VISIBILITY_MULT_THRUSTER);
|
||||
|
||||
if (fog_int > 1.0f)
|
||||
fog_int = 1.0f;
|
||||
@@ -2645,7 +2645,7 @@ void model_render_queue(model_render_params* interp, model_draw_list* scene, int
|
||||
// if we're in nebula mode, fog everything except for the warp holes and other non-fogged models
|
||||
if ( (The_mission.flags[Mission::Mission_Flags::Fullneb]) && (Neb2_render_mode != NEB2_RENDER_NONE) && !(model_flags & MR_NO_FOGGING) ) {
|
||||
float fog_near = 10.0f, fog_far = 1000.0f;
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, objp);
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, nullptr, objp);
|
||||
|
||||
unsigned char r, g, b;
|
||||
neb2_get_fog_color(&r, &g, &b);
|
||||
|
||||
+48
-88
@@ -35,9 +35,7 @@
|
||||
|
||||
bool Nebula_sexp_used = false;
|
||||
|
||||
static ubyte Neb2_fog_color_r = 0;
|
||||
static ubyte Neb2_fog_color_g = 0;
|
||||
static ubyte Neb2_fog_color_b = 0;
|
||||
ubyte Neb2_fog_color[3] = { 0,0,0 };
|
||||
|
||||
static ubyte *Neb2_htl_fog_data = NULL;
|
||||
|
||||
@@ -159,6 +157,10 @@ float Neb2_awacs = -1.0f;
|
||||
float Neb2_fog_near_mult = 1.0f;
|
||||
float Neb2_fog_far_mult = 1.0f;
|
||||
|
||||
|
||||
// this is the percent of visibility at the fog far distance
|
||||
const float NEB_FOG_FAR_PCT = 0.1f;
|
||||
|
||||
// how many "slices" are in the current player nebuls
|
||||
int Neb2_slices = 5;
|
||||
|
||||
@@ -168,8 +170,7 @@ neb2_detail Neb2_detail[MAX_DETAIL_LEVEL] = {
|
||||
{ // lowest detail level
|
||||
0.575f, // max alpha for this detail level in Glide
|
||||
0.71f, // max alpha for this detail level in D3d
|
||||
0.13f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
150.0f, 150.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
|
||||
0.013f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
510.0f, // total dimension of player poof cube
|
||||
50.0f, // inner radius of the player poof cube
|
||||
250.0f, // outer radius of the player pood cube
|
||||
@@ -179,8 +180,7 @@ neb2_detail Neb2_detail[MAX_DETAIL_LEVEL] = {
|
||||
{ // 2nd lowest detail level
|
||||
0.575f, // max alpha for this detail level in Glide
|
||||
0.71f, // max alpha for this detail level in D3d
|
||||
0.125f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
300.0f, 300.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
|
||||
0.0125f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
550.0f, // total dimension of player poof cube
|
||||
100.0f, // inner radius of the player poof cube
|
||||
250.0f, // outer radius of the player pood cube
|
||||
@@ -190,8 +190,7 @@ neb2_detail Neb2_detail[MAX_DETAIL_LEVEL] = {
|
||||
{ // 2nd highest detail level
|
||||
0.575f, // max alpha for this detail level in Glide
|
||||
0.71f, // max alpha for this detail level in D3d
|
||||
0.1f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
300.0f, 300.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
|
||||
0.01f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
550.0f, // total dimension of player poof cube
|
||||
150.0f, // inner radius of the player poof cube
|
||||
250.0f, // outer radius of the player pood cube
|
||||
@@ -201,8 +200,7 @@ neb2_detail Neb2_detail[MAX_DETAIL_LEVEL] = {
|
||||
{ // higest detail level
|
||||
0.475f, // max alpha for this detail level in Glide
|
||||
0.575f, // max alpha for this detail level in D3d
|
||||
0.05f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
200.0f, 200.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
|
||||
0.005f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
750.0f, // total dimension of player poof cube
|
||||
200.0f, // inner radius of the player poof cube
|
||||
360.0f, // outer radius of the player pood cube
|
||||
@@ -339,9 +337,9 @@ void neb2_set_detail_level(int level)
|
||||
|
||||
void neb2_get_fog_color(ubyte *r, ubyte *g, ubyte *b)
|
||||
{
|
||||
if (r) *r = Neb2_fog_color_r;
|
||||
if (g) *g = Neb2_fog_color_g;
|
||||
if (b) *b = Neb2_fog_color_b;
|
||||
if (r) *r = Neb2_fog_color[0];
|
||||
if (g) *g = Neb2_fog_color[1];
|
||||
if (b) *b = Neb2_fog_color[2];
|
||||
}
|
||||
|
||||
void neb2_level_init()
|
||||
@@ -373,13 +371,13 @@ void neb2_post_level_init()
|
||||
return;
|
||||
}
|
||||
|
||||
// Set a default colour just in case something goes wrong
|
||||
Neb2_fog_color_r = 30;
|
||||
Neb2_fog_color_g = 52;
|
||||
Neb2_fog_color_b = 157;
|
||||
|
||||
// OK, lets try something a bit more interesting
|
||||
if (strlen(Neb2_texture_name)) {
|
||||
// Set a default colour just in case something goes wrong
|
||||
Neb2_fog_color[0] = 30;
|
||||
Neb2_fog_color[1] = 52;
|
||||
Neb2_fog_color[2] = 157;
|
||||
|
||||
Neb2_htl_fog_data = new ubyte[768];
|
||||
|
||||
if ((Neb2_htl_fog_data != NULL) && (pcx_read_header(Neb2_texture_name, NULL, NULL, NULL, NULL, Neb2_htl_fog_data) == PCX_ERROR_NONE)) {
|
||||
@@ -395,12 +393,12 @@ void neb2_post_level_init()
|
||||
}
|
||||
|
||||
if (pcount > 0) {
|
||||
Neb2_fog_color_r = (ubyte)(r / pcount);
|
||||
Neb2_fog_color_g = (ubyte)(g / pcount);
|
||||
Neb2_fog_color_b = (ubyte)(b / pcount);
|
||||
Neb2_fog_color[0] = (ubyte)(r / pcount);
|
||||
Neb2_fog_color[1] = (ubyte)(g / pcount);
|
||||
Neb2_fog_color[2] = (ubyte)(b / pcount);
|
||||
} else {
|
||||
// it's just black
|
||||
Neb2_fog_color_r = Neb2_fog_color_g = Neb2_fog_color_b = 0;
|
||||
Neb2_fog_color[0] = Neb2_fog_color[1] = Neb2_fog_color[2] = 0;
|
||||
}
|
||||
|
||||
// done, now free up the palette data
|
||||
@@ -555,7 +553,7 @@ DCF(neb_skip, "Toggles culling of objects obscured by nebula")
|
||||
}
|
||||
int neb2_skip_render(object *objp, float z_depth)
|
||||
{
|
||||
float fog_near, fog_far;
|
||||
float fog_near, fog_far, fog_density;
|
||||
|
||||
// if we're never skipping
|
||||
if (!neb_skip_opt) {
|
||||
@@ -563,7 +561,8 @@ int neb2_skip_render(object *objp, float z_depth)
|
||||
}
|
||||
|
||||
// get near and far fog values based upon object type and rendering mode
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, objp);
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density);
|
||||
float fog = pow(fog_density, z_depth - fog_near + objp->radius);
|
||||
|
||||
// by object type
|
||||
switch( objp->type ) {
|
||||
@@ -579,34 +578,15 @@ int neb2_skip_render(object *objp, float z_depth)
|
||||
// any weapon over 500 meters away
|
||||
// Use the "far" distance multiplier here
|
||||
case OBJ_WEAPON:
|
||||
if (z_depth >= 500.0f * Neb2_fog_far_mult) {
|
||||
if (fog < 0.05f) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// any small ship over the fog limit, or any cruiser 50% further than the fog limit
|
||||
// any ship less than 3% visible at their closest point
|
||||
case OBJ_SHIP:
|
||||
ship_info *sip;
|
||||
if ( (objp->instance >= 0) && (Ships[objp->instance].ship_info_index >= 0) ) {
|
||||
sip = &Ship_info[Ships[objp->instance].ship_info_index];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// small ships over the fog limit by a small factor
|
||||
if ( (sip->is_small_ship()) && (z_depth >= (fog_far * 1.5f)) ) {
|
||||
if (fog < 0.03f)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// big ships
|
||||
if ( (sip->is_big_ship()) && (z_depth >= (fog_far * 2.0f)) ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// huge ships
|
||||
if ( (sip->is_huge_ship()) && (z_depth >= (fog_far * 3.0f)) ) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// any fireball over the fog limit for small ships
|
||||
@@ -619,11 +599,10 @@ int neb2_skip_render(object *objp, float z_depth)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
// any asteroids 50% farther than the fog limit for small ships
|
||||
// any asteroid less than 3% visible at their closest point
|
||||
case OBJ_ASTEROID:
|
||||
if (z_depth >= (fog_far * 1.5f)) {
|
||||
if (fog < 0.03f)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// hmmm. unknown object type - should probably let it through
|
||||
@@ -709,8 +688,8 @@ float neb2_get_alpha_2shell(float inner_radius, float outer_radius, float magic_
|
||||
float neb2_get_alpha_offscreen(float sx, float sy, float incoming_alpha)
|
||||
{
|
||||
float alpha = 0.0f;
|
||||
float per_pixel_x = incoming_alpha / (float)Nd->break_x;
|
||||
float per_pixel_y = incoming_alpha / (float)Nd->break_y;
|
||||
float per_pixel_x = incoming_alpha / (float)gr_screen.max_w;
|
||||
float per_pixel_y = incoming_alpha / (float)gr_screen.max_h;
|
||||
int off_x = ((sx < 0.0f) || (sx > (float)gr_screen.max_w));
|
||||
int off_y = ((sy < 0.0f) || (sy > (float)gr_screen.max_h));
|
||||
float off_x_amount = 0.0f;
|
||||
@@ -1185,7 +1164,7 @@ void neb2_get_fog_values(float *fnear, float *ffar, object *objp)
|
||||
}
|
||||
|
||||
// This version of the function allows for global adjustment to fog values
|
||||
void neb2_get_adjusted_fog_values(float *fnear, float *ffar, object *objp)
|
||||
void neb2_get_adjusted_fog_values(float *fnear, float *ffar, float *fdensity, object *objp)
|
||||
{
|
||||
neb2_get_fog_values(fnear, ffar, objp);
|
||||
|
||||
@@ -1196,33 +1175,36 @@ void neb2_get_adjusted_fog_values(float *fnear, float *ffar, object *objp)
|
||||
// Avoide divide-by-zero
|
||||
if ((*fnear - *ffar) == 0)
|
||||
*ffar = *fnear + 1.0f;
|
||||
|
||||
if (fdensity != nullptr)
|
||||
*fdensity = powf(NEB_FOG_FAR_PCT, 1 / (*ffar - *fnear));
|
||||
}
|
||||
|
||||
float nNf_near, nNf_far;
|
||||
float nNf_near, nNf_density;
|
||||
// given a position in space, return a value from 0.0 to 1.0 representing the fog level
|
||||
float neb2_get_fog_intensity(object *obj)
|
||||
float neb2_get_fog_visibility(object *obj)
|
||||
{
|
||||
float pct;
|
||||
float fog_far;
|
||||
|
||||
// get near and far fog values based upon object type and rendering mode
|
||||
neb2_get_adjusted_fog_values(&nNf_near, &nNf_far, obj);
|
||||
neb2_get_adjusted_fog_values(&nNf_near, &fog_far, &nNf_density, obj);
|
||||
|
||||
// get the fog pct
|
||||
pct = vm_vec_dist_quick(&Eye_position, &obj->pos) / (nNf_far - nNf_near);
|
||||
|
||||
CLAMP(pct, 0.0f, 1.0f);
|
||||
float pct = pow(nNf_density, vm_vec_dist(&Eye_position, &obj->pos) - nNf_near);
|
||||
|
||||
CLAMP(pct, 0.0f, 1.0f);
|
||||
|
||||
return pct;
|
||||
}
|
||||
|
||||
//this only gets called after the one above has been called as it assumes you have set the near and far planes properly
|
||||
//doun't use this outside of ship rendering
|
||||
float neb2_get_fog_intensity(vec3d *pos)
|
||||
//don't use this outside of ship rendering
|
||||
float neb2_get_fog_visibility(vec3d *pos, float distance_mult)
|
||||
{
|
||||
float pct;
|
||||
|
||||
// get the fog pct
|
||||
pct = vm_vec_dist_quick(&Eye_position, pos) / ((nNf_far*2) - nNf_near);
|
||||
pct = powf(nNf_density, (vm_vec_dist(&Eye_position, pos) - nNf_near) / distance_mult);
|
||||
|
||||
CLAMP(pct, 0.0f, 1.0f);
|
||||
|
||||
@@ -1302,9 +1284,6 @@ void neb2_pre_render(camid cid)
|
||||
}
|
||||
}
|
||||
|
||||
// wacky scheme for smoothing colors
|
||||
int wacky_scheme = 3;
|
||||
|
||||
// fill in the position of the eye for this frame
|
||||
void neb2_get_eye_pos(vec3d *eye_vector)
|
||||
{
|
||||
@@ -1415,25 +1394,6 @@ DCF(neb2_break_alpha, "alpha value (0.0 to 1.0) at which faded polygons are not
|
||||
dc_stuff_float(&Nd->break_alpha);
|
||||
}
|
||||
|
||||
DCF(neb2_break_off, "how many pixels offscreen (left, right, top, bottom) when a cloud poof becomes fully transparent.")
|
||||
{
|
||||
int value;
|
||||
dc_stuff_int(&value);
|
||||
Nd->break_y = (float)value;
|
||||
Nd->break_x = Nd->break_y * gr_screen.aspect;
|
||||
}
|
||||
|
||||
DCF(neb2_smooth, "magic fog smoothing modes (0 - 3)")
|
||||
{
|
||||
int index;
|
||||
dc_stuff_int(&index);
|
||||
if ( (index >= 0) && (index <= 3) ) {
|
||||
wacky_scheme = index;
|
||||
} else {
|
||||
dc_printf("Invalid smooth mode %i", index);
|
||||
}
|
||||
}
|
||||
|
||||
DCF(neb2_select, "Enables/disables a poof bitmap")
|
||||
{
|
||||
int bmap;
|
||||
@@ -1507,7 +1467,7 @@ DCF(neb2_fog_color, "Sets the RGB fog color (HTL)")
|
||||
dc_stuff_ubyte(&g);
|
||||
dc_stuff_ubyte(&b);
|
||||
|
||||
Neb2_fog_color_r = r;
|
||||
Neb2_fog_color_g = g;
|
||||
Neb2_fog_color_b = b;
|
||||
Neb2_fog_color[0] = r;
|
||||
Neb2_fog_color[1] = g;
|
||||
Neb2_fog_color[2] = b;
|
||||
}
|
||||
+21
-5
@@ -40,6 +40,17 @@ extern float Neb2_awacs;
|
||||
extern float Neb2_fog_near_mult;
|
||||
extern float Neb2_fog_far_mult;
|
||||
|
||||
#define NEB_FOG_VISIBILITY_MULT_TRAIL 1.0f
|
||||
#define NEB_FOG_VISIBILITY_MULT_THRUSTER 1.5f
|
||||
#define NEB_FOG_VISIBILITY_MULT_WEAPON 1.3f
|
||||
#define NEB_FOG_VISIBILITY_MULT_SHIELD 1.2f
|
||||
#define NEB_FOG_VISIBILITY_MULT_GLOWPOINT 1.2f
|
||||
#define NEB_FOG_VISIBILITY_MULT_BEAM(size) 4.0f + (size / 10)
|
||||
#define NEB_FOG_VISIBILITY_MULT_B_MUZZLE(size) NEB_FOG_VISIBILITY_MULT_BEAM(size)
|
||||
#define NEB_FOG_VISIBILITY_MULT_PARTICLE(size) 1.0f + (size / 12)
|
||||
#define NEB_FOG_VISIBILITY_MULT_SHOCKWAVE 2.5f
|
||||
#define NEB_FOG_VISIBILITY_MULT_FIREBALL(size) 1.2f + (size / 12)
|
||||
|
||||
#define MAX_NEB2_POOFS 32
|
||||
|
||||
// poof names and flags (for fred)
|
||||
@@ -57,6 +68,9 @@ extern char Neb2_texture_name[MAX_FILENAME_LEN];
|
||||
// how many "slices" are in the current player nebuls
|
||||
extern int Neb2_slices;
|
||||
|
||||
// the color of the fog/background
|
||||
extern ubyte Neb2_fog_color[3];
|
||||
|
||||
// nebula poofs
|
||||
typedef struct cube_poof {
|
||||
vec3d pt; // point in space
|
||||
@@ -73,7 +87,6 @@ typedef struct neb2_detail {
|
||||
float max_alpha_glide; // max alpha for this detail level in Glide
|
||||
float max_alpha_d3d; // max alpha for this detail level in D3d
|
||||
float break_alpha; // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
|
||||
float break_x, break_y; // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
|
||||
float cube_dim; // total dimension of player poof cube
|
||||
float cube_inner; // inner radius of the player poof cube
|
||||
float cube_outer; // outer radius of the player pood cube
|
||||
@@ -117,11 +130,14 @@ void neb2_eye_changed();
|
||||
void neb2_get_fog_values(float *fnear, float *ffar, object *obj = NULL);
|
||||
|
||||
// get adjusted near and far fog values (allows mission-specific fog adjustments)
|
||||
void neb2_get_adjusted_fog_values(float *fnear, float *ffar, object *obj = NULL);
|
||||
void neb2_get_adjusted_fog_values(float *fnear, float *ffar, float *fdensity = nullptr, object *obj = nullptr);
|
||||
|
||||
// given a position in space, return a value from 0.0 to 1.0 representing the fog level
|
||||
float neb2_get_fog_intensity(object *obj);
|
||||
float neb2_get_fog_intensity(vec3d *pos);
|
||||
// given an object, returns 0 - 1 the fog visibility of its center, 0 = completely obscured
|
||||
float neb2_get_fog_visibility(object *obj);
|
||||
|
||||
// given a position, returns 0 - 1 the fog visibility of that position, 0 = completely obscured
|
||||
// distance_mult will multiply the result, use for things that can be obscured but can 'shine through' the nebula more than normal
|
||||
float neb2_get_fog_visibility (vec3d* pos, float distance_mult);
|
||||
|
||||
// should we not render this object because its obscured by the nebula?
|
||||
int neb2_skip_render(object *objp, float z_depth);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "network/chat_api.h"
|
||||
#include "network/psnet2.h"
|
||||
#include "network/multi_log.h"
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
#include <sys/time.h>
|
||||
@@ -34,7 +35,7 @@ typedef int socklen_t;
|
||||
|
||||
#define MAXCHATBUFFER 500
|
||||
|
||||
SOCKET Chatsock;
|
||||
SOCKET Chatsock = INVALID_SOCKET;
|
||||
static SOCKADDR_STORAGE Chataddr;
|
||||
int Socket_connecting = 0;
|
||||
char Nick_name[33];
|
||||
@@ -148,7 +149,6 @@ int ConnectToChatServer(char *serveraddr, char *nickname, char *trackerid)
|
||||
|
||||
if ( !psnet_get_addr(nullptr, static_cast<uint16_t>(0), &Chataddr) )
|
||||
{
|
||||
printf("bail!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -216,6 +216,14 @@ int ConnectToChatServer(char *serveraddr, char *nickname, char *trackerid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for server error messages
|
||||
const char *msg = ChatGetString();
|
||||
|
||||
if (msg && !strcmp(msg, "ERROR"))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Socket_connected = 1;
|
||||
memset(signon_str, 0, sizeof(signon_str));
|
||||
sprintf_safe(signon_str, NOX("/USER %s %s %s :%s"), NOX("user"), NOX("user"), NOX("user"), Chat_tracker_id);
|
||||
@@ -245,10 +253,18 @@ int ConnectToChatServer(char *serveraddr, char *nickname, char *trackerid)
|
||||
*/
|
||||
void DisconnectFromChatServer()
|
||||
{
|
||||
if(!Socket_connected) return;
|
||||
SendChatString(NOX("/QUIT"),1);
|
||||
shutdown(Chatsock,2);
|
||||
closesocket(Chatsock);
|
||||
if (Socket_connected)
|
||||
{
|
||||
SendChatString(NOX("/QUIT"), 1);
|
||||
}
|
||||
|
||||
if (Chatsock != INVALID_SOCKET)
|
||||
{
|
||||
shutdown(Chatsock, 2);
|
||||
closesocket(Chatsock);
|
||||
}
|
||||
|
||||
Chatsock = INVALID_SOCKET;
|
||||
Socket_connecting = 0;
|
||||
Socket_connected = 0;
|
||||
Input_chat_buffer[0] = '\0';
|
||||
@@ -466,7 +482,7 @@ char *ChatGetString(void)
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(Chatsock,&read_fds);
|
||||
//Writable -- that means it's connected
|
||||
while ( select(static_cast<int>(Chatsock+1), &read_fds, nullptr, nullptr, &timeout) )
|
||||
while ( select(static_cast<int>(Chatsock+1), &read_fds, nullptr, nullptr, &timeout) > 0 )
|
||||
{
|
||||
bytesread = recv(Chatsock,ch,1,0);
|
||||
if(bytesread)
|
||||
@@ -777,6 +793,15 @@ char * ParseIRCMessage(char *Line, int iMode)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(stricmp(szCmd,NOX("ERROR"))==0)
|
||||
{
|
||||
// Server reported errors
|
||||
ml_printf("Chat ERROR: %s", szRemLine);
|
||||
AddChatCommandToQueue(CC_DISCONNECTED, nullptr, 0);
|
||||
strcpy_s(szResponse, "ERROR");
|
||||
return szResponse;
|
||||
}
|
||||
|
||||
if(stricmp(szCmd,NOX("NOTICE"))==0)
|
||||
{
|
||||
|
||||
|
||||
@@ -569,7 +569,7 @@ void process_packet_normal(ubyte* data, header *header_info)
|
||||
process_ship_kill_packet( data, header_info );
|
||||
break;
|
||||
|
||||
case WEAPON_KILL:
|
||||
case MISSILE_KILL:
|
||||
process_weapon_kill_packet(data, header_info);
|
||||
break;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class player;
|
||||
// version 51 - 9/20/2020 Object Update Packet Upgrade: Waypoints, subsystem rotation, bandwidth improvements, bugfixes
|
||||
// version 52 - 10/9/2020 Dumbfire Rollback, increases accuracy of high ping, or delayed packet primary fire for clients.
|
||||
// version 53 - 12/2/2020 big set of packet fixes/upgrades
|
||||
// version 54 - datepending - Fixes and features for FSO 21_2
|
||||
// version 54 - 3/20/2021 - Fixes for FSO 21_2 especially better net_sig calc, better missile intercept
|
||||
// STANDALONE_ONLY
|
||||
|
||||
#define MULTI_FS_SERVER_VERSION 54
|
||||
@@ -253,7 +253,7 @@ class player;
|
||||
#define REINFORCEMENT_AVAIL 0xDB // a reinforcement is available
|
||||
#define LIGHTNING_PACKET 0xDC // lightning bolt packet for multiplayer nebula
|
||||
#define BYTES_SENT 0xDD // how much data we've sent/received
|
||||
#define WEAPON_KILL 0xDE // get rid of this weapon on the client.
|
||||
#define MISSILE_KILL 0xDE // get rid of this weapon on the client.
|
||||
|
||||
#define GAME_ACTIVE 0xE1 // info on an active game server
|
||||
#define GAME_QUERY 0xE2 // request for a list of active game servers
|
||||
|
||||
@@ -639,7 +639,7 @@ void multi_ship_record_do_rollback()
|
||||
}
|
||||
|
||||
objp = &Objects[cur_ship.objnum];
|
||||
if (objp == nullptr) {
|
||||
if (objp == nullptr || objp->type != OBJ_SHIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3387,7 +3387,7 @@ void multi_oo_calc_interp_splines(int player_id, object* objp, matrix *new_orien
|
||||
float delta = multi_oo_calc_pos_time_difference(player_id, net_sig_idx);
|
||||
// if an error or invalid value, use the local timestamps instead of those received. Should be rare.
|
||||
if (delta <= 0.0f) {
|
||||
delta = (float)(timestamp() - Oo_info.received_frametimes[player_id].at(Oo_info.interp[net_sig_idx].pos_timestamp)) / TIMESTAMP_FREQUENCY;
|
||||
delta = (float)(timestamp() - Oo_info.interp[net_sig_idx].pos_timestamp) / TIMESTAMP_FREQUENCY;
|
||||
}
|
||||
|
||||
Oo_info.interp[net_sig_idx].pos_time_delta = delta;
|
||||
|
||||
@@ -644,9 +644,14 @@ void multi_respawn_process_packet(ubyte *data, header *hinfo)
|
||||
p_object *pobjp;
|
||||
|
||||
GET_USHORT( net_sig );
|
||||
pobjp = mission_parse_get_arrival_ship( net_sig );
|
||||
Assert( pobjp != NULL );
|
||||
multi_respawn_ai( pobjp );
|
||||
|
||||
// only attempt to respawn if we are in the mission
|
||||
if (!(Net_player->flags & NETINFO_FLAG_WARPING_OUT)) {
|
||||
pobjp = mission_parse_get_arrival_ship(net_sig);
|
||||
Assert(pobjp != NULL);
|
||||
multi_respawn_ai(pobjp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RESPAWN_BROADCAST:
|
||||
@@ -659,19 +664,23 @@ void multi_respawn_process_packet(ubyte *data, header *hinfo)
|
||||
GET_DATA(cur_link_status);
|
||||
GET_USHORT(ship_ets);
|
||||
GET_STRING(parse_name);
|
||||
player_index = find_player_id(player_id);
|
||||
if(player_index == -1){
|
||||
nprintf(("Network","Couldn't find player to respawn!\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
// create the ship and assign its position, net_signature, and class
|
||||
// respawn the player
|
||||
multi_respawn_player(&Net_players[player_index], cur_primary_bank, cur_secondary_bank, cur_link_status, ship_ets, net_sig, parse_name, &v);
|
||||
if (!(Net_player->flags & NETINFO_FLAG_WARPING_OUT)) {
|
||||
player_index = find_player_id(player_id);
|
||||
|
||||
// if this is for me, I should jump back into gameplay
|
||||
if(&Net_players[player_index] == Net_player){
|
||||
gameseq_post_event(GS_EVENT_ENTER_GAME);
|
||||
if(player_index == -1){
|
||||
nprintf(("Network","Couldn't find player to respawn!\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
// create the ship and assign its position, net_signature, and class
|
||||
// respawn the player
|
||||
multi_respawn_player(&Net_players[player_index], cur_primary_bank, cur_secondary_bank, cur_link_status, ship_ets, net_sig, parse_name, &v);
|
||||
|
||||
// if this is for me, I should jump back into gameplay
|
||||
if(&Net_players[player_index] == Net_player){
|
||||
gameseq_post_event(GS_EVENT_ENTER_GAME);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+20
-19
@@ -2702,21 +2702,21 @@ void process_ship_kill_packet( ubyte *data, header *hinfo )
|
||||
|
||||
constexpr int WK_FLAGS_WEAPON_WEAPON = (1<<0);
|
||||
|
||||
//simply removes the weapon from existence on the client.
|
||||
void send_weapon_kill_packet(object* objp)
|
||||
// simply removes a missile from existence on the client.
|
||||
void send_missile_kill_packet(object* objp)
|
||||
{
|
||||
Assert(objp != nullptr);
|
||||
Assert(objp->type == OBJ_WEAPON);
|
||||
Assert(MULTIPLAYER_MASTER);
|
||||
|
||||
if (objp == nullptr || objp->type != OBJ_WEAPON || MULTIPLAYER_CLIENT) {
|
||||
if (objp == nullptr || objp->type != OBJ_WEAPON || MULTIPLAYER_CLIENT || !(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype & WP_MISSILE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ubyte data[MAX_PACKET_SIZE], flags = 0;
|
||||
int packet_size;
|
||||
|
||||
BUILD_HEADER(WEAPON_KILL);
|
||||
BUILD_HEADER(MISSILE_KILL);
|
||||
|
||||
ADD_USHORT(objp->net_signature);
|
||||
if (objp->instance > -1) {
|
||||
@@ -2746,7 +2746,7 @@ void process_weapon_kill_packet(ubyte *data, header *hinfo )
|
||||
object* missile = multi_get_network_object(missile_net_signature);
|
||||
|
||||
// make sure it's valid before implementing.
|
||||
if (missile == nullptr || missile->type != OBJ_WEAPON || missile->instance < 0) {
|
||||
if (missile == nullptr || missile->type != OBJ_WEAPON || missile->instance < 0 || !(Weapon_info[Weapons[missile->instance].weapon_info_index].subtype & WP_MISSILE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2755,18 +2755,14 @@ void process_weapon_kill_packet(ubyte *data, header *hinfo )
|
||||
Weapons[missile->instance].weapon_flags.set(Weapon::Weapon_Flags::Destroyed_by_weapon);
|
||||
}
|
||||
|
||||
Weapons[missile->instance].lifeleft = -1.0f;
|
||||
// kill the missile!
|
||||
if (Weapon_info[Weapons[missile->instance].weapon_info_index].weapon_hitpoints > 0.0f) {
|
||||
missile->hull_strength = -1.0f;
|
||||
}
|
||||
|
||||
// kill the weapon!
|
||||
if (Weapon_info[Weapons[missile->instance].weapon_info_index].subtype & WP_MISSILE) {
|
||||
weapon_detonate(missile);
|
||||
}
|
||||
else {
|
||||
missile->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
}
|
||||
weapon_detonate(missile);
|
||||
missile->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
Weapons[missile->instance].lifeleft = -1.0f;
|
||||
}
|
||||
|
||||
// send a packet indicating a ship should be created
|
||||
@@ -7522,6 +7518,7 @@ void send_homing_weapon_info( int weapon_num )
|
||||
// homing signature.
|
||||
homing_signature = 0;
|
||||
homing_object = wp->homing_object;
|
||||
|
||||
if ( homing_object != &obj_used_list ) {
|
||||
homing_signature = homing_object->net_signature;
|
||||
|
||||
@@ -7545,7 +7542,7 @@ void send_homing_weapon_info( int weapon_num )
|
||||
|
||||
if (flags & HWIF_BIG_UPDATE) {
|
||||
fix current_lifetime = Missiontime - wp->creation_time;
|
||||
ADD_DATA(current_lifetime);
|
||||
ADD_INT(current_lifetime);
|
||||
ADD_VECTOR(Objects[wp->objnum].pos);
|
||||
ADD_FLOAT(wp->launch_speed);
|
||||
ADD_ORIENT(Objects[wp->objnum].orient);
|
||||
@@ -7560,14 +7557,14 @@ void process_homing_weapon_info( ubyte *data, header *hinfo )
|
||||
{
|
||||
ubyte flags;
|
||||
int offset;
|
||||
fix missile_lifetime;
|
||||
fix missile_lifetime = 0;
|
||||
ushort weapon_signature, homing_signature;
|
||||
short h_subsys;
|
||||
float launch_speed;
|
||||
vec3d missile_pos, homing_goal;
|
||||
float launch_speed = 0.0f;
|
||||
vec3d missile_pos = vmd_zero_vector, homing_goal = vmd_zero_vector;
|
||||
object *homing_object, *weapon_objp;
|
||||
weapon *wp;
|
||||
matrix orient_in;
|
||||
matrix orient_in = vmd_identity_matrix;
|
||||
|
||||
offset = HEADER_LENGTH;
|
||||
|
||||
@@ -7579,7 +7576,7 @@ void process_homing_weapon_info( ubyte *data, header *hinfo )
|
||||
GET_VECTOR( homing_goal );
|
||||
|
||||
if (flags & HWIF_BIG_UPDATE) {
|
||||
GET_DATA(missile_lifetime);
|
||||
GET_INT(missile_lifetime);
|
||||
GET_VECTOR(missile_pos);
|
||||
GET_FLOAT(launch_speed);
|
||||
GET_ORIENT(orient_in);
|
||||
@@ -7588,15 +7585,18 @@ void process_homing_weapon_info( ubyte *data, header *hinfo )
|
||||
|
||||
// deal with changing this weapons homing information
|
||||
weapon_objp = multi_get_network_object( weapon_signature );
|
||||
|
||||
if ( weapon_objp == nullptr ) {
|
||||
nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
Assert( weapon_objp->type == OBJ_WEAPON );
|
||||
wp = &Weapons[weapon_objp->instance];
|
||||
|
||||
// be sure that we can find these weapons and
|
||||
homing_object = multi_get_network_object( homing_signature );
|
||||
|
||||
if ( homing_object == nullptr ) {
|
||||
wp->homing_object = &obj_used_list;
|
||||
wp->homing_subsys = nullptr;
|
||||
@@ -7622,6 +7622,7 @@ void process_homing_weapon_info( ubyte *data, header *hinfo )
|
||||
wp->target_num = OBJ_INDEX(homing_object);
|
||||
wp->target_sig = homing_object->signature;
|
||||
wp->homing_pos = homing_goal;
|
||||
|
||||
if ( h_subsys != -1 ) {
|
||||
Assert( homing_object->type == OBJ_SHIP );
|
||||
wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
|
||||
|
||||
@@ -295,8 +295,8 @@ void send_object_update_packet(int force_all = 0);
|
||||
// send a packet indicating a ship has been killed
|
||||
void send_ship_kill_packet( object *ship_obj, object *other_objp, float percent_killed, int self_destruct );
|
||||
|
||||
// send a packet indicating that a weapon collided
|
||||
void send_weapon_kill_packet(object* objp);
|
||||
// send a packet indicating that a missile died.
|
||||
void send_missile_kill_packet(object* objp);
|
||||
|
||||
void process_weapon_kill_packet(ubyte* data, header* hinfo);
|
||||
|
||||
|
||||
@@ -3574,7 +3574,6 @@ int multi_pack_unpack_rotvel( int write, ubyte *data, physics_info *pi)
|
||||
bitbuffer_put( &buf, (uint)b, 10 );
|
||||
bitbuffer_put( &buf, (uint)c, 10 );
|
||||
|
||||
|
||||
return bitbuffer_write_flush(&buf);
|
||||
|
||||
} else {
|
||||
@@ -3637,8 +3636,10 @@ int multi_pack_unpack_desired_vel_and_desired_rotvel( int write, bool full_physi
|
||||
if (pi->max_vel.xyz.y > 0.0f) {
|
||||
e = fl2i(round( (local_desired_vel->xyz.y / pi->max_vel.xyz.y) * 7.0f));
|
||||
}
|
||||
float z_divisor = MAX(pi->afterburner_max_vel.xyz.z, pi->max_vel.xyz.z);
|
||||
|
||||
// for z velocity, take into account afterburner.
|
||||
float z_divisor = MAX(pi->afterburner_max_vel.xyz.z, pi->max_vel.xyz.z);
|
||||
|
||||
if (z_divisor > 0.0f) {
|
||||
f = fl2i(round( (local_desired_vel->xyz.z / z_divisor) * 255.0f));
|
||||
}
|
||||
@@ -3648,8 +3649,8 @@ int multi_pack_unpack_desired_vel_and_desired_rotvel( int write, bool full_physi
|
||||
CAP(f,-z_capfactor,z_capfactor);
|
||||
bitbuffer_put( &buf, (uint)d,4);
|
||||
bitbuffer_put( &buf, (uint)e,4);
|
||||
|
||||
bitbuffer_put( &buf, (uint)f,z_bitcount); // either 9 or 16 bits.
|
||||
|
||||
return bitbuffer_write_flush(&buf);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -178,7 +178,7 @@ void obj_render_all(const std::function<void(object*)>& render_function, bool *d
|
||||
{
|
||||
object *objp;
|
||||
int i;
|
||||
float fog_near, fog_far;
|
||||
float fog_near, fog_far, fog_density;
|
||||
|
||||
objp = Objects;
|
||||
|
||||
@@ -244,7 +244,7 @@ void obj_render_all(const std::function<void(object*)>& render_function, bool *d
|
||||
// if we're fullneb, fire up the fog - this also generates a fog table
|
||||
if (full_neb) {
|
||||
// get the fog values
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, obj);
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density, obj);
|
||||
|
||||
// maybe skip rendering an object because its obscured by the nebula
|
||||
if(neb2_skip_render(obj, os->z)){
|
||||
@@ -281,7 +281,7 @@ void obj_render_all(const std::function<void(object*)>& render_function, bool *d
|
||||
// if we're fullneb, fire up the fog - this also generates a fog table
|
||||
if(full_neb){
|
||||
// get the fog values
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, obj);
|
||||
neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density, obj);
|
||||
|
||||
// maybe skip rendering an object because its obscured by the nebula
|
||||
if(neb2_skip_render(obj, os->z)){
|
||||
|
||||
+80
-86
@@ -2229,36 +2229,26 @@ void read_raw_file_text(const char *filename, int mode, char *raw_text)
|
||||
|
||||
// SDL2 has iconv functionality so we use that to convert from Latin1 to UTF-8
|
||||
|
||||
// We need the raw_text as the output buffer so we first need to copy the current
|
||||
// We need the raw_text as fallback so we first need to copy the current
|
||||
SCP_string input_str = raw_text;
|
||||
|
||||
do {
|
||||
auto in_str = input_str.c_str();
|
||||
auto in_size = input_str.size();
|
||||
auto out_str = Parse_text_raw;
|
||||
auto out_size = Parse_text_size;
|
||||
SCP_string buffer;
|
||||
bool success = unicode::convert_encoding(buffer, raw_text, unicode::Encoding::Encoding_iso8859_1, unicode::Encoding::Encoding_utf8);
|
||||
|
||||
auto iconv = SDL_iconv_open("UTF-8", "ISO-8859-1");
|
||||
auto err = SDL_iconv(iconv, &in_str, &in_size, &out_str, &out_size);
|
||||
SDL_iconv_close(iconv);
|
||||
if (Parse_text_size < buffer.length()) {
|
||||
allocate_parse_text(buffer.length());
|
||||
}
|
||||
|
||||
// SDL returns the number of processed character on success;
|
||||
// error codes are (size_t)-1 through -4
|
||||
if (err < (size_t)-100) {
|
||||
break;
|
||||
} else if (err == SDL_ICONV_E2BIG) {
|
||||
// buffer is not big enough, try again with a bigger buffer. Use a rather conservative size
|
||||
// increment since the additional size required is probably pretty small
|
||||
allocate_parse_text(Parse_text_size + 300);
|
||||
} else {
|
||||
Warning(LOCATION, "File reencoding failed (error code " SIZE_T_ARG ")!\n"
|
||||
"You will probably encounter encoding issues.", err);
|
||||
if (success) {
|
||||
strncpy(Parse_text_raw, buffer.c_str(), buffer.length());
|
||||
}
|
||||
else {
|
||||
Warning(LOCATION, "File reencoding failed!\n"
|
||||
"You will probably encounter encoding issues.");
|
||||
|
||||
// Copy the original data back to the mission text pointer so that we don't loose any data here
|
||||
strcpy(Parse_text_raw, input_str.c_str());
|
||||
break;
|
||||
}
|
||||
} while(true);
|
||||
// Copy the original data back to the mission text pointer so that we don't loose any data here
|
||||
strcpy(Parse_text_raw, input_str.c_str());
|
||||
}
|
||||
} else {
|
||||
Warning(LOCATION, "Found invalid UTF-8 encoding in file %s at position " PTRDIFF_T_ARG "!\n"
|
||||
"This may cause parsing errors and should be fixed!", filename, invalid - raw_text);
|
||||
@@ -2288,41 +2278,7 @@ void coerce_to_utf8(SCP_string &buffer, const char *str)
|
||||
// we can convert it
|
||||
if (isLatin1)
|
||||
{
|
||||
size_t newlen = len;
|
||||
std::unique_ptr<char[]> newstr(new char[newlen]);
|
||||
|
||||
do {
|
||||
auto in_str = str;
|
||||
auto in_size = len;
|
||||
auto out_str = newstr.get();
|
||||
auto out_size = newlen;
|
||||
|
||||
auto iconv = SDL_iconv_open("UTF-8", "ISO-8859-1");
|
||||
auto err = SDL_iconv(iconv, &in_str, &in_size, &out_str, &out_size);
|
||||
SDL_iconv_close(iconv);
|
||||
|
||||
// SDL returns the number of processed character on success;
|
||||
// error codes are (size_t)-1 through -4
|
||||
if (err < (size_t)-100)
|
||||
{
|
||||
// successful re-encoding
|
||||
buffer.assign(newstr.get(), newlen - out_size);
|
||||
mprintf(("Re-encoding non-UTF-8 string '%s' to '%s'!\n", str, buffer.c_str()));
|
||||
return;
|
||||
}
|
||||
else if (err == SDL_ICONV_E2BIG)
|
||||
{
|
||||
// buffer is not big enough, try again with a bigger buffer. Use a rather conservative size
|
||||
// increment since the additional size required is probably pretty small
|
||||
newlen += 10;
|
||||
newstr.reset(new char[newlen]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// re-encoding failed, so use truncation
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
unicode::convert_encoding(buffer, str, unicode::Encoding::Encoding_iso8859_1, unicode::Encoding::Encoding_utf8);
|
||||
}
|
||||
|
||||
// unknown encoding, so just truncate
|
||||
@@ -2331,10 +2287,19 @@ void coerce_to_utf8(SCP_string &buffer, const char *str)
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
void process_raw_file_text(char *processed_text, char *raw_text)
|
||||
void process_raw_file_text(char* processed_text, char* raw_text)
|
||||
{
|
||||
char *mp;
|
||||
char *mp_raw;
|
||||
SCP_string parse_exception_1402;
|
||||
unicode::convert_encoding(parse_exception_1402, "1402, \"Sie haben IPX-Protokoll als Protokoll ausgew\xE4hlt, aber dieses Protokoll ist auf Ihrer Maschine nicht installiert.\".\"\n", unicode::Encoding::Encoding_iso8859_1);
|
||||
SCP_string parse_exception_1117;
|
||||
unicode::convert_encoding(parse_exception_1117, "1117, \"\\r\\n\"Aucun web browser trouva. Del\xE0 isn't on emm\xE9nagea ou if \\r\\non est emm\xE9nagea, ca isn't set pour soient la default browser.\\r\\n\\r\\n\"\n", unicode::Encoding::Encoding_iso8859_1);
|
||||
SCP_string parse_exception_1337;
|
||||
unicode::convert_encoding(parse_exception_1337, "1337, \"(fr)Loading\"\n", unicode::Encoding::Encoding_iso8859_1);
|
||||
SCP_string parse_exception_3966;
|
||||
unicode::convert_encoding(parse_exception_3966, "3966, \"Es sieht so aus, als habe Staffel Kappa Zugriff auf die GTVA-Zugangscodes f\xFCr das System gehabt. Das ist ein ernstes Sicherheitsleck. Ihre IFF-Kennung erschien als \"verb\xFCndet\", so da\xDF sie sich dem Konvoi ungehindert n\xE4hern konnten. Zum Gl\xFC\x63k flogen Sie und Alpha 2 Geleitschutz und lie\xDF\x65n den Schwindel auffliegen, bevor Kappa ihren Befehl ausf\xFChren konnte.\"\n", unicode::Encoding::Encoding_iso8859_1);
|
||||
|
||||
char* mp;
|
||||
char* mp_raw;
|
||||
char outbuf[PARSE_BUF_SIZE];
|
||||
bool in_quote = false;
|
||||
bool in_multiline_comment_a = false;
|
||||
@@ -2347,32 +2312,38 @@ void process_raw_file_text(char *processed_text, char *raw_text)
|
||||
if (raw_text == NULL)
|
||||
raw_text = Parse_text_raw;
|
||||
|
||||
Assert( processed_text != NULL );
|
||||
Assert( raw_text != NULL );
|
||||
Assert(processed_text != NULL);
|
||||
Assert(raw_text != NULL);
|
||||
|
||||
mp = processed_text;
|
||||
mp_raw = raw_text;
|
||||
|
||||
// strip comments from raw text, reading into file_text
|
||||
int num_chars_read = 0;
|
||||
while ( (num_chars_read = parse_get_line(outbuf, PARSE_BUF_SIZE, raw_text, raw_text_len, mp_raw)) != 0 ) {
|
||||
while ((num_chars_read = parse_get_line(outbuf, PARSE_BUF_SIZE, raw_text, raw_text_len, mp_raw)) != 0) {
|
||||
mp_raw += num_chars_read;
|
||||
|
||||
// stupid hacks to make retail data work with fixed parser, per Mantis #3072
|
||||
if (!strcmp(outbuf, "1402, \"Sie haben IPX-Protokoll als Protokoll ausgew\xE4hlt, aber dieses Protokoll ist auf Ihrer Maschine nicht installiert.\".\"\n")) {
|
||||
outbuf[121] = ' ';
|
||||
outbuf[122] = ' ';
|
||||
} else if (!strcmp(outbuf, "1117, \"\\r\\n\"Aucun web browser trouva. Del\xE0 isn't on emm\xE9nagea ou if \\r\\non est emm\xE9nagea, ca isn't set pour soient la default browser.\\r\\n\\r\\n\"\n")) {
|
||||
char *ch = &outbuf[11];
|
||||
if (!strcmp(outbuf, parse_exception_1402.c_str())) {
|
||||
|
||||
int offset = Unicode_text_mode ? 1 : 0;
|
||||
outbuf[121 + offset] = ' ';
|
||||
outbuf[122 + offset] = ' ';
|
||||
}
|
||||
else if (!strcmp(outbuf, parse_exception_1117.c_str())) {
|
||||
char* ch = &outbuf[11];
|
||||
do {
|
||||
*ch = *(ch+1);
|
||||
*ch = *(ch + 1);
|
||||
++ch;
|
||||
} while (*ch);
|
||||
} else if (!strcmp(outbuf, "1337, \"(fr)Loading\"\n")) {
|
||||
}
|
||||
else if (!strcmp(outbuf, parse_exception_1337.c_str())) {
|
||||
outbuf[3] = '6';
|
||||
} else if (!strcmp(outbuf, "3966, \"Es sieht so aus, als habe Staffel Kappa Zugriff auf die GTVA-Zugangscodes f\xFCr das System gehabt. Das ist ein ernstes Sicherheitsleck. Ihre IFF-Kennung erschien als \"verb\xFCndet\", so da\xDF sie sich dem Konvoi ungehindert n\xE4hern konnten. Zum Gl\xFC\x63k flogen Sie und Alpha 2 Geleitschutz und lie\xDF\x65n den Schwindel auffliegen, bevor Kappa ihren Befehl ausf\xFChren konnte.\"\n")) {
|
||||
outbuf[171] = '\'';
|
||||
outbuf[181] = '\'';
|
||||
}
|
||||
else if (!strcmp(outbuf, parse_exception_3966.c_str())) {
|
||||
int offset = Unicode_text_mode ? 1 : 0;
|
||||
outbuf[171 + offset] = '\'';
|
||||
outbuf[181 + offset * 2] = '\'';
|
||||
}
|
||||
|
||||
strip_comments(outbuf, in_quote, in_multiline_comment_a, in_multiline_comment_b);
|
||||
@@ -2819,6 +2790,9 @@ size_t stuff_token_list(T *listp, size_t list_max, F stuff_one_token, const char
|
||||
return i;
|
||||
}
|
||||
|
||||
// If this data is going to be parsed multiple times (like for mission load), then the dest variable
|
||||
// needs to be set to zero in between parses, otherwise we keep bad data.
|
||||
// For tbm files, it must not be reset.
|
||||
void parse_string_flag_list(int *dest, flag_def_list defs[], size_t defs_size)
|
||||
{
|
||||
Assert(dest!=NULL); //wtf?
|
||||
@@ -3018,16 +2992,18 @@ void stuff_loadout_list(SCP_vector<loadout_row> &list, int lookup_type)
|
||||
Warning(LOCATION, "Weapon '%s' has more than 300 possible spawned weapons over its lifetime! This can cause issues for Multiplayer.", Weapon_info[buf->index].name);
|
||||
}
|
||||
|
||||
// similarly, complain if this is a valid ship or weapon class that the player can't use
|
||||
if ((lookup_type == MISSION_LOADOUT_SHIP_LIST) && (!(Ship_info[buf->index].flags[Ship::Info_Flags::Player_ship])) ) {
|
||||
error_display(0, "Ship type \"%s\" found in loadout of mission file. This class is not marked as a player ship...skipping", str.c_str());
|
||||
skip_this_entry = true;
|
||||
}
|
||||
else if ((lookup_type == MISSION_LOADOUT_WEAPON_LIST) && (!(Weapon_info[buf->index].wi_flags[Weapon::Info_Flags::Player_allowed])) ) {
|
||||
nprintf(("Warning", "Warning: Weapon type %s found in loadout of mission file. This class is not marked as a player allowed weapon...skipping\n", str.c_str()));
|
||||
if ( !Is_standalone )
|
||||
error_display(0, "Weapon type \"%s\" found in loadout of mission file. This class is not marked as a player allowed weapon...skipping", str.c_str());
|
||||
skip_this_entry = true;
|
||||
if (!skip_this_entry) {
|
||||
// similarly, complain if this is a valid ship or weapon class that the player can't use
|
||||
if ((lookup_type == MISSION_LOADOUT_SHIP_LIST) && (!(Ship_info[buf->index].flags[Ship::Info_Flags::Player_ship])) ) {
|
||||
error_display(0, "Ship type \"%s\" found in loadout of mission file. This class is not marked as a player ship...skipping", str.c_str());
|
||||
skip_this_entry = true;
|
||||
}
|
||||
else if ((lookup_type == MISSION_LOADOUT_WEAPON_LIST) && (!(Weapon_info[buf->index].wi_flags[Weapon::Info_Flags::Player_allowed])) ) {
|
||||
nprintf(("Warning", "Warning: Weapon type %s found in loadout of mission file. This class is not marked as a player allowed weapon...skipping\n", str.c_str()));
|
||||
if ( !Is_standalone )
|
||||
error_display(0, "Weapon type \"%s\" found in loadout of mission file. This class is not marked as a player allowed weapon...skipping", str.c_str());
|
||||
skip_this_entry = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Loadout counts are only needed for missions
|
||||
@@ -3889,6 +3865,24 @@ int get_index_of_first_hash_symbol(SCP_string &src, bool ignore_doubled_hash)
|
||||
}
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
// Used for escape sequences: ## to #, !! to !, etc.
|
||||
void consolidate_double_characters(char *src, char ch)
|
||||
{
|
||||
auto dest = src;
|
||||
while (*src)
|
||||
{
|
||||
if (*src == ch && *(src + 1) == ch)
|
||||
dest--;
|
||||
|
||||
++src;
|
||||
++dest;
|
||||
|
||||
if (src != dest)
|
||||
*dest = *src;
|
||||
}
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
ptrdiff_t replace_one(char *str, const char *oldstr, const char *newstr, size_t max_len, ptrdiff_t range)
|
||||
{
|
||||
|
||||
@@ -74,6 +74,8 @@ extern char *get_pointer_to_first_hash_symbol(char *src, bool ignore_doubled_has
|
||||
extern const char *get_pointer_to_first_hash_symbol(const char *src, bool ignore_doubled_hash = false);
|
||||
extern int get_index_of_first_hash_symbol(SCP_string &src, bool ignore_doubled_hash = false);
|
||||
|
||||
extern void consolidate_double_characters(char *str, char ch);
|
||||
|
||||
// white space
|
||||
extern int is_white_space(char ch);
|
||||
extern int is_white_space(unicode::codepoint_t cp);
|
||||
|
||||
+121
-17
@@ -679,6 +679,7 @@ SCP_vector<sexp_oper> Operators = {
|
||||
{ "nebula-change-storm", OP_NEBULA_CHANGE_STORM, 1, 1, SEXP_ACTION_OPERATOR, }, // phreak
|
||||
{ "nebula-toggle-poof", OP_NEBULA_TOGGLE_POOF, 2, 2, SEXP_ACTION_OPERATOR, }, // phreak
|
||||
{ "nebula-change-pattern", OP_NEBULA_CHANGE_PATTERN, 1, 1, SEXP_ACTION_OPERATOR, }, // Axem
|
||||
{ "nebula-change-fog-color", OP_NEBULA_CHANGE_FOG_COLOR, 3, 3, SEXP_ACTION_OPERATOR, }, // Asteroth
|
||||
{ "set-skybox-model", OP_SET_SKYBOX_MODEL, 1, 8, SEXP_ACTION_OPERATOR, }, // taylor
|
||||
{ "set-skybox-orientation", OP_SET_SKYBOX_ORIENT, 3, 3, SEXP_ACTION_OPERATOR, }, // Goober5000
|
||||
{ "set-ambient-light", OP_SET_AMBIENT_LIGHT, 3, 3, SEXP_ACTION_OPERATOR, }, // Karajorma
|
||||
@@ -3390,7 +3391,9 @@ void get_sexp_text_for_variable(char *text, const char *token)
|
||||
if ( !Fred_running ) {
|
||||
// freespace - get index into Sexp_variables array
|
||||
sexp_var_index = get_index_sexp_variable_name(text);
|
||||
Assert(sexp_var_index != -1);
|
||||
if (sexp_var_index == -1) {
|
||||
Error(LOCATION, "Invalid variable name [%s]!", text);
|
||||
}
|
||||
sprintf(text, "%d", sexp_var_index);
|
||||
}
|
||||
}
|
||||
@@ -6834,9 +6837,28 @@ int sexp_is_ship_visible(int node)
|
||||
if (viewer_entry)
|
||||
viewer_shipp = viewer_entry->shipp;
|
||||
}
|
||||
// if the second argument is not supplied, and we're single-player, default to the player
|
||||
else if (!(Game_mode & GM_MULTIPLAYER))
|
||||
viewer_shipp = Player_ship;
|
||||
else
|
||||
{
|
||||
// if the second argument is not supplied, default to the player, per retail
|
||||
if (Game_mode & GM_MULTIPLAYER)
|
||||
{
|
||||
mprintf(("In multiplayer, is-ship-visible must have two arguments! Defaulting to the first player.\n"));
|
||||
|
||||
// to make allowances for buggy missions (such as retail), just pick the first player
|
||||
// if we actually have no valid players, viewer_shipp will be NULL, but that's ok
|
||||
for (int i = 0; i < MAX_PLAYERS; ++i)
|
||||
{
|
||||
int shipnum = multi_get_player_ship(i);
|
||||
if (shipnum >= 0)
|
||||
{
|
||||
viewer_shipp = &Ships[shipnum];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
viewer_shipp = Player_ship;
|
||||
}
|
||||
|
||||
// get ship's *radar* visiblity
|
||||
if (viewer_shipp)
|
||||
@@ -9995,7 +10017,7 @@ int eval_in_sequence(int arg_handler_node, int condition_node)
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
int eval_for_counter(int arg_handler_node, int condition_node)
|
||||
int eval_for_counter(int arg_handler_node, int condition_node, bool just_count = false)
|
||||
{
|
||||
bool is_nan, is_nan_forever;
|
||||
int n, num_valid_arguments, num_true, num_false, num_known_true, num_known_false;
|
||||
@@ -10045,6 +10067,9 @@ int eval_for_counter(int arg_handler_node, int condition_node)
|
||||
// situation, resulting in a crash at best. -MageKing17
|
||||
}
|
||||
|
||||
if (just_count)
|
||||
return static_cast<int>(argument_vector.size());
|
||||
|
||||
// test the whole argument vector
|
||||
num_valid_arguments = test_argument_vector_for_condition(argument_vector, true, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
|
||||
|
||||
@@ -10058,7 +10083,7 @@ int eval_for_counter(int arg_handler_node, int condition_node)
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
int eval_for_ship_collection(int arg_handler_node, int condition_node, int op_num)
|
||||
int eval_for_ship_collection(int arg_handler_node, int condition_node, int op_const, bool just_count = false)
|
||||
{
|
||||
int n, num_valid_arguments, num_true, num_false, num_known_true, num_known_false;
|
||||
SCP_vector<std::pair<char*, int>> argument_vector;
|
||||
@@ -10072,7 +10097,7 @@ int eval_for_ship_collection(int arg_handler_node, int condition_node, int op_nu
|
||||
auto constraint = CTEXT(n);
|
||||
int constraint_index = -1;
|
||||
|
||||
switch (op_num)
|
||||
switch (op_const)
|
||||
{
|
||||
case OP_FOR_SHIP_CLASS:
|
||||
constraint_index = ship_info_lookup(constraint);
|
||||
@@ -10099,7 +10124,7 @@ int eval_for_ship_collection(int arg_handler_node, int condition_node, int op_nu
|
||||
auto shipp = &Ships[objp->instance];
|
||||
int ship_index = -1;
|
||||
|
||||
switch (op_num)
|
||||
switch (op_const)
|
||||
{
|
||||
case OP_FOR_SHIP_CLASS:
|
||||
ship_index = shipp->ship_info_index;
|
||||
@@ -10121,6 +10146,9 @@ int eval_for_ship_collection(int arg_handler_node, int condition_node, int op_nu
|
||||
}
|
||||
}
|
||||
|
||||
if (just_count)
|
||||
return static_cast<int>(argument_vector.size());
|
||||
|
||||
// test the whole argument vector
|
||||
num_valid_arguments = test_argument_vector_for_condition(argument_vector, true, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
|
||||
|
||||
@@ -10134,7 +10162,7 @@ int eval_for_ship_collection(int arg_handler_node, int condition_node, int op_nu
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
int eval_for_players(int arg_handler_node, int condition_node)
|
||||
int eval_for_players(int arg_handler_node, int condition_node, bool just_count = false)
|
||||
{
|
||||
int num_valid_arguments, num_true, num_false, num_known_true, num_known_false;
|
||||
SCP_vector<std::pair<char*, int>> argument_vector;
|
||||
@@ -10157,6 +10185,9 @@ int eval_for_players(int arg_handler_node, int condition_node)
|
||||
argument_vector.emplace_back(vm_strdup(Player_ship->ship_name), -1);
|
||||
}
|
||||
|
||||
if (just_count)
|
||||
return static_cast<int>(argument_vector.size());
|
||||
|
||||
// test the whole argument vector
|
||||
num_valid_arguments = test_argument_vector_for_condition(argument_vector, true, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
|
||||
|
||||
@@ -10207,7 +10238,7 @@ void sexp_change_all_argument_validity(int n, bool invalidate)
|
||||
|
||||
arg_handler = get_handler_for_x_of_operator(n);
|
||||
|
||||
// thanks to woutersmits for finding this loophole
|
||||
// prevent a crash if the SEXP is used somewhere it's not supposed to be
|
||||
if (arg_handler < 0)
|
||||
return;
|
||||
|
||||
@@ -10243,6 +10274,27 @@ int sexp_num_valid_arguments( int n )
|
||||
|
||||
arg_handler = get_handler_for_x_of_operator(n);
|
||||
|
||||
// prevent a crash if the SEXP is used somewhere it's not supposed to be
|
||||
if (arg_handler < 0)
|
||||
return 0;
|
||||
|
||||
// the for-* sexps require special handling: they don't list their arguments explicitly but rather generate them on-the-fly
|
||||
auto op_const = get_operator_const(arg_handler);
|
||||
switch (op_const)
|
||||
{
|
||||
case OP_FOR_COUNTER:
|
||||
return eval_for_counter(arg_handler, Locked_sexp_true, true);
|
||||
|
||||
case OP_FOR_PLAYERS:
|
||||
return eval_for_players(arg_handler, Locked_sexp_true, true);
|
||||
|
||||
case OP_FOR_SHIP_CLASS:
|
||||
case OP_FOR_SHIP_TYPE:
|
||||
case OP_FOR_SHIP_TEAM:
|
||||
case OP_FOR_SHIP_SPECIES:
|
||||
return eval_for_ship_collection(arg_handler, Locked_sexp_true, op_const, true);
|
||||
}
|
||||
|
||||
// loop through arguments
|
||||
arg_n = CDR(arg_handler);
|
||||
while (arg_n != -1) {
|
||||
@@ -10250,7 +10302,6 @@ int sexp_num_valid_arguments( int n )
|
||||
matches++;
|
||||
}
|
||||
|
||||
|
||||
// iterate
|
||||
arg_n = CDR(arg_n);
|
||||
}
|
||||
@@ -10266,7 +10317,8 @@ void sexp_change_argument_validity(int n, bool invalidate)
|
||||
|
||||
arg_handler = get_handler_for_x_of_operator(n);
|
||||
|
||||
// thanks to woutersmits for finding this loophole
|
||||
// prevent a crash if the SEXP is used somewhere it's not supposed to be
|
||||
// (thanks to woutersmits for finding this bug)
|
||||
if (arg_handler < 0)
|
||||
return;
|
||||
|
||||
@@ -13973,6 +14025,28 @@ void sexp_nebula_change_pattern(int n)
|
||||
neb2_post_level_init();
|
||||
}
|
||||
|
||||
void sexp_nebula_change_fog_color(int node)
|
||||
{
|
||||
if (!(The_mission.flags[Mission::Mission_Flags::Fullneb])) return;
|
||||
|
||||
int red, green, blue = 0;
|
||||
bool is_nan, is_nan_forever;
|
||||
|
||||
Assert(node >= 0);
|
||||
|
||||
eval_nums(node, is_nan, is_nan_forever, red, green, blue);
|
||||
if (is_nan || is_nan_forever)
|
||||
return;
|
||||
|
||||
CLAMP(red, 0, 255);
|
||||
CLAMP(green, 0, 255);
|
||||
CLAMP(blue, 0, 255);
|
||||
|
||||
Neb2_fog_color[0] = (ubyte)red;
|
||||
Neb2_fog_color[1] = (ubyte)green;
|
||||
Neb2_fog_color[2] = (ubyte)blue;
|
||||
}
|
||||
|
||||
/**
|
||||
* End the mission.
|
||||
*
|
||||
@@ -17766,6 +17840,7 @@ void ship_copy_damage(ship *target_shipp, ship *source_shipp)
|
||||
target_objp->hull_strength = source_objp->hull_strength;
|
||||
|
||||
// ...and shields
|
||||
target_shipp->special_shield = source_shipp->special_shield;
|
||||
target_shipp->ship_max_shield_strength = source_shipp->ship_max_shield_strength;
|
||||
for (i = 0; i < MIN(target_objp->n_quadrants, source_objp->n_quadrants); i++)
|
||||
target_objp->shield_quadrant[i] = source_objp->shield_quadrant[i];
|
||||
@@ -24587,6 +24662,11 @@ int eval_sexp(int cur_node, int referenced_node)
|
||||
sexp_val = SEXP_TRUE;
|
||||
break;
|
||||
|
||||
case OP_NEBULA_CHANGE_FOG_COLOR:
|
||||
sexp_nebula_change_fog_color(node);
|
||||
sexp_val = SEXP_TRUE;
|
||||
break;
|
||||
|
||||
case OP_END_MISSION:
|
||||
sexp_end_mission(node);
|
||||
sexp_val = SEXP_TRUE;
|
||||
@@ -26145,15 +26225,26 @@ int get_sexp_main()
|
||||
int run_sexp(const char* sexpression, bool run_eval_num, bool *is_nan_or_nan_forever)
|
||||
{
|
||||
char* oldMp = Mp;
|
||||
int n, i, sexp_val = UNINITIALIZED;
|
||||
int n, sexp_val = UNINITIALIZED;
|
||||
char buf[8192];
|
||||
|
||||
strcpy_s(buf, sexpression);
|
||||
|
||||
// HACK: ! -> "
|
||||
for (i = 0; i < (int)strlen(buf); i++)
|
||||
if (buf[i] == '!')
|
||||
buf[i]='\"';
|
||||
for (auto ch = buf; *ch; ++ch)
|
||||
{
|
||||
// convert single ! to ", but don't convert !!
|
||||
if (*ch == '!')
|
||||
{
|
||||
if (*(ch + 1) == '!')
|
||||
++ch;
|
||||
else
|
||||
*ch = '\"';
|
||||
}
|
||||
}
|
||||
|
||||
// !! -> !
|
||||
consolidate_double_characters(buf, '!');
|
||||
|
||||
Mp = buf;
|
||||
|
||||
@@ -26779,6 +26870,7 @@ int query_operator_return_type(int op)
|
||||
case OP_TURRET_CLEAR_FORCED_TARGET:
|
||||
case OP_TURRET_SET_INACCURACY:
|
||||
case OP_REPLACE_TEXTURE:
|
||||
case OP_NEBULA_CHANGE_FOG_COLOR:
|
||||
return OPR_NULL;
|
||||
|
||||
case OP_AI_CHASE:
|
||||
@@ -29056,6 +29148,9 @@ int query_operator_argument_type(int op, int argnum)
|
||||
else
|
||||
return OPF_BOOL;
|
||||
|
||||
case OP_NEBULA_CHANGE_FOG_COLOR:
|
||||
return OPF_POSITIVE;
|
||||
|
||||
case OP_SCRIPT_EVAL_NUM:
|
||||
case OP_SCRIPT_EVAL_BLOCK:
|
||||
case OP_SCRIPT_EVAL:
|
||||
@@ -30801,6 +30896,7 @@ int get_subcategory(int sexp_id)
|
||||
case OP_NEBULA_CHANGE_STORM:
|
||||
case OP_NEBULA_TOGGLE_POOF:
|
||||
case OP_NEBULA_CHANGE_PATTERN:
|
||||
case OP_NEBULA_CHANGE_FOG_COLOR:
|
||||
case OP_SET_AMBIENT_LIGHT:
|
||||
return CHANGE_SUBCATEGORY_BACKGROUND_AND_NEBULA;
|
||||
|
||||
@@ -33968,7 +34064,7 @@ SCP_vector<sexp_help_struct> Sexp_help = {
|
||||
|
||||
{ OP_IS_SHIP_VISIBLE, "is-ship-visible\r\n"
|
||||
"\tCheck whether ship is visible on a certain ship's radar. Returns 0 - not visible, 1 - partially visible, 2 - fully visible.\r\n"
|
||||
"\tNote: In multiplayer, the second argument *must* be supplied or this SEXP will always return 0.\r\n"
|
||||
"\tNote: In multiplayer, the second argument *must* be supplied or this SEXP will default to the first player.\r\n"
|
||||
"\tTakes 1 or 2 arguments...\r\n"
|
||||
"\t1: Name of ship to check\r\n"
|
||||
"\t2 (optional): Name of the viewing ship. Defaults to the player's ship in single-player mode. If this ship is not in-mission, the SEXP will return 0.\r\n" },
|
||||
@@ -34813,6 +34909,14 @@ SCP_vector<sexp_help_struct> Sexp_help = {
|
||||
"\t1:\tNebula background pattern to change to\r\n"
|
||||
},
|
||||
|
||||
{ OP_NEBULA_CHANGE_FOG_COLOR, "nebula-change-fog-color\r\n"
|
||||
"\tChanges the current nebula fog color\r\n\r\n"
|
||||
"Takes 3 arguments...\r\n"
|
||||
"\t1:\tRed (0 - 255)\r\n"
|
||||
"\t2:\tGreen (0 - 255)\r\n"
|
||||
"\t3:\tBlue (0 - 255)\r\n"
|
||||
},
|
||||
|
||||
{OP_SCRIPT_EVAL_NUM, "script-eval-num\r\n"
|
||||
"\tEvaluates script to return a number"
|
||||
"Takes 1 argument...\r\n"
|
||||
|
||||
@@ -773,6 +773,7 @@ class waypoint_list;
|
||||
#define OP_TURRET_SET_INACCURACY (0x003f | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // Asteroth
|
||||
|
||||
#define OP_REPLACE_TEXTURE (0x0040 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // Lafiel
|
||||
#define OP_NEBULA_CHANGE_FOG_COLOR (0x0041 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // Asteroth
|
||||
|
||||
// defined for AI goals
|
||||
#define OP_AI_CHASE (0x0000 | OP_CATEGORY_AI | OP_NONCAMPAIGN_FLAG)
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#include "render/batching.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "tracing/Monitor.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "mission/missionparse.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
|
||||
using namespace particle;
|
||||
|
||||
@@ -38,10 +41,10 @@ namespace
|
||||
|
||||
static int Particles_enabled = 1;
|
||||
|
||||
float get_current_alpha(vec3d* pos)
|
||||
float get_current_alpha(vec3d* pos, float rad)
|
||||
{
|
||||
float dist;
|
||||
float alpha;
|
||||
float alpha = 0.99999f;
|
||||
|
||||
const float inner_radius = 30.0f;
|
||||
const float magic_num = 2.75f;
|
||||
@@ -55,14 +58,18 @@ namespace
|
||||
if (dist <= inner_radius)
|
||||
{
|
||||
// alpha per meter between the magic # and the inner radius
|
||||
alpha = 0.99999f / (inner_radius - magic_num);
|
||||
alpha /= (inner_radius - magic_num);
|
||||
|
||||
// above value times the # of meters away we are
|
||||
alpha *= (dist - magic_num);
|
||||
return (alpha < 0.05f) ? 0.0f : alpha;
|
||||
if (alpha < 0.05f)
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 0.99999f;
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_particles)
|
||||
alpha *= neb2_get_fog_visibility(pos, NEB_FOG_VISIBILITY_MULT_PARTICLE(rad));
|
||||
|
||||
return alpha;
|
||||
}
|
||||
|
||||
inline int get_percent(int count)
|
||||
@@ -399,7 +406,7 @@ namespace particle
|
||||
}
|
||||
|
||||
// calculate the alpha to draw at
|
||||
auto alpha = get_current_alpha(&p_pos);
|
||||
auto alpha = get_current_alpha(&p_pos, part->radius);
|
||||
|
||||
// if it's transparent then just skip it
|
||||
if (alpha <= 0.0f)
|
||||
|
||||
@@ -1380,7 +1380,7 @@ void player_level_init()
|
||||
Viewer_external_info.current_distance = 0.0f;
|
||||
|
||||
|
||||
if (Chase_view_default)
|
||||
if (Chase_view_default || The_mission.flags[Mission::Mission_Flags::Player_start_chase_view])
|
||||
{
|
||||
Viewer_mode = VM_CHASE;
|
||||
}
|
||||
|
||||
@@ -220,7 +220,17 @@ ADE_FUNC(isAutoselect, l_UserInterface_PilotSelect, nullptr,
|
||||
"Determines if the pilot selection screen should automatically select the default user.", "boolean",
|
||||
"true if autoselect is enabled, false otherwise")
|
||||
{
|
||||
return ade_set_args(L, "b", Cmdline_benchmark_mode);
|
||||
return ade_set_args(L, "b", Cmdline_benchmark_mode || Cmdline_pilot);
|
||||
}
|
||||
|
||||
ADE_VIRTVAR(CmdlinePilot, l_UserInterface_PilotSelect, nullptr,
|
||||
"The pilot chosen from commandline, if any.", "string",
|
||||
"The name if specified, nil otherwise")
|
||||
{
|
||||
if (Cmdline_pilot)
|
||||
return ade_set_args(L, "s", Cmdline_pilot);
|
||||
else
|
||||
return ADE_RETURN_NIL;
|
||||
}
|
||||
|
||||
//**********SUBLIBRARY: UserInterface/MainHall
|
||||
|
||||
@@ -643,15 +643,12 @@ ADE_FUNC(rotateTurret, l_Subsystem, "vector Pos, boolean reset=false", "Rotates
|
||||
return ADE_RETURN_NIL;
|
||||
|
||||
//Get default turret info
|
||||
vec3d gpos;
|
||||
model_subsystem *tp = sso->ss->system_info;
|
||||
object *objp = sso->objp;
|
||||
ship_get_global_turret_info(objp, tp, &gpos, nullptr);
|
||||
|
||||
auto pmi = model_get_instance(Ships[objp->instance].model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
int ret_val = model_rotate_gun(objp, pm, pmi, tp, &pos, reset);
|
||||
int ret_val = model_rotate_gun(objp, pm, pmi, sso->ss, &pos, reset);
|
||||
|
||||
if (ret_val)
|
||||
return ADE_RETURN_TRUE;
|
||||
@@ -697,7 +694,7 @@ ADE_FUNC(getFOVs, l_Subsystem, nullptr, "Returns current turrets FOVs", "number,
|
||||
|
||||
fov = tp->turret_fov;
|
||||
fov_e = tp->turret_max_fov;
|
||||
fov_y = tp->turret_y_fov;
|
||||
fov_y = tp->turret_base_fov;
|
||||
|
||||
return ade_set_args(L, "fff", fov, fov_e, fov_y);
|
||||
}
|
||||
|
||||
@@ -231,6 +231,7 @@ ADE_VIRTVAR(HomingPosition, l_Weapon, "vector", "Position that weapon will home
|
||||
{
|
||||
wp->homing_pos = vmd_zero_vector;
|
||||
}
|
||||
|
||||
// need to update the position for multiplayer.
|
||||
if (Game_mode & GM_MULTIPLAYER) {
|
||||
wp->weapon_flags.set(Weapon::Weapon_Flags::Multi_homing_update_needed);
|
||||
@@ -273,6 +274,7 @@ ADE_VIRTVAR(HomingSubsystem, l_Weapon, "subsystem", "Subsystem that weapon will
|
||||
wp->homing_pos = vmd_zero_vector;
|
||||
wp->homing_subsys = NULL;
|
||||
}
|
||||
|
||||
// need to update the position for multiplayer.
|
||||
if (Game_mode & GM_MULTIPLAYER) {
|
||||
wp->weapon_flags.set(Weapon::Weapon_Flags::Multi_homing_update_needed);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "scripting/doc_json.h"
|
||||
#include "scripting/scripting_doc.h"
|
||||
#include "ship/ship.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "weapon/beam.h"
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
@@ -672,6 +673,7 @@ void script_state::UnloadImages()
|
||||
|
||||
int script_state::RunCondition(int action, object* objp, int more_data)
|
||||
{
|
||||
TRACE_SCOPE(tracing::LuaHooks);
|
||||
int num = 0;
|
||||
|
||||
if (LuaState == nullptr) {
|
||||
|
||||
+10
-4
@@ -25,6 +25,7 @@
|
||||
#include "species_defs/species_defs.h"
|
||||
#include "tracing/Monitor.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "nebula/neb.h"
|
||||
|
||||
int Show_shield_mesh = 0;
|
||||
|
||||
@@ -490,18 +491,23 @@ void render_shield(int shield_num)
|
||||
|
||||
float alpha = 0.9999f;
|
||||
if(The_mission.flags[Mission::Mission_Flags::Fullneb]){
|
||||
alpha *= 0.85f;
|
||||
alpha *= neb2_get_fog_visibility(centerp, NEB_FOG_VISIBILITY_MULT_SHIELD);
|
||||
}
|
||||
|
||||
ubyte r, g, b;
|
||||
r = (ubyte)(Shield_hits[shield_num].rgb[0] * alpha);
|
||||
g = (ubyte)(Shield_hits[shield_num].rgb[1] * alpha);
|
||||
b = (ubyte)(Shield_hits[shield_num].rgb[2] * alpha);
|
||||
|
||||
if ( bitmap_id <= -1 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 2) ) {
|
||||
shield_render_low_detail_bitmap(bitmap_id, alpha, &Global_tris[Shield_hits[shield_num].tri_list[0]], orient, centerp, Shield_hits[shield_num].rgb[0], Shield_hits[shield_num].rgb[1], Shield_hits[shield_num].rgb[2]);
|
||||
shield_render_low_detail_bitmap(bitmap_id, alpha, &Global_tris[Shield_hits[shield_num].tri_list[0]], orient, centerp, r, g, b);
|
||||
} else if ( Detail.shield_effects < 4 ) {
|
||||
for ( int i = 0; i < Shield_hits[shield_num].num_tris; i++ ) {
|
||||
shield_render_triangle(bitmap_id, alpha, &Global_tris[Shield_hits[shield_num].tri_list[i]], orient, centerp, Shield_hits[shield_num].rgb[0], Shield_hits[shield_num].rgb[1], Shield_hits[shield_num].rgb[2]);
|
||||
shield_render_triangle(bitmap_id, alpha, &Global_tris[Shield_hits[shield_num].tri_list[i]], orient, centerp, r, g, b);
|
||||
}
|
||||
} else {
|
||||
float hit_radius = pm->core_radius;
|
||||
@@ -510,7 +516,7 @@ void render_shield(int shield_num)
|
||||
}
|
||||
|
||||
color clr;
|
||||
gr_init_alphacolor(&clr, Shield_hits[shield_num].rgb[0], Shield_hits[shield_num].rgb[1], Shield_hits[shield_num].rgb[2], fl2i(alpha * 255.0f));
|
||||
gr_init_alphacolor(&clr, r, g, b, fl2i(alpha * 255.0f));
|
||||
shield_render_decal(pm, orient, centerp, &Shield_hits[shield_num].hit_orient, &Shield_hits[shield_num].hit_pos, hit_radius, bitmap_id, &clr);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-7
@@ -351,6 +351,7 @@ flag_def_list_new<Info_Flags> Ship_flags[] = {
|
||||
{ "don't clamp max velocity", Info_Flags::Dont_clamp_max_velocity, true, false },
|
||||
{ "instantaneous acceleration", Info_Flags::Instantaneous_acceleration, true, false },
|
||||
{ "large ship deathroll", Info_Flags::Large_ship_deathroll, true, false },
|
||||
{ "no impact debris", Info_Flags::No_impact_debris, true, false },
|
||||
// to keep things clean, obsolete options go last
|
||||
{ "ballistic primaries", Info_Flags::Ballistic_primaries, false, false }
|
||||
};
|
||||
@@ -2653,6 +2654,8 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
if (optional_string("$Alt name:") || optional_string("$Display Name:"))
|
||||
{
|
||||
stuff_string(sip->display_name, F_NAME, NAME_LENGTH);
|
||||
end_string_at_first_hash_symbol(sip->display_name, true);
|
||||
consolidate_double_characters(sip->display_name, '#');
|
||||
sip->flags.set(Ship::Info_Flags::Has_display_name);
|
||||
}
|
||||
|
||||
@@ -4815,7 +4818,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
stuff_int(&value);
|
||||
CAP(value, 0, 359);
|
||||
float angle = fl_radians(value)/2.0f;
|
||||
sp->turret_y_fov = cosf(angle);
|
||||
sp->turret_base_fov = cosf(angle);
|
||||
turret_has_base_fov = true;
|
||||
}
|
||||
|
||||
@@ -4914,7 +4917,7 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
}
|
||||
|
||||
if (turret_has_base_fov)
|
||||
sp->flags.set(Model::Subsystem_Flags::Turret_alt_math);
|
||||
sp->flags.set(Model::Subsystem_Flags::Turret_restricted_fov);
|
||||
|
||||
if (optional_string("+non-targetable")) {
|
||||
Warning(LOCATION, "Grammar error in table file. Please change \"+non-targetable\" to \"+untargetable\".");
|
||||
@@ -5206,6 +5209,7 @@ static void parse_ship_type(const char *filename, const bool replace)
|
||||
create_if_not_found = false;
|
||||
}
|
||||
|
||||
bool first_time;
|
||||
int idx = ship_type_name_lookup(name_buf);
|
||||
if (idx >= 0)
|
||||
{
|
||||
@@ -5218,6 +5222,7 @@ static void parse_ship_type(const char *filename, const bool replace)
|
||||
return;
|
||||
}
|
||||
stp = &Ship_types[idx];
|
||||
first_time = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5231,6 +5236,7 @@ static void parse_ship_type(const char *filename, const bool replace)
|
||||
Ship_types.push_back(ship_type_info());
|
||||
stp = &Ship_types.back();
|
||||
strcpy_s(stp->name, name_buf);
|
||||
first_time = true;
|
||||
}
|
||||
|
||||
const char *ship_type = NULL;
|
||||
@@ -5250,6 +5256,15 @@ static void parse_ship_type(const char *filename, const bool replace)
|
||||
Warning(LOCATION, "Bad ship type name in %s\n\nUsed ship type is redirected to another ship type.\nReplace \"%s\" with \"%s\"\nin %s to fix this.\n", filename, stp->name, ship_type, filename);
|
||||
}
|
||||
|
||||
bool big_ship = false;
|
||||
bool huge_ship = false;
|
||||
if (stricmp(stp->name, "cruiser") == 0 || stricmp(stp->name, "freighter") == 0 || stricmp(stp->name, "transport") == 0 ||
|
||||
stricmp(stp->name, "corvette") == 0 || stricmp(stp->name, "gas miner") == 0 || stricmp(stp->name, "awacs") == 0)
|
||||
big_ship = true;
|
||||
|
||||
if (stricmp(stp->name, "capital") == 0 || stricmp(stp->name, "super cap") == 0 || stricmp(stp->name, "knossos device") == 0 || stricmp(stp->name, "drydock") == 0)
|
||||
huge_ship = true;
|
||||
|
||||
//Okay, now we should have the values to parse
|
||||
//But they aren't here!! :O
|
||||
//Now they are!! Whee fogging!!
|
||||
@@ -5414,6 +5429,8 @@ static void parse_ship_type(const char *filename, const bool replace)
|
||||
|
||||
if (optional_string("+Targeted by 'Huge' weapons and Ignored by 'small only' weapons:")) {
|
||||
stuff_boolean_flag(stp->flags, Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only);
|
||||
} else if (first_time && (big_ship || huge_ship)) {
|
||||
stp->flags.set(Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17286,11 +17303,10 @@ int is_support_allowed(object *objp, bool do_simple_check)
|
||||
{
|
||||
// multiplayer version behaves differently. Depending on mode:
|
||||
// 1) coop mode -- only available to friendly
|
||||
// 2) team v team mode -- Cyborg17 Has an incomplete implementation for now. Enemy teams can basically "steal" the opponent's SS and break multi.
|
||||
// A fix is on the todo list.
|
||||
// 2) team v team mode -- availble to either side
|
||||
// 3) dogfight -- never
|
||||
|
||||
if(!MULTI_COOP)
|
||||
if(Netgame.type_flags & NG_TYPE_DOGFIGHT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -19688,8 +19704,8 @@ void ship_render(object* obj, model_draw_list* scene)
|
||||
if ( !( shipp->flags[Ship_Flags::Cloaked] ) ) {
|
||||
if ( ( The_mission.flags[Mission::Mission_Flags::Fullneb] ) && ( sip->is_small_ship() ) ) {
|
||||
// force detail levels
|
||||
float fog_val = neb2_get_fog_intensity(obj);
|
||||
if ( fog_val >= 0.6f ) {
|
||||
float fog_val = neb2_get_fog_visibility(obj);
|
||||
if ( fog_val <= 0.15f ) {
|
||||
render_info.set_detail_level_lock(2);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1765,7 +1765,7 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
|
||||
|
||||
// return 1 if objp is in fov of the specified turret, tp. Otherwise return 0.
|
||||
// dist = distance from turret to center point of object
|
||||
int object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist);
|
||||
bool object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist);
|
||||
|
||||
// functions for testing fov.. returns true if fov test is passed.
|
||||
bool turret_std_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod = 0);
|
||||
|
||||
@@ -198,6 +198,7 @@ namespace Ship {
|
||||
Instantaneous_acceleration, // Goober5000
|
||||
Has_display_name, // Goober5000
|
||||
Large_ship_deathroll, // Asteroth - big ships dont normally deathroll, this makes them do it!
|
||||
No_impact_debris, // wookieejedi - Don't spawn the small debris on impact
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+24
-17
@@ -517,7 +517,8 @@ float do_subobj_hit_stuff(object *ship_objp, object *other_obj, vec3d *hitpos, i
|
||||
if (!global_damage) {
|
||||
auto subsys = ship_get_subsys_for_submodel(ship_p, submodel_num);
|
||||
|
||||
if (subsys == nullptr || !subsys->system_info->flags[Model::Subsystem_Flags::No_impact_debris]) {
|
||||
if ( !(Ship_info[ship_p->ship_info_index].flags[Ship::Info_Flags::No_impact_debris]) &&
|
||||
( subsys == nullptr || !(subsys->system_info->flags[Model::Subsystem_Flags::No_impact_debris]) ) ) {
|
||||
create_generic_debris(ship_objp, hitpos, 1.0f, 5.0f, 1.0f, false);
|
||||
}
|
||||
}
|
||||
@@ -802,30 +803,36 @@ static void shiphit_record_player_killer(object *killer_objp, player *p)
|
||||
case OBJ_WEAPON:
|
||||
p->killer_objtype=OBJ_WEAPON;
|
||||
p->killer_weapon_index=Weapons[killer_objp->instance].weapon_info_index;
|
||||
p->killer_species = Ship_info[Ships[Objects[killer_objp->parent].instance].ship_info_index].species;
|
||||
if (killer_objp->parent >= 0 && killer_objp->parent < MAX_OBJECTS) {
|
||||
p->killer_species = Ship_info[Ships[Objects[killer_objp->parent].instance].ship_info_index].species;
|
||||
|
||||
if ( &Objects[killer_objp->parent] == Player_obj ) {
|
||||
// killed by a missile?
|
||||
if(Weapon_info[p->killer_weapon_index].subtype == WP_MISSILE){
|
||||
p->flags |= PLAYER_FLAGS_KILLED_SELF_MISSILES;
|
||||
} else {
|
||||
p->flags |= PLAYER_FLAGS_KILLED_SELF_UNKNOWN;
|
||||
if ( &Objects[killer_objp->parent] == Player_obj ) {
|
||||
// killed by a missile?
|
||||
if(Weapon_info[p->killer_weapon_index].subtype == WP_MISSILE){
|
||||
p->flags |= PLAYER_FLAGS_KILLED_SELF_MISSILES;
|
||||
} else {
|
||||
p->flags |= PLAYER_FLAGS_KILLED_SELF_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// in multiplayer, record callsign of killer if killed by another player
|
||||
if ( (Game_mode & GM_MULTIPLAYER) && ( Objects[killer_objp->parent].flags[Object::Object_Flags::Player_ship]) ) {
|
||||
int pnum;
|
||||
// in multiplayer, record callsign of killer if killed by another player
|
||||
if ( (Game_mode & GM_MULTIPLAYER) && ( Objects[killer_objp->parent].flags[Object::Object_Flags::Player_ship]) ) {
|
||||
int pnum;
|
||||
|
||||
pnum = multi_find_player_by_object( &Objects[killer_objp->parent] );
|
||||
if ( pnum != -1 ) {
|
||||
strcpy_s(p->killer_parent_name, Net_players[pnum].m_player->callsign);
|
||||
pnum = multi_find_player_by_object( &Objects[killer_objp->parent] );
|
||||
if ( pnum != -1 ) {
|
||||
strcpy_s(p->killer_parent_name, Net_players[pnum].m_player->callsign);
|
||||
} else {
|
||||
nprintf(("Network", "Couldn't find player object of weapon for killer of %s\n", p->callsign));
|
||||
}
|
||||
} else {
|
||||
nprintf(("Network", "Couldn't find player object of weapon for killer of %s\n", p->callsign));
|
||||
strcpy_s(p->killer_parent_name, Ships[Objects[killer_objp->parent].instance].get_display_name());
|
||||
}
|
||||
} else {
|
||||
strcpy_s(p->killer_parent_name, Ships[Objects[killer_objp->parent].instance].get_display_name());
|
||||
p->killer_species = -1;
|
||||
strcpy_s(p->killer_parent_name, "");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OBJ_SHOCKWAVE:
|
||||
|
||||
@@ -124,6 +124,8 @@ add_file_folder("CFile"
|
||||
cfile/cfilelist.cpp
|
||||
cfile/cfilesystem.cpp
|
||||
cfile/cfilesystem.h
|
||||
cfile/cfilecompression.cpp
|
||||
cfile/cfilecompression.h
|
||||
)
|
||||
|
||||
# Cmdline files
|
||||
|
||||
@@ -13,6 +13,7 @@ bool Category::usesGPUCounter() const {
|
||||
}
|
||||
|
||||
Category LuaOnFrame("LUA On Frame", true);
|
||||
Category LuaHooks("LUA hooks", true);
|
||||
|
||||
Category DrawSceneTexture("Draw scene texture", true);
|
||||
Category UpdateDistortion("Update distortion", true);
|
||||
|
||||
@@ -26,6 +26,7 @@ class Category {
|
||||
};
|
||||
|
||||
extern Category LuaOnFrame;
|
||||
extern Category LuaHooks;
|
||||
|
||||
extern Category DrawSceneTexture;
|
||||
extern Category UpdateDistortion;
|
||||
|
||||
@@ -156,4 +156,88 @@ size_t encoded_size(codepoint_t cp) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool string_is_ascii_only(const char* str, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (str[i] > 0x79 || str[i] < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* get_encoding_string(Encoding encoding) {
|
||||
switch (encoding) {
|
||||
case Encoding::Encoding_iso8859_1:
|
||||
return "ISO-8859-1";
|
||||
case Encoding::Encoding_utf8:
|
||||
return "UTF-8";
|
||||
case Encoding::Encoding_current:
|
||||
default:
|
||||
UNREACHABLE("Unknown encoding type was passed.\n");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
bool convert_encoding(SCP_string& buffer, const char* src, Encoding encoding_src, Encoding encoding_dest) {
|
||||
|
||||
if (encoding_src == Encoding::Encoding_current)
|
||||
encoding_src = Unicode_text_mode ? Encoding::Encoding_utf8 : Encoding::Encoding_iso8859_1;
|
||||
|
||||
if (encoding_dest == Encoding::Encoding_current)
|
||||
encoding_dest = Unicode_text_mode ? Encoding::Encoding_utf8 : Encoding::Encoding_iso8859_1;
|
||||
|
||||
//We are already in the correct encoding, the string is correct
|
||||
if (encoding_src == encoding_dest) {
|
||||
buffer.assign(src);
|
||||
return true;
|
||||
}
|
||||
|
||||
//If not, convert
|
||||
auto len = strlen(src);
|
||||
|
||||
// Validate if no change needs to be done
|
||||
if (string_is_ascii_only(src, len))
|
||||
{
|
||||
// turns out this is valid anyways
|
||||
buffer.assign(src);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t newlen = len;
|
||||
std::unique_ptr<char[]> newstr(new char[newlen]);
|
||||
|
||||
do {
|
||||
auto in_str = src;
|
||||
auto in_size = len;
|
||||
auto out_str = newstr.get();
|
||||
auto out_size = newlen;
|
||||
|
||||
auto iconv = SDL_iconv_open(get_encoding_string(encoding_dest), get_encoding_string(encoding_src));
|
||||
auto err = SDL_iconv(iconv, &in_str, &in_size, &out_str, &out_size);
|
||||
SDL_iconv_close(iconv);
|
||||
|
||||
// SDL returns the number of processed character on success;
|
||||
// error codes are (size_t)-1 through -4
|
||||
if (err < (size_t)-100)
|
||||
{
|
||||
// successful re-encoding
|
||||
buffer.assign(newstr.get(), newlen - out_size);
|
||||
return true;
|
||||
}
|
||||
else if (err == SDL_ICONV_E2BIG)
|
||||
{
|
||||
// buffer is not big enough, try again with a bigger buffer. Use a rather conservative size
|
||||
// increment since the additional size required is probably pretty small
|
||||
newlen += 10;
|
||||
newstr.reset(new char[newlen]);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -163,4 +163,9 @@ void advance(octet_iterator& start, size_t n, octet_iterator end) {
|
||||
}
|
||||
}
|
||||
|
||||
enum class Encoding { Encoding_current, Encoding_utf8, Encoding_iso8859_1 };
|
||||
|
||||
bool string_is_ascii_only(const char* str, size_t len);
|
||||
const char* get_encoding_string(Encoding encoding);
|
||||
bool convert_encoding(SCP_string& buffer, const char* src, Encoding encoding_src, Encoding encoding_dest = Encoding::Encoding_current);
|
||||
}
|
||||
+29
-10
@@ -26,6 +26,7 @@
|
||||
#include "lighting/lighting.h"
|
||||
#include "math/fvi.h"
|
||||
#include "math/staticrand.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
#include "network/multi.h"
|
||||
#include "network/multimsgs.h"
|
||||
@@ -1351,8 +1352,21 @@ void beam_render(beam *b, float u_offset)
|
||||
framenum = bm_get_anim_frame(bwsi->texture.first_frame, b->beam_section_frame[s_idx], bwsi->texture.total_time, true);
|
||||
}
|
||||
|
||||
float fade = 0.9999f;
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_beams) {
|
||||
vec3d nearest;
|
||||
int result = vm_vec_dist_to_line(&Eye_position, &b->last_start, &b->last_shot, &nearest, nullptr);
|
||||
if (result == 1)
|
||||
nearest = b->last_shot;
|
||||
if (result == -1)
|
||||
nearest = b->last_start;
|
||||
|
||||
fade *= neb2_get_fog_visibility(&nearest, NEB_FOG_VISIBILITY_MULT_BEAM(b->beam_light_width));
|
||||
}
|
||||
|
||||
material material_params;
|
||||
material_set_unlit_emissive(&material_params, bwsi->texture.first_frame + framenum, 0.9999f, 2.0f);
|
||||
material_set_unlit_emissive(&material_params, bwsi->texture.first_frame + framenum, fade, 2.0f);
|
||||
g3_render_primitives_colored_textured(&material_params, h1, 4, PRIM_TYPE_TRIFAN, false);
|
||||
}
|
||||
|
||||
@@ -1437,30 +1451,35 @@ void beam_generate_muzzle_particles(beam *b)
|
||||
}
|
||||
}
|
||||
|
||||
static float get_current_alpha(vec3d *pos)
|
||||
static float get_muzzle_glow_alpha(beam* b)
|
||||
{
|
||||
float dist;
|
||||
float alpha;
|
||||
float alpha = 0.8f;
|
||||
|
||||
const float inner_radius = 15.0f;
|
||||
const float magic_num = 2.75f;
|
||||
|
||||
// determine what alpha to draw this bitmap with
|
||||
// higher alpha the closer the bitmap gets to the eye
|
||||
dist = vm_vec_dist_quick(&Eye_position, pos);
|
||||
dist = vm_vec_dist_quick(&Eye_position, &b->last_start);
|
||||
|
||||
// if the point is inside the inner radius, alpha is based on distance to the player's eye,
|
||||
// becoming more transparent as it gets close
|
||||
if (dist <= inner_radius) {
|
||||
// alpha per meter between the magic # and the inner radius
|
||||
alpha = 0.8f / (inner_radius - magic_num);
|
||||
alpha /= (inner_radius - magic_num);
|
||||
|
||||
// above value times the # of meters away we are
|
||||
alpha *= (dist - magic_num);
|
||||
return (alpha < 0.005f) ? 0.0f : alpha;
|
||||
if (alpha < 0.005f)
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 0.8f;
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_beams) {
|
||||
alpha *= neb2_get_fog_visibility(&b->last_start, NEB_FOG_VISIBILITY_MULT_B_MUZZLE(b->beam_light_width));
|
||||
}
|
||||
|
||||
return alpha;
|
||||
}
|
||||
|
||||
// render the muzzle glow for a beam weapon
|
||||
@@ -1507,7 +1526,7 @@ void beam_render_muzzle_glow(beam *b)
|
||||
if (rad <= 0.0f)
|
||||
return;
|
||||
|
||||
float alpha = get_current_alpha(&b->last_start);
|
||||
float alpha = get_muzzle_glow_alpha(b);
|
||||
|
||||
if (alpha <= 0.0f)
|
||||
return;
|
||||
@@ -3567,9 +3586,9 @@ int beam_ok_to_fire(beam *b)
|
||||
|
||||
if (b->flags & BF_IS_FIGHTER_BEAM) {
|
||||
turret_normal = b->objp->orient.vec.fvec;
|
||||
b->subsys->system_info->flags.remove(Model::Subsystem_Flags::Turret_alt_math);
|
||||
b->subsys->system_info->flags.remove(Model::Subsystem_Flags::Turret_restricted_fov);
|
||||
} else {
|
||||
model_instance_find_world_dir(&turret_normal, &b->subsys->system_info->turret_norm, Ships[b->objp->instance].model_instance_num, b->subsys->system_info->subobj_num, &b->objp->orient);
|
||||
model_instance_find_world_dir(&turret_normal, &b->subsys->system_info->turret_norm, Ships[b->objp->instance].model_instance_num, b->subsys->system_info->subobj_num, &b->objp->orient, true);
|
||||
}
|
||||
|
||||
if (!(turret_fov_test(b->subsys, &turret_normal, &aim_dir))) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "globalincs/linklist.h"
|
||||
#include "io/timer.h"
|
||||
#include "model/modelrender.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "object/object.h"
|
||||
#include "options/Option.h"
|
||||
#include "render/3d.h"
|
||||
@@ -392,6 +393,11 @@ void shockwave_render(object *objp, model_draw_list *scene)
|
||||
if ( (sw->current_bitmap < 0) && (sw->model_id < 0) )
|
||||
return;
|
||||
|
||||
|
||||
float alpha = 1.0f;
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_weapons)
|
||||
alpha *= neb2_get_fog_visibility(&objp->pos, NEB_FOG_VISIBILITY_MULT_SHOCKWAVE);
|
||||
|
||||
if (sw->model_id > -1) {
|
||||
vec3d scale;
|
||||
scale.xyz.x = scale.xyz.y = scale.xyz.z = sw->radius / 50.0f;
|
||||
@@ -422,7 +428,7 @@ void shockwave_render(object *objp, model_draw_list *scene)
|
||||
batching_add_distortion_bitmap_rotated(sw->current_bitmap, &p, fl_radians(sw->rot_angles.p), sw->radius, intensity);
|
||||
}
|
||||
|
||||
batching_add_volume_bitmap_rotated(sw->current_bitmap, &p, fl_radians(sw->rot_angles.p), sw->radius);
|
||||
batching_add_volume_bitmap_rotated(sw->current_bitmap, &p, fl_radians(sw->rot_angles.p), sw->radius, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "io/timer.h"
|
||||
#include "mission/missionparse.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "render/3d.h"
|
||||
#include "ship/ship.h"
|
||||
#include "tracing/tracing.h"
|
||||
@@ -224,6 +226,9 @@ void trail_render( trail * trailp )
|
||||
l = (ubyte)fl2i((fade * a_size + ti->a_start) * 255.0f);
|
||||
}
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb])
|
||||
l = (ubyte)(l * neb2_get_fog_visibility(&trailp->pos[n], NEB_FOG_VISIBILITY_MULT_TRAIL));
|
||||
|
||||
if ( i == 0 ) {
|
||||
if ( num_sections > 1 ) {
|
||||
vm_vec_sub(&tmp_fvec, &trailp->pos[n], &trailp->pos[sections[i+1]] );
|
||||
|
||||
@@ -344,6 +344,9 @@ struct weapon_info
|
||||
float weapon_range; // max range weapon can be effectively fired. (May be less than life * speed)
|
||||
float WeaponMinRange; // *Minimum weapon range, default is 0 -Et1
|
||||
|
||||
bool pierce_objects;
|
||||
bool spawn_children_on_pierce;
|
||||
|
||||
// spawn weapons
|
||||
int num_spawn_weapons_defined;
|
||||
int maximum_children_spawned; // An upper bound for the total number of spawned children, used by multi
|
||||
|
||||
+66
-40
@@ -28,6 +28,7 @@
|
||||
#include "math/staticrand.h"
|
||||
#include "missionui/missionweaponchoice.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "network/multi.h"
|
||||
#include "network/multimsgs.h"
|
||||
#include "network/multiutil.h"
|
||||
@@ -894,7 +895,8 @@ int parse_weapon(int subtype, bool replace, const char *filename)
|
||||
// if this name has a hash, create a default display name
|
||||
if (get_pointer_to_first_hash_symbol(wip->name)) {
|
||||
strcpy_s(wip->display_name, wip->name);
|
||||
end_string_at_first_hash_symbol(wip->display_name);
|
||||
end_string_at_first_hash_symbol(wip->display_name, true);
|
||||
consolidate_double_characters(wip->display_name, '#');
|
||||
wip->wi_flags.set(Weapon::Info_Flags::Has_display_name);
|
||||
preset_wi_flags.set(Weapon::Info_Flags::Has_display_name);
|
||||
}
|
||||
@@ -1754,6 +1756,14 @@ int parse_weapon(int subtype, bool replace, const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("$Pierce Objects:")) {
|
||||
stuff_boolean(&wip->pierce_objects);
|
||||
|
||||
if (optional_string("+Spawn Children On Pierce:")) {
|
||||
stuff_boolean(&wip->spawn_children_on_pierce);
|
||||
}
|
||||
}
|
||||
|
||||
parse_wi_flags(wip, preset_wi_flags);
|
||||
|
||||
// preset_wi_flags does not need to be maintained after the above function is called
|
||||
@@ -5149,8 +5159,9 @@ void weapon_process_post(object * obj, float frame_time)
|
||||
if ( !MULTIPLAYER_CLIENT || (MULTIPLAYER_CLIENT && (wip->wi_flags[Weapon::Info_Flags::Child]))) { // don't call this function multiplayer client -- host will send this packet to us
|
||||
weapon_detonate(obj);
|
||||
}
|
||||
|
||||
if (MULTIPLAYER_MASTER) {
|
||||
send_weapon_kill_packet(obj);
|
||||
send_missile_kill_packet(obj);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -6834,40 +6845,6 @@ void weapon_hit( object * weapon_obj, object * other_obj, vec3d * hitpos, int qu
|
||||
}
|
||||
}
|
||||
|
||||
// For all objects that had this weapon as a target, wipe it out, forcing find of a new enemy
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
||||
other_objp = &Objects[so->objnum];
|
||||
Assert(other_objp->instance != -1);
|
||||
|
||||
shipp = &Ships[other_objp->instance];
|
||||
Assert(shipp->ai_index != -1);
|
||||
|
||||
ai_info *aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
if (aip->target_objnum == objnum) {
|
||||
set_target_objnum(aip, -1);
|
||||
// If this ship had a dynamic goal of chasing this weapon, clear the dynamic goal.
|
||||
if (aip->resume_goal_time != -1)
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
}
|
||||
|
||||
if (aip->goal_objnum == objnum) {
|
||||
aip->goal_objnum = -1;
|
||||
aip->goal_signature = -1;
|
||||
}
|
||||
|
||||
if (aip->guard_objnum == objnum) {
|
||||
aip->guard_objnum = -1;
|
||||
aip->guard_signature = -1;
|
||||
}
|
||||
|
||||
if (aip->hitter_objnum == objnum) {
|
||||
aip->hitter_objnum = -1;
|
||||
}
|
||||
}
|
||||
|
||||
weapon_obj->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
|
||||
//Set shockwaves flag
|
||||
int sw_flag = SW_WEAPON;
|
||||
|
||||
@@ -6909,13 +6886,53 @@ void weapon_hit( object * weapon_obj, object * other_obj, vec3d * hitpos, int qu
|
||||
}
|
||||
}
|
||||
|
||||
// spawn weapons - note the change from FS 1 multiplayer.
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Spawn]){
|
||||
if (!((wip->wi_flags[Weapon::Info_Flags::Dont_spawn_if_shot]) && (Weapons[num].weapon_flags[Weapon::Weapon_Flags::Destroyed_by_weapon]))){ // prevent spawning of children if shot down and the dont spawn if shot flag is set (DahBlount)
|
||||
spawn_child_weapons(weapon_obj);
|
||||
if (!wip->pierce_objects || wip->spawn_children_on_pierce || !other_obj) {
|
||||
// spawn weapons - note the change from FS 1 multiplayer.
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Spawn]) {
|
||||
if (!((wip->wi_flags[Weapon::Info_Flags::Dont_spawn_if_shot]) && (Weapons[num].weapon_flags[Weapon::Weapon_Flags::Destroyed_by_weapon]))) { // prevent spawning of children if shot down and the dont spawn if shot flag is set (DahBlount)
|
||||
spawn_child_weapons(weapon_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//No other_obj means this weapon detonates
|
||||
if (wip->pierce_objects && other_obj)
|
||||
return;
|
||||
|
||||
// For all objects that had this weapon as a target, wipe it out, forcing find of a new enemy
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
||||
other_objp = &Objects[so->objnum];
|
||||
Assert(other_objp->instance != -1);
|
||||
|
||||
shipp = &Ships[other_objp->instance];
|
||||
Assert(shipp->ai_index != -1);
|
||||
|
||||
ai_info *aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
if (aip->target_objnum == objnum) {
|
||||
set_target_objnum(aip, -1);
|
||||
// If this ship had a dynamic goal of chasing this weapon, clear the dynamic goal.
|
||||
if (aip->resume_goal_time != -1)
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
}
|
||||
|
||||
if (aip->goal_objnum == objnum) {
|
||||
aip->goal_objnum = -1;
|
||||
aip->goal_signature = -1;
|
||||
}
|
||||
|
||||
if (aip->guard_objnum == objnum) {
|
||||
aip->guard_objnum = -1;
|
||||
aip->guard_signature = -1;
|
||||
}
|
||||
|
||||
if (aip->hitter_objnum == objnum) {
|
||||
aip->hitter_objnum = -1;
|
||||
}
|
||||
}
|
||||
|
||||
weapon_obj->flags.set(Object::Object_Flags::Should_be_dead);
|
||||
|
||||
// decrement parent's number of active remote detonators if applicable
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Remote] && weapon_obj->parent >= 0 && (weapon_obj->parent < MAX_OBJECTS)) {
|
||||
object* parent = &Objects[weapon_obj->parent];
|
||||
@@ -7989,6 +8006,9 @@ void weapon_render(object* obj, model_draw_list *scene)
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Transparent])
|
||||
alpha = fl2i(wp->alpha_current * 255.0f);
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_weapons)
|
||||
alpha = (int)(alpha * neb2_get_fog_visibility(&obj->pos, NEB_FOG_VISIBILITY_MULT_WEAPON));
|
||||
|
||||
vec3d headp;
|
||||
|
||||
vm_vec_scale_add(&headp, &obj->pos, &obj->orient.vec.fvec, wip->laser_length);
|
||||
@@ -8037,6 +8057,9 @@ void weapon_render(object* obj, model_draw_list *scene)
|
||||
alpha = weapon_glow_alpha;
|
||||
}
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_weapons)
|
||||
alpha = (int)(alpha * neb2_get_fog_visibility(&obj->pos, NEB_FOG_VISIBILITY_MULT_WEAPON));
|
||||
|
||||
batching_add_laser(wip->laser_glow_bitmap.first_frame + framenum, &headp2, wip->laser_head_radius * weapon_glow_scale_f, &tailp, wip->laser_tail_radius * weapon_glow_scale_r, (c.red*alpha)/255, (c.green*alpha)/255, (c.blue*alpha)/255);
|
||||
}
|
||||
|
||||
@@ -8276,6 +8299,9 @@ void weapon_info::reset()
|
||||
// *Minimum weapon range, default is 0 -Et1
|
||||
this->WeaponMinRange = 0.0f;
|
||||
|
||||
this->pierce_objects = false;
|
||||
this->spawn_children_on_pierce = false;
|
||||
|
||||
this->num_spawn_weapons_defined = 0;
|
||||
this->maximum_children_spawned = 0;
|
||||
for (i = 0; i < MAX_SPAWN_TYPES_PER_WEAPON; i++)
|
||||
|
||||
@@ -65,6 +65,7 @@ event_editor::event_editor(CWnd* pParent /*=NULL*/)
|
||||
m_persona = -1;
|
||||
m_wave_filename = _T("");
|
||||
m_cur_msg = -1;
|
||||
m_cur_msg_old = -1;
|
||||
m_team = -1;
|
||||
m_message_team = -1;
|
||||
m_last_message_node = -1;
|
||||
@@ -87,6 +88,9 @@ event_editor::event_editor(CWnd* pParent /*=NULL*/)
|
||||
|
||||
void event_editor::DoDataExchange(CDataExchange* pDX)
|
||||
{
|
||||
if (m_cur_msg >= 0)
|
||||
m_cur_msg_old = m_cur_msg;
|
||||
|
||||
CDialog::DoDataExchange(pDX);
|
||||
//{{AFX_DATA_MAP(event_editor)
|
||||
DDX_Control(pDX, IDC_EVENT_TREE, m_event_tree);
|
||||
@@ -114,7 +118,6 @@ void event_editor::DoDataExchange(CDataExchange* pDX)
|
||||
DDX_Check(pDX, IDC_MISSION_LOG_LAST_TRIGGER, m_log_last_trigger);
|
||||
DDX_Check(pDX, IDC_MISSION_LOG_STATE_CHANGE, m_log_state_change);
|
||||
|
||||
|
||||
// m_team == -1 maps to 2
|
||||
if(m_team == -1){
|
||||
m_team = MAX_TVT_TEAMS;
|
||||
@@ -910,7 +913,7 @@ void event_editor::insert_handler(int old, int node)
|
||||
|
||||
void event_editor::save()
|
||||
{
|
||||
int m = m_cur_msg;
|
||||
int m = (m_cur_msg >= 0) ? m_cur_msg : m_cur_msg_old;
|
||||
|
||||
save_event(cur_event);
|
||||
save_message(m);
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ public:
|
||||
CString m_message_text;
|
||||
int m_persona;
|
||||
CString m_wave_filename;
|
||||
int m_cur_msg;
|
||||
int m_cur_msg, m_cur_msg_old;
|
||||
int m_team;
|
||||
int m_message_team;
|
||||
int m_last_message_node;
|
||||
|
||||
+5
-3
@@ -902,7 +902,9 @@ BEGIN
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,151,123,10
|
||||
CONTROL "Player Starts under AI Control (NO MULTI)",IDC_PLAYER_START_AI,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,161,146,10
|
||||
CONTROL "2D Mission",IDC_2D_MISSION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,171,123,10
|
||||
CONTROL "Player Starts in Chase View",IDC_PLAYER_START_CHASE,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,171,146,10
|
||||
CONTROL "2D Mission",IDC_2D_MISSION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,181,123,10
|
||||
LTEXT "AI Profile",IDC_STATIC,320,229,32,8
|
||||
COMBOBOX IDC_AI_PROFILE,378,226,93,140,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Mission Description",IDC_STATIC,4,260,62,8
|
||||
@@ -916,8 +918,8 @@ BEGIN
|
||||
CONTROL "",IDC_MAX_RESPAWN_DELAY_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,136,112,11,14
|
||||
PUSHBUTTON "Sound Environment",IDC_SOUND_ENVIRONMENT_BUTTON,158,244,140,15
|
||||
CONTROL "Always Show Mission Goals In Briefing",IDC_ALWAYS_SHOW_GOALS,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,180,142,10
|
||||
CONTROL "Mission End to Mainhall",IDC_END_TO_MAINHALL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,190,142,10
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,191,142,10
|
||||
CONTROL "Mission End to Mainhall",IDC_END_TO_MAINHALL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,326,201,142,10
|
||||
CONTROL "Override #Command in event messages",IDC_OVERRIDE_HASHCOMMAND,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,172,142,10
|
||||
END
|
||||
|
||||
@@ -1125,6 +1125,8 @@ void inc_mission_time() {
|
||||
|
||||
if (Frametime > MAX_FRAMETIME) {
|
||||
Frametime = MAX_FRAMETIME;
|
||||
} else if (Frametime < 0) {
|
||||
Frametime = thistime = MIN_FRAMETIME;
|
||||
} else if (Frametime < MIN_FRAMETIME) {
|
||||
if (!Cmdline_NoFPSCap) {
|
||||
thistime = MIN_FRAMETIME - Frametime;
|
||||
|
||||
+1
-1
@@ -4369,7 +4369,7 @@ void CFREDView::OnUpdateDisableUndo(CCmdUI* pCmdUI)
|
||||
|
||||
void CFREDView::OnUpdateCmdBrief(CCmdUI* pCmdUI)
|
||||
{
|
||||
pCmdUI->Enable(!(The_mission.game_type & MISSION_TYPE_MULTI));
|
||||
pCmdUI->Enable(true);
|
||||
}
|
||||
|
||||
int get_visible_sub_system_count(ship *shipp)
|
||||
|
||||
@@ -67,6 +67,7 @@ CMissionNotesDlg::CMissionNotesDlg(CWnd* pParent /*=NULL*/) : CDialog(CMissionNo
|
||||
m_support_repairs_hull = FALSE;
|
||||
m_beam_free_all_by_default = FALSE;
|
||||
m_player_start_using_ai = FALSE;
|
||||
m_player_start_chase_view = FALSE;
|
||||
m_no_briefing = FALSE;
|
||||
m_no_debriefing = FALSE;
|
||||
m_autpilot_cinematics = FALSE;
|
||||
@@ -120,6 +121,7 @@ void CMissionNotesDlg::DoDataExchange(CDataExchange* pDX)
|
||||
DDX_Check(pDX, IDC_SUPPORT_REPAIRS_HULL, m_support_repairs_hull);
|
||||
DDX_Check(pDX, IDC_BEAM_FREE_ALL_BY_DEFAULT, m_beam_free_all_by_default);
|
||||
DDX_Check(pDX, IDC_PLAYER_START_AI, m_player_start_using_ai);
|
||||
DDX_Check(pDX, IDC_PLAYER_START_CHASE, m_player_start_chase_view);
|
||||
DDX_Check(pDX, IDC_NO_BRIEFING, m_no_briefing);
|
||||
DDX_Check(pDX, IDC_NO_DEBRIEFING, m_no_debriefing);
|
||||
DDX_Check(pDX, IDC_USE_AUTOPILOT_CINEMATICS, m_autpilot_cinematics);
|
||||
@@ -273,6 +275,9 @@ void CMissionNotesDlg::OnOK()
|
||||
// set player AI by default
|
||||
The_mission.flags.set(Mission::Mission_Flags::Player_start_ai, m_player_start_using_ai != 0);
|
||||
|
||||
// set player chase view
|
||||
The_mission.flags.set(Mission::Mission_Flags::Player_start_chase_view, m_player_start_chase_view != 0);
|
||||
|
||||
// set briefing
|
||||
The_mission.flags.set(Mission::Mission_Flags::No_briefing, m_no_briefing != 0);
|
||||
|
||||
@@ -394,6 +399,7 @@ BOOL CMissionNotesDlg::OnInitDialog()
|
||||
m_support_repairs_hull = (The_mission.flags[Mission::Mission_Flags::Support_repairs_hull]) ? 1 : 0;
|
||||
m_beam_free_all_by_default = (The_mission.flags[Mission::Mission_Flags::Beam_free_all_by_default]) ? 1 : 0;
|
||||
m_player_start_using_ai = (The_mission.flags[Mission::Mission_Flags::Player_start_ai]) ? 1 : 0;
|
||||
m_player_start_chase_view = (The_mission.flags[Mission::Mission_Flags::Player_start_chase_view]) ? 1 : 0;
|
||||
m_no_briefing = (The_mission.flags[Mission::Mission_Flags::No_briefing]) ? 1 : 0;
|
||||
m_no_debriefing = (The_mission.flags[Mission::Mission_Flags::Toggle_debriefing]) ? 1 : 0;
|
||||
m_autpilot_cinematics = (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics]) ? 1 : 0;
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
BOOL m_support_repairs_hull;
|
||||
BOOL m_beam_free_all_by_default;
|
||||
BOOL m_player_start_using_ai;
|
||||
BOOL m_player_start_chase_view;
|
||||
BOOL m_no_briefing;
|
||||
BOOL m_no_debriefing;
|
||||
BOOL m_autpilot_cinematics;
|
||||
|
||||
@@ -1371,9 +1371,6 @@ int CFred_mission_save::save_cmd_brief()
|
||||
required_string_fred("#Command Briefing");
|
||||
parse_comments(2);
|
||||
|
||||
if (The_mission.game_type & MISSION_TYPE_MULTI)
|
||||
return err; // no command briefings allowed in multiplayer missions.
|
||||
|
||||
save_custom_bitmap("$Background 640:", "$Background 1024:", Cur_cmd_brief->background[GR_640], Cur_cmd_brief->background[GR_1024], 1);
|
||||
|
||||
for (stage = 0; stage < Cur_cmd_brief->num_stages; stage++) {
|
||||
|
||||
@@ -1054,6 +1054,7 @@
|
||||
#define IDC_EXPORT 1581
|
||||
#define IDC_SECONDARIES_LOCKED 1582
|
||||
#define IDC_SUBSTITUTE_BRIEFING_MUSIC 1582
|
||||
#define IDC_PLAYER_START_CHASE 1583
|
||||
#define IDC_RESTRICT_PATHS_LABEL 1584
|
||||
#define IDC_PATH_LIST 1585
|
||||
#define IDC_BACKGROUND 1586
|
||||
|
||||
+118
-62
@@ -2030,8 +2030,21 @@ void game_show_framerate()
|
||||
gr_set_color_fast(&HUD_color_debug);
|
||||
|
||||
if (Cmdline_frame_profile) {
|
||||
gr_string(gr_screen.center_offset_x + 20, gr_screen.center_offset_y + 100 + line_height,
|
||||
tracing::get_frame_profile_output().c_str(), GR_RESIZE_NONE);
|
||||
// Split frame profile into two columns if necessary to avoid losing trace data
|
||||
int fp_start_y = gr_screen.center_offset_y + 100 + line_height;
|
||||
int fp_line_limit = (gr_screen.max_h - fp_start_y) / line_height;
|
||||
size_t fp_column_break = 0;
|
||||
auto fp_trace_str = tracing::get_frame_profile_output();
|
||||
|
||||
for (int i = 0; i < fp_line_limit && fp_column_break < fp_trace_str.length(); i++) {
|
||||
fp_column_break = fp_trace_str.find_first_of('\n', fp_column_break+1);
|
||||
}
|
||||
|
||||
gr_string(gr_screen.center_offset_x + 20, fp_start_y, fp_trace_str.substr(0,fp_column_break).c_str(), GR_RESIZE_NONE);
|
||||
|
||||
if (fp_column_break < fp_trace_str.length()) {
|
||||
gr_string(gr_screen.max_w / 2, fp_start_y, fp_trace_str.substr(fp_column_break, fp_trace_str.npos).c_str(), GR_RESIZE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (Show_framerate) {
|
||||
@@ -4941,6 +4954,40 @@ void game_process_event( int current_state, int event )
|
||||
}
|
||||
}
|
||||
|
||||
static bool going_to_briefing_state(int new_state)
|
||||
{
|
||||
switch (new_state) {
|
||||
case GS_STATE_TEAM_SELECT:
|
||||
case GS_STATE_SHIP_SELECT:
|
||||
case GS_STATE_WEAPON_SELECT:
|
||||
case GS_STATE_OPTIONS_MENU:
|
||||
case GS_STATE_GAMEPLAY_HELP:
|
||||
case GS_STATE_HOTKEY_SCREEN:
|
||||
case GS_STATE_MULTI_MISSION_SYNC:
|
||||
case GS_STATE_BRIEFING:
|
||||
case GS_STATE_CMD_BRIEF:
|
||||
case GS_STATE_RED_ALERT:
|
||||
case GS_STATE_FICTION_VIEWER:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool going_to_menu_state(int new_state)
|
||||
{
|
||||
switch (new_state) {
|
||||
case GS_STATE_MAIN_MENU:
|
||||
case GS_STATE_PXO:
|
||||
case GS_STATE_MULTI_JOIN_GAME:
|
||||
case GS_STATE_STANDALONE_MAIN:
|
||||
case GS_STATE_QUIT_GAME:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called when a state is being left.
|
||||
// The current state is still at old_state, but as soon as
|
||||
// this function leaves, then the current state will become
|
||||
@@ -4989,17 +5036,15 @@ void game_leave_state( int old_state, int new_state )
|
||||
switch (old_state) {
|
||||
case GS_STATE_BRIEFING:
|
||||
brief_stop_voices();
|
||||
if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
|
||||
&& (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
|
||||
&& (new_state != GS_STATE_TEAM_SELECT) && (new_state != GS_STATE_MULTI_MISSION_SYNC)){
|
||||
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
if ( (new_state == GS_STATE_MAIN_MENU) || (new_state == GS_STATE_PXO)
|
||||
|| (new_state == GS_STATE_MULTI_JOIN_GAME) )
|
||||
{
|
||||
freespace_stop_mission();
|
||||
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// COMMAND LINE OPTION
|
||||
if (Cmdline_multi_stream_chat_to_file){
|
||||
cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
|
||||
@@ -5035,67 +5080,57 @@ void game_leave_state( int old_state, int new_state )
|
||||
cmd_brief_hold();
|
||||
} else {
|
||||
cmd_brief_close();
|
||||
common_select_close();
|
||||
|
||||
if (new_state != GS_STATE_BRIEFING) {
|
||||
common_music_close();
|
||||
}
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
|
||||
if ( (new_state == GS_STATE_MAIN_MENU) || (new_state == GS_STATE_PXO)
|
||||
|| (new_state == GS_STATE_MULTI_JOIN_GAME) )
|
||||
{
|
||||
freespace_stop_mission();
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_STATE_RED_ALERT:
|
||||
red_alert_close();
|
||||
common_select_close();
|
||||
if ( (new_state == GS_STATE_MAIN_MENU) || (new_state == GS_STATE_PXO)
|
||||
|| (new_state == GS_STATE_MULTI_JOIN_GAME) )
|
||||
{
|
||||
freespace_stop_mission();
|
||||
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_STATE_SHIP_SELECT:
|
||||
if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
|
||||
new_state != GS_STATE_HOTKEY_SCREEN &&
|
||||
new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT && (new_state != GS_STATE_MULTI_MISSION_SYNC)) {
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
if ( (new_state == GS_STATE_MAIN_MENU) || (new_state == GS_STATE_PXO)
|
||||
|| (new_state == GS_STATE_MULTI_JOIN_GAME) )
|
||||
{
|
||||
freespace_stop_mission();
|
||||
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_STATE_WEAPON_SELECT:
|
||||
if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
|
||||
new_state != GS_STATE_HOTKEY_SCREEN &&
|
||||
new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT && (new_state != GS_STATE_MULTI_MISSION_SYNC)) {
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
if ( (new_state == GS_STATE_MAIN_MENU) || (new_state == GS_STATE_PXO)
|
||||
|| (new_state == GS_STATE_MULTI_JOIN_GAME) )
|
||||
{
|
||||
freespace_stop_mission();
|
||||
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_STATE_TEAM_SELECT:
|
||||
if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
|
||||
new_state != GS_STATE_HOTKEY_SCREEN &&
|
||||
new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT && (new_state != GS_STATE_MULTI_MISSION_SYNC)) {
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
if ( (new_state == GS_STATE_MAIN_MENU) || (new_state == GS_STATE_PXO)
|
||||
|| (new_state == GS_STATE_MULTI_JOIN_GAME) )
|
||||
{
|
||||
freespace_stop_mission();
|
||||
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_STATE_MAIN_MENU:
|
||||
@@ -5109,6 +5144,12 @@ void game_leave_state( int old_state, int new_state )
|
||||
|
||||
options_menu_close();
|
||||
|
||||
// can't use going_to_briefing_state() here since it doesn't catch sub-optionmenu states
|
||||
// it's basically just to catch the exit game button
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
common_select_close();
|
||||
}
|
||||
|
||||
if (new_state != GS_STATE_CONTROL_CONFIG && new_state != GS_STATE_HUD_CONFIG) {
|
||||
// unpause all sounds, since we could be headed back to the game
|
||||
// only unpause if we're in-mission; we could also be in the main hall
|
||||
@@ -5305,7 +5346,9 @@ void game_leave_state( int old_state, int new_state )
|
||||
break;
|
||||
|
||||
case GS_STATE_MULTI_MISSION_SYNC:
|
||||
common_select_close();
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
}
|
||||
|
||||
// if we're moving into the options menu we don't need to do anything else
|
||||
if(new_state == GS_STATE_OPTIONS_MENU){
|
||||
@@ -5314,6 +5357,7 @@ void game_leave_state( int old_state, int new_state )
|
||||
|
||||
Assert( Game_mode & GM_MULTIPLAYER );
|
||||
multi_sync_close();
|
||||
|
||||
if ( new_state == GS_STATE_GAME_PLAY ){
|
||||
// palette_restore_palette();
|
||||
|
||||
@@ -5323,10 +5367,14 @@ void game_leave_state( int old_state, int new_state )
|
||||
|
||||
// set the game mode
|
||||
Game_mode |= GM_IN_MISSION;
|
||||
|
||||
// any other state needs to close out the mission, because we're not going in to gameplay.
|
||||
} else if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
|
||||
main_hall_stop_music(true);
|
||||
main_hall_stop_ambient();
|
||||
main_hall_stop_ambient();
|
||||
break;
|
||||
|
||||
case GS_STATE_VIEW_CUTSCENES:
|
||||
@@ -5378,16 +5426,13 @@ void game_leave_state( int old_state, int new_state )
|
||||
|
||||
case GS_STATE_FICTION_VIEWER:
|
||||
fiction_viewer_close();
|
||||
common_select_close();
|
||||
|
||||
if ( (new_state != GS_STATE_BRIEFING) && (new_state != GS_STATE_CMD_BRIEF) ) {
|
||||
common_music_close();
|
||||
}
|
||||
if ( !going_to_briefing_state(new_state) ) {
|
||||
common_select_close();
|
||||
|
||||
if ( (new_state == GS_STATE_MAIN_MENU) || (new_state == GS_STATE_PXO)
|
||||
|| (new_state == GS_STATE_MULTI_JOIN_GAME) )
|
||||
{
|
||||
freespace_stop_mission();
|
||||
if ( going_to_menu_state(new_state) ) {
|
||||
freespace_stop_mission();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -7540,13 +7585,24 @@ int main(int argc, char *argv[])
|
||||
|
||||
SCP_mspdbcs_Initialise();
|
||||
|
||||
// If we're being evoked from a console, attach the STDIO streams to it and reopen the streams
|
||||
// This is needed because Windows assumes SUBSYSTEM:WINDOWS programs won't need console IO. Additionally, SDL
|
||||
// seems to close or otherwise grab the streams for somthing else.
|
||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
freopen("CONIN$", "r", stdin);
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
bool keep_stdout = false;
|
||||
char envbuf[2];
|
||||
// GetEnvironmentVariable returns the amount of stored characters on success, we're looking for the value "1"
|
||||
// so we only care about the case where it successfully read exactly one character (not including the null byte).
|
||||
if (GetEnvironmentVariable("FSO_KEEP_STDOUT", envbuf, 2) == 1) {
|
||||
keep_stdout = envbuf[0] == '1';
|
||||
}
|
||||
|
||||
// Only try redirecting stdout if FSO_KEEP_STDOUT is not set to "1".
|
||||
if (!keep_stdout) {
|
||||
// If we're being evoked from a console, attach the STDIO streams to it and reopen the streams
|
||||
// This is needed because Windows assumes SUBSYSTEM:WINDOWS programs won't need console IO. Additionally, SDL
|
||||
// seems to close or otherwise grab the streams for somthing else.
|
||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
freopen("CONIN$", "r", stdin);
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef APPLE_APP
|
||||
|
||||
@@ -50,3 +50,5 @@ include(vulkan.cmake)
|
||||
add_subdirectory(mdns)
|
||||
|
||||
add_subdirectory(variant)
|
||||
|
||||
ADD_SUBDIRECTORY(lz4)
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
IF(NOT FSO_BUILD_INCLUDED_LIBS)
|
||||
FIND_PACKAGE(LZ4 QUIET)
|
||||
ENDIF(NOT FSO_BUILD_INCLUDED_LIBS)
|
||||
|
||||
IF (FSO_BUILD_INCLUDED_LIBS OR NOT LZ4_FOUND)
|
||||
MESSAGE(STATUS "Building lz4 from source")
|
||||
|
||||
SET(LZ4_SOURCES
|
||||
lz4.c
|
||||
lz4frame.c
|
||||
lz4hc.c
|
||||
xxhash.c
|
||||
lz4.h
|
||||
lz4frame.h
|
||||
lz4hc.h
|
||||
xxhash.h)
|
||||
|
||||
ADD_LIBRARY(lz4 ${LZ4_SOURCES})
|
||||
|
||||
target_include_directories(lz4 SYSTEM PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
set_target_properties(lz4
|
||||
PROPERTIES
|
||||
FOLDER "3rdparty"
|
||||
DEFINE_SYMBOL LZ4_DLL # This will only be defined if we are building a shared library
|
||||
)
|
||||
|
||||
# Disable warnings if building from source
|
||||
suppress_warnings(lz4)
|
||||
|
||||
target_link_libraries(lz4 PUBLIC compiler)
|
||||
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(lz4 INTERFACE LZ4_DLL)
|
||||
ENDIF(BUILD_SHARED_LIBS)
|
||||
|
||||
IF(FSO_COPY_EXE AND BUILD_SHARED_LIBS)
|
||||
INSTALL(
|
||||
TARGETS lz4
|
||||
RUNTIME DESTINATION ${BINARY_DESTINATION}
|
||||
LIBRARY DESTINATION ${BINARY_DESTINATION}
|
||||
)
|
||||
ENDIF(FSO_COPY_EXE AND BUILD_SHARED_LIBS)
|
||||
|
||||
ELSE(FSO_BUILD_INCLUDED_LIBS OR NOT LZ4_FOUND)
|
||||
INCLUDE(util)
|
||||
|
||||
ADD_IMPORTED_LIB(lz4 ${LZ4_INCLUDE_DIR} ${LZ4_LIBRARIES})
|
||||
|
||||
ENDIF(FSO_BUILD_INCLUDED_LIBS OR NOT LZ4_FOUND)
|
||||
+2495
File diff suppressed because it is too large.
Load diff
+774
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* LZ4 - Fast LZ compression algorithm
|
||||
* Header File
|
||||
* Copyright (C) 2011-2020, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://www.lz4.org
|
||||
- LZ4 source repository : https://github.com/lz4/lz4
|
||||
*/
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef LZ4_H_2983827168210
|
||||
#define LZ4_H_2983827168210
|
||||
|
||||
/* --- Dependency --- */
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/**
|
||||
Introduction
|
||||
|
||||
LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core,
|
||||
scalable with multi-cores CPU. It features an extremely fast decoder, with speed in
|
||||
multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.
|
||||
|
||||
The LZ4 compression library provides in-memory compression and decompression functions.
|
||||
It gives full buffer control to user.
|
||||
Compression can be done in:
|
||||
- a single step (described as Simple Functions)
|
||||
- a single step, reusing a context (described in Advanced Functions)
|
||||
- unbounded multiple steps (described as Streaming compression)
|
||||
|
||||
lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md).
|
||||
Decompressing such a compressed block requires additional metadata.
|
||||
Exact metadata depends on exact decompression function.
|
||||
For the typical case of LZ4_decompress_safe(),
|
||||
metadata includes block's compressed size, and maximum bound of decompressed size.
|
||||
Each application is free to encode and pass such metadata in whichever way it wants.
|
||||
|
||||
lz4.h only handle blocks, it can not generate Frames.
|
||||
|
||||
Blocks are different from Frames (doc/lz4_Frame_format.md).
|
||||
Frames bundle both blocks and metadata in a specified manner.
|
||||
Embedding metadata is required for compressed data to be self-contained and portable.
|
||||
Frame format is delivered through a companion API, declared in lz4frame.h.
|
||||
The `lz4` CLI can only manage frames.
|
||||
*/
|
||||
|
||||
/*^***************************************************************
|
||||
* Export parameters
|
||||
*****************************************************************/
|
||||
/*
|
||||
* LZ4_DLL_EXPORT :
|
||||
* Enable exporting of functions when building a Windows DLL
|
||||
* LZ4LIB_VISIBILITY :
|
||||
* Control library symbols visibility.
|
||||
*/
|
||||
#ifndef LZ4LIB_VISIBILITY
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
# define LZ4LIB_VISIBILITY __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define LZ4LIB_VISIBILITY
|
||||
# endif
|
||||
#endif
|
||||
#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)
|
||||
# define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY
|
||||
#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)
|
||||
# define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
|
||||
#else
|
||||
# define LZ4LIB_API LZ4LIB_VISIBILITY
|
||||
#endif
|
||||
|
||||
/*------ Version ------*/
|
||||
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
|
||||
#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */
|
||||
#define LZ4_VERSION_RELEASE 3 /* for tweaks, bug-fixes, or development */
|
||||
|
||||
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
|
||||
|
||||
#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE
|
||||
#define LZ4_QUOTE(str) #str
|
||||
#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)
|
||||
#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)
|
||||
|
||||
LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version */
|
||||
LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; useful to check dll version */
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Tuning parameter
|
||||
**************************************/
|
||||
/*!
|
||||
* LZ4_MEMORY_USAGE :
|
||||
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
|
||||
* Increasing memory usage improves compression ratio.
|
||||
* Reduced memory usage may improve speed, thanks to better cache locality.
|
||||
* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
|
||||
*/
|
||||
#ifndef LZ4_MEMORY_USAGE
|
||||
# define LZ4_MEMORY_USAGE 14
|
||||
#endif
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Simple Functions
|
||||
**************************************/
|
||||
/*! LZ4_compress_default() :
|
||||
* Compresses 'srcSize' bytes from buffer 'src'
|
||||
* into already allocated 'dst' buffer of size 'dstCapacity'.
|
||||
* Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).
|
||||
* It also runs faster, so it's a recommended setting.
|
||||
* If the function cannot compress 'src' into a more limited 'dst' budget,
|
||||
* compression stops *immediately*, and the function result is zero.
|
||||
* In which case, 'dst' content is undefined (invalid).
|
||||
* srcSize : max supported value is LZ4_MAX_INPUT_SIZE.
|
||||
* dstCapacity : size of buffer 'dst' (which must be already allocated)
|
||||
* @return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity)
|
||||
* or 0 if compression fails
|
||||
* Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer).
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);
|
||||
|
||||
/*! LZ4_decompress_safe() :
|
||||
* compressedSize : is the exact complete size of the compressed block.
|
||||
* dstCapacity : is the size of destination buffer (which must be already allocated), presumed an upper bound of decompressed size.
|
||||
* @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)
|
||||
* If destination buffer is not large enough, decoding will stop and output an error code (negative value).
|
||||
* If the source stream is detected malformed, the function will stop decoding and return a negative result.
|
||||
* Note 1 : This function is protected against malicious data packets :
|
||||
* it will never writes outside 'dst' buffer, nor read outside 'source' buffer,
|
||||
* even if the compressed block is maliciously modified to order the decoder to do these actions.
|
||||
* In such case, the decoder stops immediately, and considers the compressed block malformed.
|
||||
* Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them.
|
||||
* The implementation is free to send / store / derive this information in whichever way is most beneficial.
|
||||
* If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity);
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Advanced Functions
|
||||
**************************************/
|
||||
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
|
||||
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
|
||||
|
||||
/*! LZ4_compressBound() :
|
||||
Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
|
||||
This function is primarily useful for memory allocation purposes (destination buffer size).
|
||||
Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
|
||||
Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize)
|
||||
inputSize : max supported value is LZ4_MAX_INPUT_SIZE
|
||||
return : maximum output size in a "worst case" scenario
|
||||
or 0, if input size is incorrect (too large or negative)
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compressBound(int inputSize);
|
||||
|
||||
/*! LZ4_compress_fast() :
|
||||
Same as LZ4_compress_default(), but allows selection of "acceleration" factor.
|
||||
The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
|
||||
It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
|
||||
An acceleration value of "1" is the same as regular LZ4_compress_default()
|
||||
Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).
|
||||
Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c).
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
|
||||
/*! LZ4_compress_fast_extState() :
|
||||
* Same as LZ4_compress_fast(), using an externally allocated memory space for its state.
|
||||
* Use LZ4_sizeofState() to know how much memory must be allocated,
|
||||
* and allocate it on 8-bytes boundaries (using `malloc()` typically).
|
||||
* Then, provide this buffer as `void* state` to compression function.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_sizeofState(void);
|
||||
LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
|
||||
/*! LZ4_compress_destSize() :
|
||||
* Reverse the logic : compresses as much data as possible from 'src' buffer
|
||||
* into already allocated buffer 'dst', of size >= 'targetDestSize'.
|
||||
* This function either compresses the entire 'src' content into 'dst' if it's large enough,
|
||||
* or fill 'dst' buffer completely with as much data as possible from 'src'.
|
||||
* note: acceleration parameter is fixed to "default".
|
||||
*
|
||||
* *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.
|
||||
* New value is necessarily <= input value.
|
||||
* @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)
|
||||
* or 0 if compression fails.
|
||||
*
|
||||
* Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+):
|
||||
* the produced compressed content could, in specific circumstances,
|
||||
* require to be decompressed into a destination buffer larger
|
||||
* by at least 1 byte than the content to decompress.
|
||||
* If an application uses `LZ4_compress_destSize()`,
|
||||
* it's highly recommended to update liblz4 to v1.9.2 or better.
|
||||
* If this can't be done or ensured,
|
||||
* the receiving decompression function should provide
|
||||
* a dstCapacity which is > decompressedSize, by at least 1 byte.
|
||||
* See https://github.com/lz4/lz4/issues/859 for details
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);
|
||||
|
||||
|
||||
/*! LZ4_decompress_safe_partial() :
|
||||
* Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',
|
||||
* into destination buffer 'dst' of size 'dstCapacity'.
|
||||
* Up to 'targetOutputSize' bytes will be decoded.
|
||||
* The function stops decoding on reaching this objective.
|
||||
* This can be useful to boost performance
|
||||
* whenever only the beginning of a block is required.
|
||||
*
|
||||
* @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)
|
||||
* If source stream is detected malformed, function returns a negative result.
|
||||
*
|
||||
* Note 1 : @return can be < targetOutputSize, if compressed block contains less data.
|
||||
*
|
||||
* Note 2 : targetOutputSize must be <= dstCapacity
|
||||
*
|
||||
* Note 3 : this function effectively stops decoding on reaching targetOutputSize,
|
||||
* so dstCapacity is kind of redundant.
|
||||
* This is because in older versions of this function,
|
||||
* decoding operation would still write complete sequences.
|
||||
* Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,
|
||||
* it could write more bytes, though only up to dstCapacity.
|
||||
* Some "margin" used to be required for this operation to work properly.
|
||||
* Thankfully, this is no longer necessary.
|
||||
* The function nonetheless keeps the same signature, in an effort to preserve API compatibility.
|
||||
*
|
||||
* Note 4 : If srcSize is the exact size of the block,
|
||||
* then targetOutputSize can be any value,
|
||||
* including larger than the block's decompressed size.
|
||||
* The function will, at most, generate block's decompressed size.
|
||||
*
|
||||
* Note 5 : If srcSize is _larger_ than block's compressed size,
|
||||
* then targetOutputSize **MUST** be <= block's decompressed size.
|
||||
* Otherwise, *silent corruption will occur*.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);
|
||||
|
||||
|
||||
/*-*********************************************
|
||||
* Streaming Compression Functions
|
||||
***********************************************/
|
||||
typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
|
||||
|
||||
LZ4LIB_API LZ4_stream_t* LZ4_createStream(void);
|
||||
LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr);
|
||||
|
||||
/*! LZ4_resetStream_fast() : v1.9.0+
|
||||
* Use this to prepare an LZ4_stream_t for a new chain of dependent blocks
|
||||
* (e.g., LZ4_compress_fast_continue()).
|
||||
*
|
||||
* An LZ4_stream_t must be initialized once before usage.
|
||||
* This is automatically done when created by LZ4_createStream().
|
||||
* However, should the LZ4_stream_t be simply declared on stack (for example),
|
||||
* it's necessary to initialize it first, using LZ4_initStream().
|
||||
*
|
||||
* After init, start any new stream with LZ4_resetStream_fast().
|
||||
* A same LZ4_stream_t can be re-used multiple times consecutively
|
||||
* and compress multiple streams,
|
||||
* provided that it starts each new stream with LZ4_resetStream_fast().
|
||||
*
|
||||
* LZ4_resetStream_fast() is much faster than LZ4_initStream(),
|
||||
* but is not compatible with memory regions containing garbage data.
|
||||
*
|
||||
* Note: it's only useful to call LZ4_resetStream_fast()
|
||||
* in the context of streaming compression.
|
||||
* The *extState* functions perform their own resets.
|
||||
* Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive.
|
||||
*/
|
||||
LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr);
|
||||
|
||||
/*! LZ4_loadDict() :
|
||||
* Use this function to reference a static dictionary into LZ4_stream_t.
|
||||
* The dictionary must remain available during compression.
|
||||
* LZ4_loadDict() triggers a reset, so any previous data will be forgotten.
|
||||
* The same dictionary will have to be loaded on decompression side for successful decoding.
|
||||
* Dictionary are useful for better compression of small data (KB range).
|
||||
* While LZ4 accept any input as dictionary,
|
||||
* results are generally better when using Zstandard's Dictionary Builder.
|
||||
* Loading a size of 0 is allowed, and is the same as reset.
|
||||
* @return : loaded dictionary size, in bytes (necessarily <= 64 KB)
|
||||
*/
|
||||
LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
|
||||
|
||||
/*! LZ4_compress_fast_continue() :
|
||||
* Compress 'src' content using data from previously compressed blocks, for better compression ratio.
|
||||
* 'dst' buffer must be already allocated.
|
||||
* If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
|
||||
*
|
||||
* @return : size of compressed block
|
||||
* or 0 if there is an error (typically, cannot fit into 'dst').
|
||||
*
|
||||
* Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block.
|
||||
* Each block has precise boundaries.
|
||||
* Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata.
|
||||
* It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together.
|
||||
*
|
||||
* Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory !
|
||||
*
|
||||
* Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB.
|
||||
* Make sure that buffers are separated, by at least one byte.
|
||||
* This construction ensures that each block only depends on previous block.
|
||||
*
|
||||
* Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB.
|
||||
*
|
||||
* Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
/*! LZ4_saveDict() :
|
||||
* If last 64KB data cannot be guaranteed to remain available at its current memory location,
|
||||
* save it into a safer place (char* safeBuffer).
|
||||
* This is schematically equivalent to a memcpy() followed by LZ4_loadDict(),
|
||||
* but is much faster, because LZ4_saveDict() doesn't need to rebuild tables.
|
||||
* @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize);
|
||||
|
||||
|
||||
/*-**********************************************
|
||||
* Streaming Decompression Functions
|
||||
* Bufferless synchronous API
|
||||
************************************************/
|
||||
typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */
|
||||
|
||||
/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :
|
||||
* creation / destruction of streaming decompression tracking context.
|
||||
* A tracking context can be re-used multiple times.
|
||||
*/
|
||||
LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void);
|
||||
LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
|
||||
|
||||
/*! LZ4_setStreamDecode() :
|
||||
* An LZ4_streamDecode_t context can be allocated once and re-used multiple times.
|
||||
* Use this function to start decompression of a new stream of blocks.
|
||||
* A dictionary can optionally be set. Use NULL or size 0 for a reset order.
|
||||
* Dictionary is presumed stable : it must remain accessible and unmodified during next decompression.
|
||||
* @return : 1 if OK, 0 if error
|
||||
*/
|
||||
LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
|
||||
|
||||
/*! LZ4_decoderRingBufferSize() : v1.8.2+
|
||||
* Note : in a ring buffer scenario (optional),
|
||||
* blocks are presumed decompressed next to each other
|
||||
* up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize),
|
||||
* at which stage it resumes from beginning of ring buffer.
|
||||
* When setting such a ring buffer for streaming decompression,
|
||||
* provides the minimum size of this ring buffer
|
||||
* to be compatible with any source respecting maxBlockSize condition.
|
||||
* @return : minimum ring buffer size,
|
||||
* or 0 if there is an error (invalid maxBlockSize).
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize);
|
||||
#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */
|
||||
|
||||
/*! LZ4_decompress_*_continue() :
|
||||
* These decoding functions allow decompression of consecutive blocks in "streaming" mode.
|
||||
* A block is an unsplittable entity, it must be presented entirely to a decompression function.
|
||||
* Decompression functions only accepts one block at a time.
|
||||
* The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded.
|
||||
* If less than 64KB of data has been decoded, all the data must be present.
|
||||
*
|
||||
* Special : if decompression side sets a ring buffer, it must respect one of the following conditions :
|
||||
* - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize).
|
||||
* maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes.
|
||||
* In which case, encoding and decoding buffers do not need to be synchronized.
|
||||
* Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize.
|
||||
* - Synchronized mode :
|
||||
* Decompression buffer size is _exactly_ the same as compression buffer size,
|
||||
* and follows exactly same update rule (block boundaries at same positions),
|
||||
* and decoding function is provided with exact decompressed size of each block (exception for last block of the stream),
|
||||
* _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB).
|
||||
* - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes.
|
||||
* In which case, encoding and decoding buffers do not need to be synchronized,
|
||||
* and encoding ring buffer can have any size, including small ones ( < 64 KB).
|
||||
*
|
||||
* Whenever these conditions are not possible,
|
||||
* save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression,
|
||||
* then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity);
|
||||
|
||||
|
||||
/*! LZ4_decompress_*_usingDict() :
|
||||
* These decoding functions work the same as
|
||||
* a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()
|
||||
* They are stand-alone, and don't need an LZ4_streamDecode_t structure.
|
||||
* Dictionary is presumed stable : it must remain accessible and unmodified during decompression.
|
||||
* Performance tip : Decompression speed can be substantially increased
|
||||
* when dst == dictStart + dictSize.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize);
|
||||
|
||||
#endif /* LZ4_H_2983827168210 */
|
||||
|
||||
|
||||
/*^*************************************
|
||||
* !!!!!! STATIC LINKING ONLY !!!!!!
|
||||
***************************************/
|
||||
|
||||
/*-****************************************************************************
|
||||
* Experimental section
|
||||
*
|
||||
* Symbols declared in this section must be considered unstable. Their
|
||||
* signatures or semantics may change, or they may be removed altogether in the
|
||||
* future. They are therefore only safe to depend on when the caller is
|
||||
* statically linked against the library.
|
||||
*
|
||||
* To protect against unsafe usage, not only are the declarations guarded,
|
||||
* the definitions are hidden by default
|
||||
* when building LZ4 as a shared/dynamic library.
|
||||
*
|
||||
* In order to access these declarations,
|
||||
* define LZ4_STATIC_LINKING_ONLY in your application
|
||||
* before including LZ4's headers.
|
||||
*
|
||||
* In order to make their implementations accessible dynamically, you must
|
||||
* define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library.
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LZ4_STATIC_LINKING_ONLY
|
||||
|
||||
#ifndef LZ4_STATIC_3504398509
|
||||
#define LZ4_STATIC_3504398509
|
||||
|
||||
#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS
|
||||
#define LZ4LIB_STATIC_API LZ4LIB_API
|
||||
#else
|
||||
#define LZ4LIB_STATIC_API
|
||||
#endif
|
||||
|
||||
|
||||
/*! LZ4_compress_fast_extState_fastReset() :
|
||||
* A variant of LZ4_compress_fast_extState().
|
||||
*
|
||||
* Using this variant avoids an expensive initialization step.
|
||||
* It is only safe to call if the state buffer is known to be correctly initialized already
|
||||
* (see above comment on LZ4_resetStream_fast() for a definition of "correctly initialized").
|
||||
* From a high level, the difference is that
|
||||
* this function initializes the provided state with a call to something like LZ4_resetStream_fast()
|
||||
* while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream().
|
||||
*/
|
||||
LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
|
||||
|
||||
/*! LZ4_attach_dictionary() :
|
||||
* This is an experimental API that allows
|
||||
* efficient use of a static dictionary many times.
|
||||
*
|
||||
* Rather than re-loading the dictionary buffer into a working context before
|
||||
* each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a
|
||||
* working LZ4_stream_t, this function introduces a no-copy setup mechanism,
|
||||
* in which the working stream references the dictionary stream in-place.
|
||||
*
|
||||
* Several assumptions are made about the state of the dictionary stream.
|
||||
* Currently, only streams which have been prepared by LZ4_loadDict() should
|
||||
* be expected to work.
|
||||
*
|
||||
* Alternatively, the provided dictionaryStream may be NULL,
|
||||
* in which case any existing dictionary stream is unset.
|
||||
*
|
||||
* If a dictionary is provided, it replaces any pre-existing stream history.
|
||||
* The dictionary contents are the only history that can be referenced and
|
||||
* logically immediately precede the data compressed in the first subsequent
|
||||
* compression call.
|
||||
*
|
||||
* The dictionary will only remain attached to the working stream through the
|
||||
* first compression call, at the end of which it is cleared. The dictionary
|
||||
* stream (and source buffer) must remain in-place / accessible / unchanged
|
||||
* through the completion of the first compression call on the stream.
|
||||
*/
|
||||
LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream);
|
||||
|
||||
|
||||
/*! In-place compression and decompression
|
||||
*
|
||||
* It's possible to have input and output sharing the same buffer,
|
||||
* for highly constrained memory environments.
|
||||
* In both cases, it requires input to lay at the end of the buffer,
|
||||
* and decompression to start at beginning of the buffer.
|
||||
* Buffer size must feature some margin, hence be larger than final size.
|
||||
*
|
||||
* |<------------------------buffer--------------------------------->|
|
||||
* |<-----------compressed data--------->|
|
||||
* |<-----------decompressed size------------------>|
|
||||
* |<----margin---->|
|
||||
*
|
||||
* This technique is more useful for decompression,
|
||||
* since decompressed size is typically larger,
|
||||
* and margin is short.
|
||||
*
|
||||
* In-place decompression will work inside any buffer
|
||||
* which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize).
|
||||
* This presumes that decompressedSize > compressedSize.
|
||||
* Otherwise, it means compression actually expanded data,
|
||||
* and it would be more efficient to store such data with a flag indicating it's not compressed.
|
||||
* This can happen when data is not compressible (already compressed, or encrypted).
|
||||
*
|
||||
* For in-place compression, margin is larger, as it must be able to cope with both
|
||||
* history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX,
|
||||
* and data expansion, which can happen when input is not compressible.
|
||||
* As a consequence, buffer size requirements are much higher,
|
||||
* and memory savings offered by in-place compression are more limited.
|
||||
*
|
||||
* There are ways to limit this cost for compression :
|
||||
* - Reduce history size, by modifying LZ4_DISTANCE_MAX.
|
||||
* Note that it is a compile-time constant, so all compressions will apply this limit.
|
||||
* Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX,
|
||||
* so it's a reasonable trick when inputs are known to be small.
|
||||
* - Require the compressor to deliver a "maximum compressed size".
|
||||
* This is the `dstCapacity` parameter in `LZ4_compress*()`.
|
||||
* When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail,
|
||||
* in which case, the return code will be 0 (zero).
|
||||
* The caller must be ready for these cases to happen,
|
||||
* and typically design a backup scheme to send data uncompressed.
|
||||
* The combination of both techniques can significantly reduce
|
||||
* the amount of margin required for in-place compression.
|
||||
*
|
||||
* In-place compression can work in any buffer
|
||||
* which size is >= (maxCompressedSize)
|
||||
* with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success.
|
||||
* LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX,
|
||||
* so it's possible to reduce memory requirements by playing with them.
|
||||
*/
|
||||
|
||||
#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) (((compressedSize) >> 8) + 32)
|
||||
#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize)) /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */
|
||||
|
||||
#ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at compile time */
|
||||
# define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
|
||||
#endif
|
||||
|
||||
#define LZ4_COMPRESS_INPLACE_MARGIN (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */
|
||||
#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */
|
||||
|
||||
#endif /* LZ4_STATIC_3504398509 */
|
||||
#endif /* LZ4_STATIC_LINKING_ONLY */
|
||||
|
||||
|
||||
|
||||
#ifndef LZ4_H_98237428734687
|
||||
#define LZ4_H_98237428734687
|
||||
|
||||
/*-************************************************************
|
||||
* Private Definitions
|
||||
**************************************************************
|
||||
* Do not use these definitions directly.
|
||||
* They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.
|
||||
* Accessing members will expose user code to API and/or ABI break in future versions of the library.
|
||||
**************************************************************/
|
||||
#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
|
||||
#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
|
||||
#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
|
||||
|
||||
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# include <stdint.h>
|
||||
typedef int8_t LZ4_i8;
|
||||
typedef uint8_t LZ4_byte;
|
||||
typedef uint16_t LZ4_u16;
|
||||
typedef uint32_t LZ4_u32;
|
||||
#else
|
||||
typedef signed char LZ4_i8;
|
||||
typedef unsigned char LZ4_byte;
|
||||
typedef unsigned short LZ4_u16;
|
||||
typedef unsigned int LZ4_u32;
|
||||
#endif
|
||||
|
||||
typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
|
||||
struct LZ4_stream_t_internal {
|
||||
LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];
|
||||
LZ4_u32 currentOffset;
|
||||
LZ4_u32 tableType;
|
||||
const LZ4_byte* dictionary;
|
||||
const LZ4_stream_t_internal* dictCtx;
|
||||
LZ4_u32 dictSize;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const LZ4_byte* externalDict;
|
||||
size_t extDictSize;
|
||||
const LZ4_byte* prefixEnd;
|
||||
size_t prefixSize;
|
||||
} LZ4_streamDecode_t_internal;
|
||||
|
||||
|
||||
/*! LZ4_stream_t :
|
||||
* Do not use below internal definitions directly !
|
||||
* Declare or allocate an LZ4_stream_t instead.
|
||||
* LZ4_stream_t can also be created using LZ4_createStream(), which is recommended.
|
||||
* The structure definition can be convenient for static allocation
|
||||
* (on stack, or as part of larger structure).
|
||||
* Init this structure with LZ4_initStream() before first use.
|
||||
* note : only use this definition in association with static linking !
|
||||
* this definition is not API/ABI safe, and may change in future versions.
|
||||
*/
|
||||
#define LZ4_STREAMSIZE 16416 /* static size, for inter-version compatibility */
|
||||
#define LZ4_STREAMSIZE_VOIDP (LZ4_STREAMSIZE / sizeof(void*))
|
||||
union LZ4_stream_u {
|
||||
void* table[LZ4_STREAMSIZE_VOIDP];
|
||||
LZ4_stream_t_internal internal_donotuse;
|
||||
}; /* previously typedef'd to LZ4_stream_t */
|
||||
|
||||
|
||||
/*! LZ4_initStream() : v1.9.0+
|
||||
* An LZ4_stream_t structure must be initialized at least once.
|
||||
* This is automatically done when invoking LZ4_createStream(),
|
||||
* but it's not when the structure is simply declared on stack (for example).
|
||||
*
|
||||
* Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t.
|
||||
* It can also initialize any arbitrary buffer of sufficient size,
|
||||
* and will @return a pointer of proper type upon initialization.
|
||||
*
|
||||
* Note : initialization fails if size and alignment conditions are not respected.
|
||||
* In which case, the function will @return NULL.
|
||||
* Note2: An LZ4_stream_t structure guarantees correct alignment and size.
|
||||
* Note3: Before v1.9.0, use LZ4_resetStream() instead
|
||||
*/
|
||||
LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size);
|
||||
|
||||
|
||||
/*! LZ4_streamDecode_t :
|
||||
* information structure to track an LZ4 stream during decompression.
|
||||
* init this structure using LZ4_setStreamDecode() before first use.
|
||||
* note : only use in association with static linking !
|
||||
* this definition is not API/ABI safe,
|
||||
* and may change in a future version !
|
||||
*/
|
||||
#define LZ4_STREAMDECODESIZE_U64 (4 + ((sizeof(void*)==16) ? 2 : 0) /*AS-400*/ )
|
||||
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
|
||||
union LZ4_streamDecode_u {
|
||||
unsigned long long table[LZ4_STREAMDECODESIZE_U64];
|
||||
LZ4_streamDecode_t_internal internal_donotuse;
|
||||
} ; /* previously typedef'd to LZ4_streamDecode_t */
|
||||
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Obsolete Functions
|
||||
**************************************/
|
||||
|
||||
/*! Deprecation warnings
|
||||
*
|
||||
* Deprecated functions make the compiler generate a warning when invoked.
|
||||
* This is meant to invite users to update their source code.
|
||||
* Should deprecation warnings be a problem, it is generally possible to disable them,
|
||||
* typically with -Wno-deprecated-declarations for gcc
|
||||
* or _CRT_SECURE_NO_WARNINGS in Visual.
|
||||
*
|
||||
* Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS
|
||||
* before including the header file.
|
||||
*/
|
||||
#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS
|
||||
# define LZ4_DEPRECATED(message) /* disable deprecation warnings */
|
||||
#else
|
||||
# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
|
||||
# define LZ4_DEPRECATED(message) [[deprecated(message)]]
|
||||
# elif defined(_MSC_VER)
|
||||
# define LZ4_DEPRECATED(message) __declspec(deprecated(message))
|
||||
# elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))
|
||||
# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
# elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)
|
||||
# define LZ4_DEPRECATED(message) __attribute__((deprecated))
|
||||
# else
|
||||
# pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler")
|
||||
# define LZ4_DEPRECATED(message) /* disabled */
|
||||
# endif
|
||||
#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */
|
||||
|
||||
/*! Obsolete compression functions (since v1.7.3) */
|
||||
LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* src, char* dest, int srcSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
/*! Obsolete decompression functions (since v1.8.0) */
|
||||
LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize);
|
||||
LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize);
|
||||
|
||||
/* Obsolete streaming functions (since v1.7.0)
|
||||
* degraded functionality; do not use!
|
||||
*
|
||||
* In order to perform streaming compression, these functions depended on data
|
||||
* that is no longer tracked in the state. They have been preserved as well as
|
||||
* possible: using them will still produce a correct output. However, they don't
|
||||
* actually retain any history between compression calls. The compression ratio
|
||||
* achieved will therefore be no better than compressing each chunk
|
||||
* independently.
|
||||
*/
|
||||
LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer);
|
||||
LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void);
|
||||
LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer);
|
||||
LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state);
|
||||
|
||||
/*! Obsolete streaming decoding functions (since v1.7.0) */
|
||||
LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
|
||||
LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
|
||||
|
||||
/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) :
|
||||
* These functions used to be faster than LZ4_decompress_safe(),
|
||||
* but this is no longer the case. They are now slower.
|
||||
* This is because LZ4_decompress_fast() doesn't know the input size,
|
||||
* and therefore must progress more cautiously into the input buffer to not read beyond the end of block.
|
||||
* On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability.
|
||||
* As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.
|
||||
*
|
||||
* The last remaining LZ4_decompress_fast() specificity is that
|
||||
* it can decompress a block without knowing its compressed size.
|
||||
* Such functionality can be achieved in a more secure manner
|
||||
* by employing LZ4_decompress_safe_partial().
|
||||
*
|
||||
* Parameters:
|
||||
* originalSize : is the uncompressed size to regenerate.
|
||||
* `dst` must be already allocated, its size must be >= 'originalSize' bytes.
|
||||
* @return : number of bytes read from source buffer (== compressed size).
|
||||
* The function expects to finish at block's end exactly.
|
||||
* If the source stream is detected malformed, the function stops decoding and returns a negative result.
|
||||
* note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer.
|
||||
* However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds.
|
||||
* Also, since match offsets are not validated, match reads from 'src' may underflow too.
|
||||
* These issues never happen if input (compressed) data is correct.
|
||||
* But they may happen if input data is invalid (error or intentional tampering).
|
||||
* As a consequence, use these functions in trusted environments with trusted data **only**.
|
||||
*/
|
||||
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead")
|
||||
LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);
|
||||
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead")
|
||||
LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);
|
||||
LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead")
|
||||
LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);
|
||||
|
||||
/*! LZ4_resetStream() :
|
||||
* An LZ4_stream_t structure must be initialized at least once.
|
||||
* This is done with LZ4_initStream(), or LZ4_resetStream().
|
||||
* Consider switching to LZ4_initStream(),
|
||||
* invoking LZ4_resetStream() will trigger deprecation warnings in the future.
|
||||
*/
|
||||
LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr);
|
||||
|
||||
|
||||
#endif /* LZ4_H_98237428734687 */
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
+1899
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
LZ4 auto-framing library
|
||||
Header File
|
||||
Copyright (C) 2011-2020, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : https://github.com/lz4/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
/* LZ4F is a stand-alone API able to create and decode LZ4 frames
|
||||
* conformant with specification v1.6.1 in doc/lz4_Frame_format.md .
|
||||
* Generated frames are compatible with `lz4` CLI.
|
||||
*
|
||||
* LZ4F also offers streaming capabilities.
|
||||
*
|
||||
* lz4.h is not required when using lz4frame.h,
|
||||
* except to extract common constant such as LZ4_VERSION_NUMBER.
|
||||
* */
|
||||
|
||||
#ifndef LZ4F_H_09782039843
|
||||
#define LZ4F_H_09782039843
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* --- Dependency --- */
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/**
|
||||
Introduction
|
||||
|
||||
lz4frame.h implements LZ4 frame specification (doc/lz4_Frame_format.md).
|
||||
lz4frame.h provides frame compression functions that take care
|
||||
of encoding standard metadata alongside LZ4-compressed blocks.
|
||||
*/
|
||||
|
||||
/*-***************************************************************
|
||||
* Compiler specifics
|
||||
*****************************************************************/
|
||||
/* LZ4_DLL_EXPORT :
|
||||
* Enable exporting of functions when building a Windows DLL
|
||||
* LZ4FLIB_VISIBILITY :
|
||||
* Control library symbols visibility.
|
||||
*/
|
||||
#ifndef LZ4FLIB_VISIBILITY
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
# define LZ4FLIB_VISIBILITY __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define LZ4FLIB_VISIBILITY
|
||||
# endif
|
||||
#endif
|
||||
#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)
|
||||
# define LZ4FLIB_API __declspec(dllexport) LZ4FLIB_VISIBILITY
|
||||
#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)
|
||||
# define LZ4FLIB_API __declspec(dllimport) LZ4FLIB_VISIBILITY
|
||||
#else
|
||||
# define LZ4FLIB_API LZ4FLIB_VISIBILITY
|
||||
#endif
|
||||
|
||||
#ifdef LZ4F_DISABLE_DEPRECATE_WARNINGS
|
||||
# define LZ4F_DEPRECATE(x) x
|
||||
#else
|
||||
# if defined(_MSC_VER)
|
||||
# define LZ4F_DEPRECATE(x) x /* __declspec(deprecated) x - only works with C++ */
|
||||
# elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
|
||||
# define LZ4F_DEPRECATE(x) x __attribute__((deprecated))
|
||||
# else
|
||||
# define LZ4F_DEPRECATE(x) x /* no deprecation warning for this compiler */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Error management
|
||||
**************************************/
|
||||
typedef size_t LZ4F_errorCode_t;
|
||||
|
||||
LZ4FLIB_API unsigned LZ4F_isError(LZ4F_errorCode_t code); /**< tells when a function result is an error code */
|
||||
LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /**< return error code string; for debugging */
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Frame compression types
|
||||
************************************* */
|
||||
/* #define LZ4F_ENABLE_OBSOLETE_ENUMS // uncomment to enable obsolete enums */
|
||||
#ifdef LZ4F_ENABLE_OBSOLETE_ENUMS
|
||||
# define LZ4F_OBSOLETE_ENUM(x) , LZ4F_DEPRECATE(x) = LZ4F_##x
|
||||
#else
|
||||
# define LZ4F_OBSOLETE_ENUM(x)
|
||||
#endif
|
||||
|
||||
/* The larger the block size, the (slightly) better the compression ratio,
|
||||
* though there are diminishing returns.
|
||||
* Larger blocks also increase memory usage on both compression and decompression sides.
|
||||
*/
|
||||
typedef enum {
|
||||
LZ4F_default=0,
|
||||
LZ4F_max64KB=4,
|
||||
LZ4F_max256KB=5,
|
||||
LZ4F_max1MB=6,
|
||||
LZ4F_max4MB=7
|
||||
LZ4F_OBSOLETE_ENUM(max64KB)
|
||||
LZ4F_OBSOLETE_ENUM(max256KB)
|
||||
LZ4F_OBSOLETE_ENUM(max1MB)
|
||||
LZ4F_OBSOLETE_ENUM(max4MB)
|
||||
} LZ4F_blockSizeID_t;
|
||||
|
||||
/* Linked blocks sharply reduce inefficiencies when using small blocks,
|
||||
* they compress better.
|
||||
* However, some LZ4 decoders are only compatible with independent blocks */
|
||||
typedef enum {
|
||||
LZ4F_blockLinked=0,
|
||||
LZ4F_blockIndependent
|
||||
LZ4F_OBSOLETE_ENUM(blockLinked)
|
||||
LZ4F_OBSOLETE_ENUM(blockIndependent)
|
||||
} LZ4F_blockMode_t;
|
||||
|
||||
typedef enum {
|
||||
LZ4F_noContentChecksum=0,
|
||||
LZ4F_contentChecksumEnabled
|
||||
LZ4F_OBSOLETE_ENUM(noContentChecksum)
|
||||
LZ4F_OBSOLETE_ENUM(contentChecksumEnabled)
|
||||
} LZ4F_contentChecksum_t;
|
||||
|
||||
typedef enum {
|
||||
LZ4F_noBlockChecksum=0,
|
||||
LZ4F_blockChecksumEnabled
|
||||
} LZ4F_blockChecksum_t;
|
||||
|
||||
typedef enum {
|
||||
LZ4F_frame=0,
|
||||
LZ4F_skippableFrame
|
||||
LZ4F_OBSOLETE_ENUM(skippableFrame)
|
||||
} LZ4F_frameType_t;
|
||||
|
||||
#ifdef LZ4F_ENABLE_OBSOLETE_ENUMS
|
||||
typedef LZ4F_blockSizeID_t blockSizeID_t;
|
||||
typedef LZ4F_blockMode_t blockMode_t;
|
||||
typedef LZ4F_frameType_t frameType_t;
|
||||
typedef LZ4F_contentChecksum_t contentChecksum_t;
|
||||
#endif
|
||||
|
||||
/*! LZ4F_frameInfo_t :
|
||||
* makes it possible to set or read frame parameters.
|
||||
* Structure must be first init to 0, using memset() or LZ4F_INIT_FRAMEINFO,
|
||||
* setting all parameters to default.
|
||||
* It's then possible to update selectively some parameters */
|
||||
typedef struct {
|
||||
LZ4F_blockSizeID_t blockSizeID; /* max64KB, max256KB, max1MB, max4MB; 0 == default */
|
||||
LZ4F_blockMode_t blockMode; /* LZ4F_blockLinked, LZ4F_blockIndependent; 0 == default */
|
||||
LZ4F_contentChecksum_t contentChecksumFlag; /* 1: frame terminated with 32-bit checksum of decompressed data; 0: disabled (default) */
|
||||
LZ4F_frameType_t frameType; /* read-only field : LZ4F_frame or LZ4F_skippableFrame */
|
||||
unsigned long long contentSize; /* Size of uncompressed content ; 0 == unknown */
|
||||
unsigned dictID; /* Dictionary ID, sent by compressor to help decoder select correct dictionary; 0 == no dictID provided */
|
||||
LZ4F_blockChecksum_t blockChecksumFlag; /* 1: each block followed by a checksum of block's compressed data; 0: disabled (default) */
|
||||
} LZ4F_frameInfo_t;
|
||||
|
||||
#define LZ4F_INIT_FRAMEINFO { LZ4F_default, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0ULL, 0U, LZ4F_noBlockChecksum } /* v1.8.3+ */
|
||||
|
||||
/*! LZ4F_preferences_t :
|
||||
* makes it possible to supply advanced compression instructions to streaming interface.
|
||||
* Structure must be first init to 0, using memset() or LZ4F_INIT_PREFERENCES,
|
||||
* setting all parameters to default.
|
||||
* All reserved fields must be set to zero. */
|
||||
typedef struct {
|
||||
LZ4F_frameInfo_t frameInfo;
|
||||
int compressionLevel; /* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger "fast acceleration" */
|
||||
unsigned autoFlush; /* 1: always flush; reduces usage of internal buffers */
|
||||
unsigned favorDecSpeed; /* 1: parser favors decompression speed vs compression ratio. Only works for high compression modes (>= LZ4HC_CLEVEL_OPT_MIN) */ /* v1.8.2+ */
|
||||
unsigned reserved[3]; /* must be zero for forward compatibility */
|
||||
} LZ4F_preferences_t;
|
||||
|
||||
#define LZ4F_INIT_PREFERENCES { LZ4F_INIT_FRAMEINFO, 0, 0u, 0u, { 0u, 0u, 0u } } /* v1.8.3+ */
|
||||
|
||||
|
||||
/*-*********************************
|
||||
* Simple compression function
|
||||
***********************************/
|
||||
|
||||
LZ4FLIB_API int LZ4F_compressionLevel_max(void); /* v1.8.0+ */
|
||||
|
||||
/*! LZ4F_compressFrameBound() :
|
||||
* Returns the maximum possible compressed size with LZ4F_compressFrame() given srcSize and preferences.
|
||||
* `preferencesPtr` is optional. It can be replaced by NULL, in which case, the function will assume default preferences.
|
||||
* Note : this result is only usable with LZ4F_compressFrame().
|
||||
* It may also be used with LZ4F_compressUpdate() _if no flush() operation_ is performed.
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
|
||||
/*! LZ4F_compressFrame() :
|
||||
* Compress an entire srcBuffer into a valid LZ4 frame.
|
||||
* dstCapacity MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).
|
||||
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.
|
||||
* @return : number of bytes written into dstBuffer.
|
||||
* or an error code if it fails (can be tested using LZ4F_isError())
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
const LZ4F_preferences_t* preferencesPtr);
|
||||
|
||||
|
||||
/*-***********************************
|
||||
* Advanced compression functions
|
||||
*************************************/
|
||||
typedef struct LZ4F_cctx_s LZ4F_cctx; /* incomplete type */
|
||||
typedef LZ4F_cctx* LZ4F_compressionContext_t; /* for compatibility with previous API version */
|
||||
|
||||
typedef struct {
|
||||
unsigned stableSrc; /* 1 == src content will remain present on future calls to LZ4F_compress(); skip copying src content within tmp buffer */
|
||||
unsigned reserved[3];
|
||||
} LZ4F_compressOptions_t;
|
||||
|
||||
/*--- Resource Management ---*/
|
||||
|
||||
#define LZ4F_VERSION 100 /* This number can be used to check for an incompatible API breaking change */
|
||||
LZ4FLIB_API unsigned LZ4F_getVersion(void);
|
||||
|
||||
/*! LZ4F_createCompressionContext() :
|
||||
* The first thing to do is to create a compressionContext object, which will be used in all compression operations.
|
||||
* This is achieved using LZ4F_createCompressionContext(), which takes as argument a version.
|
||||
* The version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL.
|
||||
* The function will provide a pointer to a fully allocated LZ4F_cctx object.
|
||||
* If @return != zero, there was an error during context creation.
|
||||
* Object can release its memory using LZ4F_freeCompressionContext();
|
||||
*/
|
||||
LZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version);
|
||||
LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
|
||||
|
||||
|
||||
/*---- Compression ----*/
|
||||
|
||||
#define LZ4F_HEADER_SIZE_MIN 7 /* LZ4 Frame header size can vary, depending on selected paramaters */
|
||||
#define LZ4F_HEADER_SIZE_MAX 19
|
||||
|
||||
/* Size in bytes of a block header in little-endian format. Highest bit indicates if block data is uncompressed */
|
||||
#define LZ4F_BLOCK_HEADER_SIZE 4
|
||||
|
||||
/* Size in bytes of a block checksum footer in little-endian format. */
|
||||
#define LZ4F_BLOCK_CHECKSUM_SIZE 4
|
||||
|
||||
/* Size in bytes of the content checksum. */
|
||||
#define LZ4F_CONTENT_CHECKSUM_SIZE 4
|
||||
|
||||
/*! LZ4F_compressBegin() :
|
||||
* will write the frame header into dstBuffer.
|
||||
* dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.
|
||||
* `prefsPtr` is optional : you can provide NULL as argument, all preferences will then be set to default.
|
||||
* @return : number of bytes written into dstBuffer for the header
|
||||
* or an error code (which can be tested using LZ4F_isError())
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_cctx* cctx,
|
||||
void* dstBuffer, size_t dstCapacity,
|
||||
const LZ4F_preferences_t* prefsPtr);
|
||||
|
||||
/*! LZ4F_compressBound() :
|
||||
* Provides minimum dstCapacity required to guarantee success of
|
||||
* LZ4F_compressUpdate(), given a srcSize and preferences, for a worst case scenario.
|
||||
* When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() instead.
|
||||
* Note that the result is only valid for a single invocation of LZ4F_compressUpdate().
|
||||
* When invoking LZ4F_compressUpdate() multiple times,
|
||||
* if the output buffer is gradually filled up instead of emptied and re-used from its start,
|
||||
* one must check if there is enough remaining capacity before each invocation, using LZ4F_compressBound().
|
||||
* @return is always the same for a srcSize and prefsPtr.
|
||||
* prefsPtr is optional : when NULL is provided, preferences will be set to cover worst case scenario.
|
||||
* tech details :
|
||||
* @return if automatic flushing is not enabled, includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes.
|
||||
* It also includes frame footer (ending + checksum), since it might be generated by LZ4F_compressEnd().
|
||||
* @return doesn't include frame header, as it was already generated by LZ4F_compressBegin().
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* prefsPtr);
|
||||
|
||||
/*! LZ4F_compressUpdate() :
|
||||
* LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
|
||||
* Important rule: dstCapacity MUST be large enough to ensure operation success even in worst case situations.
|
||||
* This value is provided by LZ4F_compressBound().
|
||||
* If this condition is not respected, LZ4F_compress() will fail (result is an errorCode).
|
||||
* LZ4F_compressUpdate() doesn't guarantee error recovery.
|
||||
* When an error occurs, compression context must be freed or resized.
|
||||
* `cOptPtr` is optional : NULL can be provided, in which case all options are set to default.
|
||||
* @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered).
|
||||
* or an error code if it fails (which can be tested using LZ4F_isError())
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_compressUpdate(LZ4F_cctx* cctx,
|
||||
void* dstBuffer, size_t dstCapacity,
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
const LZ4F_compressOptions_t* cOptPtr);
|
||||
|
||||
/*! LZ4F_flush() :
|
||||
* When data must be generated and sent immediately, without waiting for a block to be completely filled,
|
||||
* it's possible to call LZ4_flush(). It will immediately compress any data buffered within cctx.
|
||||
* `dstCapacity` must be large enough to ensure the operation will be successful.
|
||||
* `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default.
|
||||
* @return : nb of bytes written into dstBuffer (can be zero, when there is no data stored within cctx)
|
||||
* or an error code if it fails (which can be tested using LZ4F_isError())
|
||||
* Note : LZ4F_flush() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr).
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_flush(LZ4F_cctx* cctx,
|
||||
void* dstBuffer, size_t dstCapacity,
|
||||
const LZ4F_compressOptions_t* cOptPtr);
|
||||
|
||||
/*! LZ4F_compressEnd() :
|
||||
* To properly finish an LZ4 frame, invoke LZ4F_compressEnd().
|
||||
* It will flush whatever data remained within `cctx` (like LZ4_flush())
|
||||
* and properly finalize the frame, with an endMark and a checksum.
|
||||
* `cOptPtr` is optional : NULL can be provided, in which case all options will be set to default.
|
||||
* @return : nb of bytes written into dstBuffer, necessarily >= 4 (endMark),
|
||||
* or an error code if it fails (which can be tested using LZ4F_isError())
|
||||
* Note : LZ4F_compressEnd() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr).
|
||||
* A successful call to LZ4F_compressEnd() makes `cctx` available again for another compression task.
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_compressEnd(LZ4F_cctx* cctx,
|
||||
void* dstBuffer, size_t dstCapacity,
|
||||
const LZ4F_compressOptions_t* cOptPtr);
|
||||
|
||||
|
||||
/*-*********************************
|
||||
* Decompression functions
|
||||
***********************************/
|
||||
typedef struct LZ4F_dctx_s LZ4F_dctx; /* incomplete type */
|
||||
typedef LZ4F_dctx* LZ4F_decompressionContext_t; /* compatibility with previous API versions */
|
||||
|
||||
typedef struct {
|
||||
unsigned stableDst; /* pledges that last 64KB decompressed data will remain available unmodified. This optimization skips storage operations in tmp buffers. */
|
||||
unsigned reserved[3]; /* must be set to zero for forward compatibility */
|
||||
} LZ4F_decompressOptions_t;
|
||||
|
||||
|
||||
/* Resource management */
|
||||
|
||||
/*! LZ4F_createDecompressionContext() :
|
||||
* Create an LZ4F_dctx object, to track all decompression operations.
|
||||
* The version provided MUST be LZ4F_VERSION.
|
||||
* The function provides a pointer to an allocated and initialized LZ4F_dctx object.
|
||||
* The result is an errorCode, which can be tested using LZ4F_isError().
|
||||
* dctx memory can be released using LZ4F_freeDecompressionContext();
|
||||
* Result of LZ4F_freeDecompressionContext() indicates current state of decompressionContext when being released.
|
||||
* That is, it should be == 0 if decompression has been completed fully and correctly.
|
||||
*/
|
||||
LZ4FLIB_API LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** dctxPtr, unsigned version);
|
||||
LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx);
|
||||
|
||||
|
||||
/*-***********************************
|
||||
* Streaming decompression functions
|
||||
*************************************/
|
||||
|
||||
#define LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH 5
|
||||
|
||||
/*! LZ4F_headerSize() : v1.9.0+
|
||||
* Provide the header size of a frame starting at `src`.
|
||||
* `srcSize` must be >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH,
|
||||
* which is enough to decode the header length.
|
||||
* @return : size of frame header
|
||||
* or an error code, which can be tested using LZ4F_isError()
|
||||
* note : Frame header size is variable, but is guaranteed to be
|
||||
* >= LZ4F_HEADER_SIZE_MIN bytes, and <= LZ4F_HEADER_SIZE_MAX bytes.
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_headerSize(const void* src, size_t srcSize);
|
||||
|
||||
/*! LZ4F_getFrameInfo() :
|
||||
* This function extracts frame parameters (max blockSize, dictID, etc.).
|
||||
* Its usage is optional: user can call LZ4F_decompress() directly.
|
||||
*
|
||||
* Extracted information will fill an existing LZ4F_frameInfo_t structure.
|
||||
* This can be useful for allocation and dictionary identification purposes.
|
||||
*
|
||||
* LZ4F_getFrameInfo() can work in the following situations :
|
||||
*
|
||||
* 1) At the beginning of a new frame, before any invocation of LZ4F_decompress().
|
||||
* It will decode header from `srcBuffer`,
|
||||
* consuming the header and starting the decoding process.
|
||||
*
|
||||
* Input size must be large enough to contain the full frame header.
|
||||
* Frame header size can be known beforehand by LZ4F_headerSize().
|
||||
* Frame header size is variable, but is guaranteed to be >= LZ4F_HEADER_SIZE_MIN bytes,
|
||||
* and not more than <= LZ4F_HEADER_SIZE_MAX bytes.
|
||||
* Hence, blindly providing LZ4F_HEADER_SIZE_MAX bytes or more will always work.
|
||||
* It's allowed to provide more input data than the header size,
|
||||
* LZ4F_getFrameInfo() will only consume the header.
|
||||
*
|
||||
* If input size is not large enough,
|
||||
* aka if it's smaller than header size,
|
||||
* function will fail and return an error code.
|
||||
*
|
||||
* 2) After decoding has been started,
|
||||
* it's possible to invoke LZ4F_getFrameInfo() anytime
|
||||
* to extract already decoded frame parameters stored within dctx.
|
||||
*
|
||||
* Note that, if decoding has barely started,
|
||||
* and not yet read enough information to decode the header,
|
||||
* LZ4F_getFrameInfo() will fail.
|
||||
*
|
||||
* The number of bytes consumed from srcBuffer will be updated in *srcSizePtr (necessarily <= original value).
|
||||
* LZ4F_getFrameInfo() only consumes bytes when decoding has not yet started,
|
||||
* and when decoding the header has been successful.
|
||||
* Decompression must then resume from (srcBuffer + *srcSizePtr).
|
||||
*
|
||||
* @return : a hint about how many srcSize bytes LZ4F_decompress() expects for next call,
|
||||
* or an error code which can be tested using LZ4F_isError().
|
||||
* note 1 : in case of error, dctx is not modified. Decoding operation can resume from beginning safely.
|
||||
* note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,
|
||||
LZ4F_frameInfo_t* frameInfoPtr,
|
||||
const void* srcBuffer, size_t* srcSizePtr);
|
||||
|
||||
/*! LZ4F_decompress() :
|
||||
* Call this function repetitively to regenerate data compressed in `srcBuffer`.
|
||||
*
|
||||
* The function requires a valid dctx state.
|
||||
* It will read up to *srcSizePtr bytes from srcBuffer,
|
||||
* and decompress data into dstBuffer, of capacity *dstSizePtr.
|
||||
*
|
||||
* The nb of bytes consumed from srcBuffer will be written into *srcSizePtr (necessarily <= original value).
|
||||
* The nb of bytes decompressed into dstBuffer will be written into *dstSizePtr (necessarily <= original value).
|
||||
*
|
||||
* The function does not necessarily read all input bytes, so always check value in *srcSizePtr.
|
||||
* Unconsumed source data must be presented again in subsequent invocations.
|
||||
*
|
||||
* `dstBuffer` can freely change between each consecutive function invocation.
|
||||
* `dstBuffer` content will be overwritten.
|
||||
*
|
||||
* @return : an hint of how many `srcSize` bytes LZ4F_decompress() expects for next call.
|
||||
* Schematically, it's the size of the current (or remaining) compressed block + header of next block.
|
||||
* Respecting the hint provides some small speed benefit, because it skips intermediate buffers.
|
||||
* This is just a hint though, it's always possible to provide any srcSize.
|
||||
*
|
||||
* When a frame is fully decoded, @return will be 0 (no more data expected).
|
||||
* When provided with more bytes than necessary to decode a frame,
|
||||
* LZ4F_decompress() will stop reading exactly at end of current frame, and @return 0.
|
||||
*
|
||||
* If decompression failed, @return is an error code, which can be tested using LZ4F_isError().
|
||||
* After a decompression error, the `dctx` context is not resumable.
|
||||
* Use LZ4F_resetDecompressionContext() to return to clean state.
|
||||
*
|
||||
* After a frame is fully decoded, dctx can be used again to decompress another frame.
|
||||
*/
|
||||
LZ4FLIB_API size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
||||
void* dstBuffer, size_t* dstSizePtr,
|
||||
const void* srcBuffer, size_t* srcSizePtr,
|
||||
const LZ4F_decompressOptions_t* dOptPtr);
|
||||
|
||||
|
||||
/*! LZ4F_resetDecompressionContext() : added in v1.8.0
|
||||
* In case of an error, the context is left in "undefined" state.
|
||||
* In which case, it's necessary to reset it, before re-using it.
|
||||
* This method can also be used to abruptly stop any unfinished decompression,
|
||||
* and start a new one using same context resources. */
|
||||
LZ4FLIB_API void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx); /* always successful */
|
||||
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LZ4F_H_09782039843 */
|
||||
|
||||
#if defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843)
|
||||
#define LZ4F_H_STATIC_09782039843
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* These declarations are not stable and may change in the future.
|
||||
* They are therefore only safe to depend on
|
||||
* when the caller is statically linked against the library.
|
||||
* To access their declarations, define LZ4F_STATIC_LINKING_ONLY.
|
||||
*
|
||||
* By default, these symbols aren't published into shared/dynamic libraries.
|
||||
* You can override this behavior and force them to be published
|
||||
* by defining LZ4F_PUBLISH_STATIC_FUNCTIONS.
|
||||
* Use at your own risk.
|
||||
*/
|
||||
#ifdef LZ4F_PUBLISH_STATIC_FUNCTIONS
|
||||
# define LZ4FLIB_STATIC_API LZ4FLIB_API
|
||||
#else
|
||||
# define LZ4FLIB_STATIC_API
|
||||
#endif
|
||||
|
||||
|
||||
/* --- Error List --- */
|
||||
#define LZ4F_LIST_ERRORS(ITEM) \
|
||||
ITEM(OK_NoError) \
|
||||
ITEM(ERROR_GENERIC) \
|
||||
ITEM(ERROR_maxBlockSize_invalid) \
|
||||
ITEM(ERROR_blockMode_invalid) \
|
||||
ITEM(ERROR_contentChecksumFlag_invalid) \
|
||||
ITEM(ERROR_compressionLevel_invalid) \
|
||||
ITEM(ERROR_headerVersion_wrong) \
|
||||
ITEM(ERROR_blockChecksum_invalid) \
|
||||
ITEM(ERROR_reservedFlag_set) \
|
||||
ITEM(ERROR_allocation_failed) \
|
||||
ITEM(ERROR_srcSize_tooLarge) \
|
||||
ITEM(ERROR_dstMaxSize_tooSmall) \
|
||||
ITEM(ERROR_frameHeader_incomplete) \
|
||||
ITEM(ERROR_frameType_unknown) \
|
||||
ITEM(ERROR_frameSize_wrong) \
|
||||
ITEM(ERROR_srcPtr_wrong) \
|
||||
ITEM(ERROR_decompressionFailed) \
|
||||
ITEM(ERROR_headerChecksum_invalid) \
|
||||
ITEM(ERROR_contentChecksum_invalid) \
|
||||
ITEM(ERROR_frameDecoding_alreadyStarted) \
|
||||
ITEM(ERROR_maxCode)
|
||||
|
||||
#define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM,
|
||||
|
||||
/* enum list is exposed, to handle specific errors */
|
||||
typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM)
|
||||
_LZ4F_dummy_error_enum_for_c89_never_used } LZ4F_errorCodes;
|
||||
|
||||
LZ4FLIB_STATIC_API LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult);
|
||||
|
||||
LZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(unsigned);
|
||||
|
||||
/**********************************
|
||||
* Bulk processing dictionary API
|
||||
*********************************/
|
||||
|
||||
/* A Dictionary is useful for the compression of small messages (KB range).
|
||||
* It dramatically improves compression efficiency.
|
||||
*
|
||||
* LZ4 can ingest any input as dictionary, though only the last 64 KB are useful.
|
||||
* Best results are generally achieved by using Zstandard's Dictionary Builder
|
||||
* to generate a high-quality dictionary from a set of samples.
|
||||
*
|
||||
* Loading a dictionary has a cost, since it involves construction of tables.
|
||||
* The Bulk processing dictionary API makes it possible to share this cost
|
||||
* over an arbitrary number of compression jobs, even concurrently,
|
||||
* markedly improving compression latency for these cases.
|
||||
*
|
||||
* The same dictionary will have to be used on the decompression side
|
||||
* for decoding to be successful.
|
||||
* To help identify the correct dictionary at decoding stage,
|
||||
* the frame header allows optional embedding of a dictID field.
|
||||
*/
|
||||
typedef struct LZ4F_CDict_s LZ4F_CDict;
|
||||
|
||||
/*! LZ4_createCDict() :
|
||||
* When compressing multiple messages / blocks using the same dictionary, it's recommended to load it just once.
|
||||
* LZ4_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.
|
||||
* LZ4_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.
|
||||
* `dictBuffer` can be released after LZ4_CDict creation, since its content is copied within CDict */
|
||||
LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize);
|
||||
LZ4FLIB_STATIC_API void LZ4F_freeCDict(LZ4F_CDict* CDict);
|
||||
|
||||
|
||||
/*! LZ4_compressFrame_usingCDict() :
|
||||
* Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary.
|
||||
* cctx must point to a context created by LZ4F_createCompressionContext().
|
||||
* If cdict==NULL, compress without a dictionary.
|
||||
* dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).
|
||||
* If this condition is not respected, function will fail (@return an errorCode).
|
||||
* The LZ4F_preferences_t structure is optional : you may provide NULL as argument,
|
||||
* but it's not recommended, as it's the only way to provide dictID in the frame header.
|
||||
* @return : number of bytes written into dstBuffer.
|
||||
* or an error code if it fails (can be tested using LZ4F_isError()) */
|
||||
LZ4FLIB_STATIC_API size_t LZ4F_compressFrame_usingCDict(
|
||||
LZ4F_cctx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
const LZ4F_CDict* cdict,
|
||||
const LZ4F_preferences_t* preferencesPtr);
|
||||
|
||||
|
||||
/*! LZ4F_compressBegin_usingCDict() :
|
||||
* Inits streaming dictionary compression, and writes the frame header into dstBuffer.
|
||||
* dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.
|
||||
* `prefsPtr` is optional : you may provide NULL as argument,
|
||||
* however, it's the only way to provide dictID in the frame header.
|
||||
* @return : number of bytes written into dstBuffer for the header,
|
||||
* or an error code (which can be tested using LZ4F_isError()) */
|
||||
LZ4FLIB_STATIC_API size_t LZ4F_compressBegin_usingCDict(
|
||||
LZ4F_cctx* cctx,
|
||||
void* dstBuffer, size_t dstCapacity,
|
||||
const LZ4F_CDict* cdict,
|
||||
const LZ4F_preferences_t* prefsPtr);
|
||||
|
||||
|
||||
/*! LZ4F_decompress_usingDict() :
|
||||
* Same as LZ4F_decompress(), using a predefined dictionary.
|
||||
* Dictionary is used "in place", without any preprocessing.
|
||||
* It must remain accessible throughout the entire frame decoding. */
|
||||
LZ4FLIB_STATIC_API size_t LZ4F_decompress_usingDict(
|
||||
LZ4F_dctx* dctxPtr,
|
||||
void* dstBuffer, size_t* dstSizePtr,
|
||||
const void* srcBuffer, size_t* srcSizePtr,
|
||||
const void* dict, size_t dictSize,
|
||||
const LZ4F_decompressOptions_t* decompressOptionsPtr);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843) */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
LZ4 auto-framing library
|
||||
Header File for static linking only
|
||||
Copyright (C) 2011-2020, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : https://github.com/lz4/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
#ifndef LZ4FRAME_STATIC_H_0398209384
|
||||
#define LZ4FRAME_STATIC_H_0398209384
|
||||
|
||||
/* The declarations that formerly were made here have been merged into
|
||||
* lz4frame.h, protected by the LZ4F_STATIC_LINKING_ONLY macro. Going forward,
|
||||
* it is recommended to simply include that header directly.
|
||||
*/
|
||||
|
||||
#define LZ4F_STATIC_LINKING_ONLY
|
||||
#include "lz4frame.h"
|
||||
|
||||
#endif /* LZ4FRAME_STATIC_H_0398209384 */
|
||||
+1619
File diff suppressed because it is too large.
Load diff
+413
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
LZ4 HC - High Compression Mode of LZ4
|
||||
Header File
|
||||
Copyright (C) 2011-2020, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : https://github.com/lz4/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
#ifndef LZ4_HC_H_19834876238432
|
||||
#define LZ4_HC_H_19834876238432
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* --- Dependency --- */
|
||||
/* note : lz4hc requires lz4.h/lz4.c for compilation */
|
||||
#include "lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */
|
||||
|
||||
|
||||
/* --- Useful constants --- */
|
||||
#define LZ4HC_CLEVEL_MIN 3
|
||||
#define LZ4HC_CLEVEL_DEFAULT 9
|
||||
#define LZ4HC_CLEVEL_OPT_MIN 10
|
||||
#define LZ4HC_CLEVEL_MAX 12
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Block Compression
|
||||
**************************************/
|
||||
/*! LZ4_compress_HC() :
|
||||
* Compress data from `src` into `dst`, using the powerful but slower "HC" algorithm.
|
||||
* `dst` must be already allocated.
|
||||
* Compression is guaranteed to succeed if `dstCapacity >= LZ4_compressBound(srcSize)` (see "lz4.h")
|
||||
* Max supported `srcSize` value is LZ4_MAX_INPUT_SIZE (see "lz4.h")
|
||||
* `compressionLevel` : any value between 1 and LZ4HC_CLEVEL_MAX will work.
|
||||
* Values > LZ4HC_CLEVEL_MAX behave the same as LZ4HC_CLEVEL_MAX.
|
||||
* @return : the number of bytes written into 'dst'
|
||||
* or 0 if compression fails.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel);
|
||||
|
||||
|
||||
/* Note :
|
||||
* Decompression functions are provided within "lz4.h" (BSD license)
|
||||
*/
|
||||
|
||||
|
||||
/*! LZ4_compress_HC_extStateHC() :
|
||||
* Same as LZ4_compress_HC(), but using an externally allocated memory segment for `state`.
|
||||
* `state` size is provided by LZ4_sizeofStateHC().
|
||||
* Memory segment must be aligned on 8-bytes boundaries (which a normal malloc() should do properly).
|
||||
*/
|
||||
LZ4LIB_API int LZ4_sizeofStateHC(void);
|
||||
LZ4LIB_API int LZ4_compress_HC_extStateHC(void* stateHC, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel);
|
||||
|
||||
|
||||
/*! LZ4_compress_HC_destSize() : v1.9.0+
|
||||
* Will compress as much data as possible from `src`
|
||||
* to fit into `targetDstSize` budget.
|
||||
* Result is provided in 2 parts :
|
||||
* @return : the number of bytes written into 'dst' (necessarily <= targetDstSize)
|
||||
* or 0 if compression fails.
|
||||
* `srcSizePtr` : on success, *srcSizePtr is updated to indicate how much bytes were read from `src`
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_HC_destSize(void* stateHC,
|
||||
const char* src, char* dst,
|
||||
int* srcSizePtr, int targetDstSize,
|
||||
int compressionLevel);
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Streaming Compression
|
||||
* Bufferless synchronous API
|
||||
**************************************/
|
||||
typedef union LZ4_streamHC_u LZ4_streamHC_t; /* incomplete type (defined later) */
|
||||
|
||||
/*! LZ4_createStreamHC() and LZ4_freeStreamHC() :
|
||||
* These functions create and release memory for LZ4 HC streaming state.
|
||||
* Newly created states are automatically initialized.
|
||||
* A same state can be used multiple times consecutively,
|
||||
* starting with LZ4_resetStreamHC_fast() to start a new stream of blocks.
|
||||
*/
|
||||
LZ4LIB_API LZ4_streamHC_t* LZ4_createStreamHC(void);
|
||||
LZ4LIB_API int LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr);
|
||||
|
||||
/*
|
||||
These functions compress data in successive blocks of any size,
|
||||
using previous blocks as dictionary, to improve compression ratio.
|
||||
One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks.
|
||||
There is an exception for ring buffers, which can be smaller than 64 KB.
|
||||
Ring-buffer scenario is automatically detected and handled within LZ4_compress_HC_continue().
|
||||
|
||||
Before starting compression, state must be allocated and properly initialized.
|
||||
LZ4_createStreamHC() does both, though compression level is set to LZ4HC_CLEVEL_DEFAULT.
|
||||
|
||||
Selecting the compression level can be done with LZ4_resetStreamHC_fast() (starts a new stream)
|
||||
or LZ4_setCompressionLevel() (anytime, between blocks in the same stream) (experimental).
|
||||
LZ4_resetStreamHC_fast() only works on states which have been properly initialized at least once,
|
||||
which is automatically the case when state is created using LZ4_createStreamHC().
|
||||
|
||||
After reset, a first "fictional block" can be designated as initial dictionary,
|
||||
using LZ4_loadDictHC() (Optional).
|
||||
|
||||
Invoke LZ4_compress_HC_continue() to compress each successive block.
|
||||
The number of blocks is unlimited.
|
||||
Previous input blocks, including initial dictionary when present,
|
||||
must remain accessible and unmodified during compression.
|
||||
|
||||
It's allowed to update compression level anytime between blocks,
|
||||
using LZ4_setCompressionLevel() (experimental).
|
||||
|
||||
'dst' buffer should be sized to handle worst case scenarios
|
||||
(see LZ4_compressBound(), it ensures compression success).
|
||||
In case of failure, the API does not guarantee recovery,
|
||||
so the state _must_ be reset.
|
||||
To ensure compression success
|
||||
whenever `dst` buffer size cannot be made >= LZ4_compressBound(),
|
||||
consider using LZ4_compress_HC_continue_destSize().
|
||||
|
||||
Whenever previous input blocks can't be preserved unmodified in-place during compression of next blocks,
|
||||
it's possible to copy the last blocks into a more stable memory space, using LZ4_saveDictHC().
|
||||
Return value of LZ4_saveDictHC() is the size of dictionary effectively saved into 'safeBuffer' (<= 64 KB)
|
||||
|
||||
After completing a streaming compression,
|
||||
it's possible to start a new stream of blocks, using the same LZ4_streamHC_t state,
|
||||
just by resetting it, using LZ4_resetStreamHC_fast().
|
||||
*/
|
||||
|
||||
LZ4LIB_API void LZ4_resetStreamHC_fast(LZ4_streamHC_t* streamHCPtr, int compressionLevel); /* v1.9.0+ */
|
||||
LZ4LIB_API int LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize);
|
||||
|
||||
LZ4LIB_API int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr,
|
||||
const char* src, char* dst,
|
||||
int srcSize, int maxDstSize);
|
||||
|
||||
/*! LZ4_compress_HC_continue_destSize() : v1.9.0+
|
||||
* Similar to LZ4_compress_HC_continue(),
|
||||
* but will read as much data as possible from `src`
|
||||
* to fit into `targetDstSize` budget.
|
||||
* Result is provided into 2 parts :
|
||||
* @return : the number of bytes written into 'dst' (necessarily <= targetDstSize)
|
||||
* or 0 if compression fails.
|
||||
* `srcSizePtr` : on success, *srcSizePtr will be updated to indicate how much bytes were read from `src`.
|
||||
* Note that this function may not consume the entire input.
|
||||
*/
|
||||
LZ4LIB_API int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t* LZ4_streamHCPtr,
|
||||
const char* src, char* dst,
|
||||
int* srcSizePtr, int targetDstSize);
|
||||
|
||||
LZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize);
|
||||
|
||||
|
||||
|
||||
/*^**********************************************
|
||||
* !!!!!! STATIC LINKING ONLY !!!!!!
|
||||
***********************************************/
|
||||
|
||||
/*-******************************************************************
|
||||
* PRIVATE DEFINITIONS :
|
||||
* Do not use these definitions directly.
|
||||
* They are merely exposed to allow static allocation of `LZ4_streamHC_t`.
|
||||
* Declare an `LZ4_streamHC_t` directly, rather than any type below.
|
||||
* Even then, only do so in the context of static linking, as definitions may change between versions.
|
||||
********************************************************************/
|
||||
|
||||
#define LZ4HC_DICTIONARY_LOGSIZE 16
|
||||
#define LZ4HC_MAXD (1<<LZ4HC_DICTIONARY_LOGSIZE)
|
||||
#define LZ4HC_MAXD_MASK (LZ4HC_MAXD - 1)
|
||||
|
||||
#define LZ4HC_HASH_LOG 15
|
||||
#define LZ4HC_HASHTABLESIZE (1 << LZ4HC_HASH_LOG)
|
||||
#define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1)
|
||||
|
||||
|
||||
typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal;
|
||||
struct LZ4HC_CCtx_internal
|
||||
{
|
||||
LZ4_u32 hashTable[LZ4HC_HASHTABLESIZE];
|
||||
LZ4_u16 chainTable[LZ4HC_MAXD];
|
||||
const LZ4_byte* end; /* next block here to continue on current prefix */
|
||||
const LZ4_byte* base; /* All index relative to this position */
|
||||
const LZ4_byte* dictBase; /* alternate base for extDict */
|
||||
LZ4_u32 dictLimit; /* below that point, need extDict */
|
||||
LZ4_u32 lowLimit; /* below that point, no more dict */
|
||||
LZ4_u32 nextToUpdate; /* index from which to continue dictionary update */
|
||||
short compressionLevel;
|
||||
LZ4_i8 favorDecSpeed; /* favor decompression speed if this flag set,
|
||||
otherwise, favor compression ratio */
|
||||
LZ4_i8 dirty; /* stream has to be fully reset if this flag is set */
|
||||
const LZ4HC_CCtx_internal* dictCtx;
|
||||
};
|
||||
|
||||
|
||||
/* Do not use these definitions directly !
|
||||
* Declare or allocate an LZ4_streamHC_t instead.
|
||||
*/
|
||||
#define LZ4_STREAMHCSIZE 262200 /* static size, for inter-version compatibility */
|
||||
#define LZ4_STREAMHCSIZE_VOIDP (LZ4_STREAMHCSIZE / sizeof(void*))
|
||||
union LZ4_streamHC_u {
|
||||
void* table[LZ4_STREAMHCSIZE_VOIDP];
|
||||
LZ4HC_CCtx_internal internal_donotuse;
|
||||
}; /* previously typedef'd to LZ4_streamHC_t */
|
||||
|
||||
/* LZ4_streamHC_t :
|
||||
* This structure allows static allocation of LZ4 HC streaming state.
|
||||
* This can be used to allocate statically, on state, or as part of a larger structure.
|
||||
*
|
||||
* Such state **must** be initialized using LZ4_initStreamHC() before first use.
|
||||
*
|
||||
* Note that invoking LZ4_initStreamHC() is not required when
|
||||
* the state was created using LZ4_createStreamHC() (which is recommended).
|
||||
* Using the normal builder, a newly created state is automatically initialized.
|
||||
*
|
||||
* Static allocation shall only be used in combination with static linking.
|
||||
*/
|
||||
|
||||
/* LZ4_initStreamHC() : v1.9.0+
|
||||
* Required before first use of a statically allocated LZ4_streamHC_t.
|
||||
* Before v1.9.0 : use LZ4_resetStreamHC() instead
|
||||
*/
|
||||
LZ4LIB_API LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size);
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Deprecated Functions
|
||||
**************************************/
|
||||
/* see lz4.h LZ4_DISABLE_DEPRECATE_WARNINGS to turn off deprecation warnings */
|
||||
|
||||
/* deprecated compression functions */
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC() instead") LZ4LIB_API int LZ4_compressHC (const char* source, char* dest, int inputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC() instead") LZ4LIB_API int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC() instead") LZ4LIB_API int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC() instead") LZ4LIB_API int LZ4_compressHC2_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") LZ4LIB_API int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") LZ4LIB_API int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") LZ4LIB_API int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") LZ4LIB_API int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
/* Obsolete streaming functions; degraded functionality; do not use!
|
||||
*
|
||||
* In order to perform streaming compression, these functions depended on data
|
||||
* that is no longer tracked in the state. They have been preserved as well as
|
||||
* possible: using them will still produce a correct output. However, use of
|
||||
* LZ4_slideInputBufferHC() will truncate the history of the stream, rather
|
||||
* than preserve a window-sized chunk of history.
|
||||
*/
|
||||
LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API void* LZ4_createHC (const char* inputBuffer);
|
||||
LZ4_DEPRECATED("use LZ4_saveDictHC() instead") LZ4LIB_API char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
|
||||
LZ4_DEPRECATED("use LZ4_freeStreamHC() instead") LZ4LIB_API int LZ4_freeHC (void* LZ4HC_Data);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API int LZ4_sizeofStreamStateHC(void);
|
||||
LZ4_DEPRECATED("use LZ4_initStreamHC() instead") LZ4LIB_API int LZ4_resetStreamStateHC(void* state, char* inputBuffer);
|
||||
|
||||
|
||||
/* LZ4_resetStreamHC() is now replaced by LZ4_initStreamHC().
|
||||
* The intention is to emphasize the difference with LZ4_resetStreamHC_fast(),
|
||||
* which is now the recommended function to start a new stream of blocks,
|
||||
* but cannot be used to initialize a memory segment containing arbitrary garbage data.
|
||||
*
|
||||
* It is recommended to switch to LZ4_initStreamHC().
|
||||
* LZ4_resetStreamHC() will generate deprecation warnings in a future version.
|
||||
*/
|
||||
LZ4LIB_API void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel);
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LZ4_HC_H_19834876238432 */
|
||||
|
||||
|
||||
/*-**************************************************
|
||||
* !!!!! STATIC LINKING ONLY !!!!!
|
||||
* Following definitions are considered experimental.
|
||||
* They should not be linked from DLL,
|
||||
* as there is no guarantee of API stability yet.
|
||||
* Prototypes will be promoted to "stable" status
|
||||
* after successfull usage in real-life scenarios.
|
||||
***************************************************/
|
||||
#ifdef LZ4_HC_STATIC_LINKING_ONLY /* protection macro */
|
||||
#ifndef LZ4_HC_SLO_098092834
|
||||
#define LZ4_HC_SLO_098092834
|
||||
|
||||
#define LZ4_STATIC_LINKING_ONLY /* LZ4LIB_STATIC_API */
|
||||
#include "lz4.h"
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! LZ4_setCompressionLevel() : v1.8.0+ (experimental)
|
||||
* It's possible to change compression level
|
||||
* between successive invocations of LZ4_compress_HC_continue*()
|
||||
* for dynamic adaptation.
|
||||
*/
|
||||
LZ4LIB_STATIC_API void LZ4_setCompressionLevel(
|
||||
LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);
|
||||
|
||||
/*! LZ4_favorDecompressionSpeed() : v1.8.2+ (experimental)
|
||||
* Opt. Parser will favor decompression speed over compression ratio.
|
||||
* Only applicable to levels >= LZ4HC_CLEVEL_OPT_MIN.
|
||||
*/
|
||||
LZ4LIB_STATIC_API void LZ4_favorDecompressionSpeed(
|
||||
LZ4_streamHC_t* LZ4_streamHCPtr, int favor);
|
||||
|
||||
/*! LZ4_resetStreamHC_fast() : v1.9.0+
|
||||
* When an LZ4_streamHC_t is known to be in a internally coherent state,
|
||||
* it can often be prepared for a new compression with almost no work, only
|
||||
* sometimes falling back to the full, expensive reset that is always required
|
||||
* when the stream is in an indeterminate state (i.e., the reset performed by
|
||||
* LZ4_resetStreamHC()).
|
||||
*
|
||||
* LZ4_streamHCs are guaranteed to be in a valid state when:
|
||||
* - returned from LZ4_createStreamHC()
|
||||
* - reset by LZ4_resetStreamHC()
|
||||
* - memset(stream, 0, sizeof(LZ4_streamHC_t))
|
||||
* - the stream was in a valid state and was reset by LZ4_resetStreamHC_fast()
|
||||
* - the stream was in a valid state and was then used in any compression call
|
||||
* that returned success
|
||||
* - the stream was in an indeterminate state and was used in a compression
|
||||
* call that fully reset the state (LZ4_compress_HC_extStateHC()) and that
|
||||
* returned success
|
||||
*
|
||||
* Note:
|
||||
* A stream that was last used in a compression call that returned an error
|
||||
* may be passed to this function. However, it will be fully reset, which will
|
||||
* clear any existing history and settings from the context.
|
||||
*/
|
||||
LZ4LIB_STATIC_API void LZ4_resetStreamHC_fast(
|
||||
LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);
|
||||
|
||||
/*! LZ4_compress_HC_extStateHC_fastReset() :
|
||||
* A variant of LZ4_compress_HC_extStateHC().
|
||||
*
|
||||
* Using this variant avoids an expensive initialization step. It is only safe
|
||||
* to call if the state buffer is known to be correctly initialized already
|
||||
* (see above comment on LZ4_resetStreamHC_fast() for a definition of
|
||||
* "correctly initialized"). From a high level, the difference is that this
|
||||
* function initializes the provided state with a call to
|
||||
* LZ4_resetStreamHC_fast() while LZ4_compress_HC_extStateHC() starts with a
|
||||
* call to LZ4_resetStreamHC().
|
||||
*/
|
||||
LZ4LIB_STATIC_API int LZ4_compress_HC_extStateHC_fastReset (
|
||||
void* state,
|
||||
const char* src, char* dst,
|
||||
int srcSize, int dstCapacity,
|
||||
int compressionLevel);
|
||||
|
||||
/*! LZ4_attach_HC_dictionary() :
|
||||
* This is an experimental API that allows for the efficient use of a
|
||||
* static dictionary many times.
|
||||
*
|
||||
* Rather than re-loading the dictionary buffer into a working context before
|
||||
* each compression, or copying a pre-loaded dictionary's LZ4_streamHC_t into a
|
||||
* working LZ4_streamHC_t, this function introduces a no-copy setup mechanism,
|
||||
* in which the working stream references the dictionary stream in-place.
|
||||
*
|
||||
* Several assumptions are made about the state of the dictionary stream.
|
||||
* Currently, only streams which have been prepared by LZ4_loadDictHC() should
|
||||
* be expected to work.
|
||||
*
|
||||
* Alternatively, the provided dictionary stream pointer may be NULL, in which
|
||||
* case any existing dictionary stream is unset.
|
||||
*
|
||||
* A dictionary should only be attached to a stream without any history (i.e.,
|
||||
* a stream that has just been reset).
|
||||
*
|
||||
* The dictionary will remain attached to the working stream only for the
|
||||
* current stream session. Calls to LZ4_resetStreamHC(_fast) will remove the
|
||||
* dictionary context association from the working stream. The dictionary
|
||||
* stream (and source buffer) must remain in-place / accessible / unchanged
|
||||
* through the lifetime of the stream session.
|
||||
*/
|
||||
LZ4LIB_STATIC_API void LZ4_attach_HC_dictionary(
|
||||
LZ4_streamHC_t *working_stream,
|
||||
const LZ4_streamHC_t *dictionary_stream);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LZ4_HC_SLO_098092834 */
|
||||
#endif /* LZ4_HC_STATIC_LINKING_ONLY */
|
||||
+1030
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
xxHash - Extremely Fast Hash algorithm
|
||||
Header File
|
||||
Copyright (C) 2012-2016, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/* Notice extracted from xxHash homepage :
|
||||
|
||||
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
It also successfully passes all tests from the SMHasher suite.
|
||||
|
||||
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||
|
||||
Name Speed Q.Score Author
|
||||
xxHash 5.4 GB/s 10
|
||||
CrapWow 3.2 GB/s 2 Andrew
|
||||
MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
SBox 1.4 GB/s 9 Bret Mulvey
|
||||
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
CRC32 0.43 GB/s 9
|
||||
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
SHA1-32 0.28 GB/s 10
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
|
||||
A 64-bit version, named XXH64, is available since r35.
|
||||
It offers much better speed, but for 64-bit applications only.
|
||||
Name Speed on 64 bits Speed on 32 bits
|
||||
XXH64 13.8 GB/s 1.9 GB/s
|
||||
XXH32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#ifndef XXHASH_H_5627135585666179
|
||||
#define XXHASH_H_5627135585666179 1
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* ****************************
|
||||
* Definitions
|
||||
******************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||
|
||||
|
||||
/* ****************************
|
||||
* API modifier
|
||||
******************************/
|
||||
/** XXH_INLINE_ALL (and XXH_PRIVATE_API)
|
||||
* This is useful to include xxhash functions in `static` mode
|
||||
* in order to inline them, and remove their symbol from the public list.
|
||||
* Inlining can offer dramatic performance improvement on small keys.
|
||||
* Methodology :
|
||||
* #define XXH_INLINE_ALL
|
||||
* #include "xxhash.h"
|
||||
* `xxhash.c` is automatically included.
|
||||
* It's not useful to compile and link it as a separate module.
|
||||
*/
|
||||
#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
|
||||
# ifndef XXH_STATIC_LINKING_ONLY
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# endif
|
||||
# if defined(__GNUC__)
|
||||
# define XXH_PUBLIC_API static __inline __attribute__((unused))
|
||||
# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# define XXH_PUBLIC_API static inline
|
||||
# elif defined(_MSC_VER)
|
||||
# define XXH_PUBLIC_API static __inline
|
||||
# else
|
||||
/* this version may generate warnings for unused static functions */
|
||||
# define XXH_PUBLIC_API static
|
||||
# endif
|
||||
#else
|
||||
# define XXH_PUBLIC_API /* do nothing */
|
||||
#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */
|
||||
|
||||
/*! XXH_NAMESPACE, aka Namespace Emulation :
|
||||
*
|
||||
* If you want to include _and expose_ xxHash functions from within your own library,
|
||||
* but also want to avoid symbol collisions with other libraries which may also include xxHash,
|
||||
*
|
||||
* you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
|
||||
* with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).
|
||||
*
|
||||
* Note that no change is required within the calling program as long as it includes `xxhash.h` :
|
||||
* regular symbol name will be automatically translated by this header.
|
||||
*/
|
||||
#ifdef XXH_NAMESPACE
|
||||
# define XXH_CAT(A,B) A##B
|
||||
# define XXH_NAME2(A,B) XXH_CAT(A,B)
|
||||
# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
|
||||
# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
|
||||
# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
|
||||
# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
|
||||
# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
|
||||
# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
|
||||
# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
|
||||
# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
|
||||
# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
|
||||
# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
|
||||
# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
|
||||
# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
|
||||
# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
|
||||
# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
|
||||
# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
|
||||
# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
|
||||
# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
|
||||
# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
|
||||
# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Version
|
||||
***************************************/
|
||||
#define XXH_VERSION_MAJOR 0
|
||||
#define XXH_VERSION_MINOR 6
|
||||
#define XXH_VERSION_RELEASE 5
|
||||
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||
|
||||
|
||||
/*-**********************************************************************
|
||||
* 32-bit hash
|
||||
************************************************************************/
|
||||
typedef unsigned int XXH32_hash_t;
|
||||
|
||||
/*! XXH32() :
|
||||
Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input".
|
||||
The memory between input & input+length must be valid (allocated and read-accessible).
|
||||
"seed" can be used to alter the result predictably.
|
||||
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
|
||||
|
||||
/*====== Streaming ======*/
|
||||
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
|
||||
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
|
||||
|
||||
/*
|
||||
* Streaming functions generate the xxHash of an input provided in multiple segments.
|
||||
* Note that, for small input, they are slower than single-call functions, due to state management.
|
||||
* For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.
|
||||
*
|
||||
* XXH state must first be allocated, using XXH*_createState() .
|
||||
*
|
||||
* Start a new hash by initializing state with a seed, using XXH*_reset().
|
||||
*
|
||||
* Then, feed the hash state by calling XXH*_update() as many times as necessary.
|
||||
* The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
||||
*
|
||||
* Finally, a hash value can be produced anytime, by using XXH*_digest().
|
||||
* This function returns the nn-bits hash as an int or long long.
|
||||
*
|
||||
* It's still possible to continue inserting input into the hash state after a digest,
|
||||
* and generate some new hashes later on, by calling again XXH*_digest().
|
||||
*
|
||||
* When done, free XXH state space if it was allocated dynamically.
|
||||
*/
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
|
||||
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
|
||||
|
||||
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
|
||||
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
|
||||
* These functions allow transformation of hash result into and from its canonical format.
|
||||
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef XXH_NO_LONG_LONG
|
||||
/*-**********************************************************************
|
||||
* 64-bit hash
|
||||
************************************************************************/
|
||||
typedef unsigned long long XXH64_hash_t;
|
||||
|
||||
/*! XXH64() :
|
||||
Calculate the 64-bit hash of sequence of length "len" stored at memory address "input".
|
||||
"seed" can be used to alter the result predictably.
|
||||
This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark).
|
||||
*/
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
|
||||
|
||||
/*====== Streaming ======*/
|
||||
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
|
||||
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
|
||||
#endif /* XXH_NO_LONG_LONG */
|
||||
|
||||
|
||||
|
||||
#ifdef XXH_STATIC_LINKING_ONLY
|
||||
|
||||
/* ================================================================================================
|
||||
This section contains declarations which are not guaranteed to remain stable.
|
||||
They may change in future versions, becoming incompatible with a different version of the library.
|
||||
These declarations should only be used with static linking.
|
||||
Never use them in association with dynamic linking !
|
||||
=================================================================================================== */
|
||||
|
||||
/* These definitions are only present to allow
|
||||
* static allocation of XXH state, on stack or in a struct for example.
|
||||
* Never **ever** use members directly. */
|
||||
|
||||
#if !defined (__VMS) \
|
||||
&& (defined (__cplusplus) \
|
||||
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
|
||||
# include <stdint.h>
|
||||
|
||||
struct XXH32_state_s {
|
||||
uint32_t total_len_32;
|
||||
uint32_t large_len;
|
||||
uint32_t v1;
|
||||
uint32_t v2;
|
||||
uint32_t v3;
|
||||
uint32_t v4;
|
||||
uint32_t mem32[4];
|
||||
uint32_t memsize;
|
||||
uint32_t reserved; /* never read nor write, might be removed in a future version */
|
||||
}; /* typedef'd to XXH32_state_t */
|
||||
|
||||
struct XXH64_state_s {
|
||||
uint64_t total_len;
|
||||
uint64_t v1;
|
||||
uint64_t v2;
|
||||
uint64_t v3;
|
||||
uint64_t v4;
|
||||
uint64_t mem64[4];
|
||||
uint32_t memsize;
|
||||
uint32_t reserved[2]; /* never read nor write, might be removed in a future version */
|
||||
}; /* typedef'd to XXH64_state_t */
|
||||
|
||||
# else
|
||||
|
||||
struct XXH32_state_s {
|
||||
unsigned total_len_32;
|
||||
unsigned large_len;
|
||||
unsigned v1;
|
||||
unsigned v2;
|
||||
unsigned v3;
|
||||
unsigned v4;
|
||||
unsigned mem32[4];
|
||||
unsigned memsize;
|
||||
unsigned reserved; /* never read nor write, might be removed in a future version */
|
||||
}; /* typedef'd to XXH32_state_t */
|
||||
|
||||
# ifndef XXH_NO_LONG_LONG /* remove 64-bit support */
|
||||
struct XXH64_state_s {
|
||||
unsigned long long total_len;
|
||||
unsigned long long v1;
|
||||
unsigned long long v2;
|
||||
unsigned long long v3;
|
||||
unsigned long long v4;
|
||||
unsigned long long mem64[4];
|
||||
unsigned memsize;
|
||||
unsigned reserved[2]; /* never read nor write, might be removed in a future version */
|
||||
}; /* typedef'd to XXH64_state_t */
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
|
||||
#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
|
||||
# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */
|
||||
#endif
|
||||
|
||||
#endif /* XXH_STATIC_LINKING_ONLY */
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XXHASH_H_5627135585666179 */
|
||||
@@ -1134,10 +1134,6 @@ int CFred_mission_save::save_cmd_brief()
|
||||
required_string_fred("#Command Briefing");
|
||||
parse_comments(2);
|
||||
|
||||
if (The_mission.game_type & MISSION_TYPE_MULTI) {
|
||||
return err;
|
||||
} // no command briefings allowed in multiplayer missions.
|
||||
|
||||
save_custom_bitmap("$Background 640:",
|
||||
"$Background 1024:",
|
||||
Cur_cmd_brief->background[GR_640],
|
||||
|
||||
@@ -79,6 +79,7 @@ MissionSpecDialog::MissionSpecDialog(FredView* parent, EditorViewport* viewport)
|
||||
connect(ui->toggleAutopilotCinematics, &QCheckBox::toggled, this, [this](bool param) {flagToggled(param, Mission::Mission_Flags::Use_ap_cinematics); });
|
||||
connect(ui->toggleHardcodedAutopilot, &QCheckBox::toggled, this, [this](bool param) {flagToggled(param, Mission::Mission_Flags::Deactivate_ap); });
|
||||
connect(ui->toggleAIControlStart, &QCheckBox::toggled, this, [this](bool param) {flagToggled(param, Mission::Mission_Flags::Player_start_ai); });
|
||||
connect(ui->toggleChaseViewStart, &QCheckBox::toggled, this, [this](bool param) {flagToggled(param, Mission::Mission_Flags::Player_start_chase_view); });
|
||||
connect(ui->toggle2DMission, &QCheckBox::toggled, this, [this](bool param) {flagToggled(param, Mission::Mission_Flags::Mission_2d); });
|
||||
connect(ui->toggleGoalsInBriefing, &QCheckBox::toggled, this, [this](bool param) {flagToggled(param, Mission::Mission_Flags::Always_show_goals); });
|
||||
connect(ui->toggleMissionEndToMainhall, &QCheckBox::toggled, this, [this](bool param) {flagToggled(param, Mission::Mission_Flags::End_to_mainhall); });
|
||||
@@ -236,6 +237,7 @@ void MissionSpecDialog::updateFlags() {
|
||||
auto flags = _model->getMissionFlags();
|
||||
ui->toggle2DMission->setChecked(flags[Mission::Mission_Flags::Mission_2d]);
|
||||
ui->toggleAIControlStart->setChecked(flags[Mission::Mission_Flags::Player_start_ai]);
|
||||
ui->toggleChaseViewStart->setChecked(flags[Mission::Mission_Flags::Player_start_chase_view]);
|
||||
ui->toggleAllTeamsAtWar->setChecked(flags[Mission::Mission_Flags::All_attack]);
|
||||
ui->toggleAutopilotCinematics->setChecked(flags[Mission::Mission_Flags::Use_ap_cinematics]);
|
||||
ui->toggleBeamFreeDefault->setChecked(flags[Mission::Mission_Flags::Beam_free_all_by_default]);
|
||||
|
||||
@@ -887,6 +887,16 @@
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggleChaseViewStart">
|
||||
<property name="text">
|
||||
<string>Player Starts in Chase View</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">m_flagGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle2DMission">
|
||||
<property name="text">
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
set(FSO_VERSION_MAJOR 21)
|
||||
set(FSO_VERSION_MINOR 2)
|
||||
set(FSO_VERSION_BUILD 0)
|
||||
set(FSO_VERSION_REVISION 0)
|
||||
set(FSO_VERSION_REVISION_STR )
|
||||
Reference in new issue
Block a user