diff --git a/source/interface/first_person_weapons.c b/source/interface/first_person_weapons.c index 0b735111..75b4947b 100644 --- a/source/interface/first_person_weapons.c +++ b/source/interface/first_person_weapons.c @@ -117,6 +117,7 @@ symbols in this file: #include "models/models.h" #include "networking/network_connection.h" #include "objects/objects.h" +#include "rasterizer/rasterizer.h" /* port: rasterizer_memory_alloc */ #include "rasterizer/rasterizer_model_types.h" #include "render/render.h" #include "saved games/game_state.h" @@ -509,7 +510,21 @@ void first_person_weapon_draw( struct animation_graph *animation_graph= animation_graph_definition_get( weapon_definition->weapon.interface_definition.first_person_animations.index); struct render_lighting *lighting= object_get_cached_render_lighting(unit_index, FLT_MAX); + real values[NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS]; + real const *weapon_functions = weapon->object.outgoing_function_values; + real const *unit_functions = unit->object.outgoing_function_values; + real *kept; + /* port: the tick's functions, moved into this frame, so the + charge clicks with the picture instead of once a tick; kept + in the rasterizer's memory for the frame, as the groups drawn + later read them (render_objects.c) */ + object_function_values_for_render(first_person_weapon->weapon_index, values); + if ((kept = rasterizer_memory_alloc(values, sizeof(values))) != NULL) + weapon_functions = kept; + object_function_values_for_render(unit_index, values); + if ((kept = rasterizer_memory_alloc(values, sizeof(values))) != NULL) + unit_functions = kept; model_effect.modifier_shader= NULL; if (TEST_FLAG(unit->unit.flags, _unit_active_camouflaged_bit) || unit->unit.active_camouflage>0.0f) @@ -540,7 +555,7 @@ void first_person_weapon_draw( model_node_matrices, NULL, weapon->object.outgoing_change_colors, - weapon->object.outgoing_function_values, + weapon_functions, lighting, &render.camera.position, 0.0f, @@ -569,7 +584,7 @@ void first_person_weapon_draw( model_effect.modifier_animation.colors= shield_color_colors(unit_index, unit->object.outgoing_change_colors); model_effect.modifier_animation.values= overshield_effect_values(unit_index, - unit->object.outgoing_function_values, TRUE); + unit_functions, TRUE); } } } @@ -589,7 +604,7 @@ void first_person_weapon_draw( model_node_matrices, NULL, unit->object.outgoing_change_colors, - unit->object.outgoing_function_values, + unit_functions, lighting, &render.camera.position, 0.0f, diff --git a/source/objects/objects.c b/source/objects/objects.c index fa99d7c1..8fb123ae 100644 --- a/source/objects/objects.c +++ b/source/objects/objects.c @@ -97,6 +97,19 @@ index, which reads no function: 0 */ #define OBJECT_FRAME_INDEX_GET(object_index) ((object_index) + game_time_get()) +/* port: set while a frame is drawn, so a function read for the picture is +the tick's value moved into the frame */ +static int object_function_render_depth = 0; + +static real object_function_addition( + struct object_datum *object, + struct object_function_definition *function, + real huh, + real const *outgoing, + boolean *active); +static real object_function_wrap( + real value); + /* ---------- structures */ struct object_globals @@ -1550,6 +1563,77 @@ void object_permute_region( return; } +void object_functions_set_for_render( + boolean for_render) +{ + if (for_render) + object_function_render_depth++; + else if (object_function_render_depth > 0) + object_function_render_depth--; +} + +void object_function_values_for_render( + long object_index, + real values[NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS]) +{ + struct object_datum *object = object_get(object_index); + struct object_definition *definition = object_definition_get(object->definition_index); + /* port: where the picture is, between the previous tick (0) and this one + (1) (render_interpolation.c); 1 outside an interpolated frame (Smooth + Motion off), where the tick's own values are shown */ + real fraction = render_interpolation_fraction(); + short function_count = (short)MIN( + definition->object.functions.count, + NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS); + short function_index; + real huh; + real back; + + csmemcpy( + values, + object->object.outgoing_function_values, + sizeof(object->object.outgoing_function_values)); + if (!(fraction >= 0.0f) || !(fraction < 1.0f)) + return; + + back = 1.0f - fraction; + huh = (57 * DATUM_INDEX_TO_ABSOLUTE_INDEX(object_index) + game_time_get()) * 0.033333335f; + for (function_index = 0; function_index < function_count; function_index++) + { + struct object_function_definition *function = TAG_BLOCK_GET_ELEMENT( + &definition->object.functions, + function_index, + struct object_function_definition); + boolean active; + real output; + + /* port: an additive function steps by a whole tick: the picture + is that part of the step back from this tick's value. Anything else + is the function at the picture's moment. */ + if (TEST_FLAG(function->flags, _object_function_clip_to_bounds_and_normalize)) + { + output = object_function_addition( + object, + function, + huh, + object->object.outgoing_function_values, + &active); + values[function_index] = object_function_wrap( + object->object.outgoing_function_values[function_index] - back * output); + } + else + { + output = object_function_addition( + object, + function, + huh - back * 0.033333335f, + values, + &active); + values[function_index] = output; + } + } +} + boolean object_get_function_value( long object_index, short function_index, @@ -1573,7 +1657,17 @@ boolean object_get_function_value( it reads as off */ if (VALID_INDEX(function_index, NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS)) { - *value_reference = object->object.outgoing_function_values[function_index]; + if (object_function_render_depth > 0) + { + real shown[NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS]; + + object_function_values_for_render(object_index, shown); + *value_reference = shown[function_index]; + } + else + { + *value_reference = object->object.outgoing_function_values[function_index]; + } result = TEST_FLAG(object->object.functions_active_flags, function_index); } @@ -5175,6 +5269,150 @@ static void object_delete_recursive( return; } +static real object_function_input_value( + struct object_datum *object, + real const *outgoing, + short index) +{ + if ((unsigned long)(index - 1) >= + (unsigned long)(NUMBER_OF_INCOMING_OBJECT_FUNCTIONS + NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS)) + return 0.0f; + if (index >= NUMBER_OF_INCOMING_OBJECT_FUNCTIONS + 1) + return outgoing[index - NUMBER_OF_INCOMING_OBJECT_FUNCTIONS - 1]; + return object->object.incoming_function_values[index - 1]; +} + +static real object_function_wrap( + real value) +{ + value -= (real)floor((double)value); + if (!(value >= 0.0f)) + value += 1.0f; + return value; +} + +/* port: the original's loop body, as one function, so that the picture's +values (object_function_values_for_render) are found as the tick's are: what +one tick stores, before an additive function folds it into the value it +already held. `outgoing` is the functions already computed. */ +static real object_function_addition( + struct object_datum *object, + struct object_function_definition *function, + real huh, + real const *outgoing, + boolean *active) +{ + real value; + real output; + boolean function_is_active = TRUE; + real period = function->runtime_one_over_period; + + if (function->scale_period_by_function_index) + { + real function_value = object_function_input_value( + object, + outgoing, + function->scale_period_by_function_index); + + if (function_value > 0.f) + period = period / function_value; + } + + value = periodic_function_evaluate(function->function_type, huh * period); + + if (function->scale_function_by_function_index) + { + value *= object_function_input_value( + object, + outgoing, + function->scale_function_by_function_index); + } + + if (TEST_FLAG(function->flags, _object_function_invert_function_bit)) + value = 1.f - value; + + if (function->wobble_magnitude != 0.f) + { + real val = periodic_function_evaluate( + function->wobble_function_type, + huh * function->wobble_period); + + value += (2.f * function->wobble_magnitude * (val - 0.5f)); + } + + if (function->square_wave_threshold != 0.f) + value = value > function->square_wave_threshold ? 1.f : 0.f; + + if (function->step_count > 1) + { + real floor_value = floor(function->step_count * value); + + value = floor_value * function->runtime_reciprocal_step_count; + } + + if (function->runtime_reciprocal_sawtooth_count > 0.f) + value = fmod(value, function->runtime_reciprocal_sawtooth_count); + + if (function->add_function_index) + { + value += object_function_input_value(object, outgoing, function->add_function_index); + value = MIN(value, 1.f); + } + + if (function->scale_result_by_function_index) + { + value *= object_function_input_value( + object, + outgoing, + function->scale_result_by_function_index); + } + + output = transition_function_evaluate(function->map_result_to_transition_function, value); + + if (function->scale_by > 0.f) + output *= function->scale_by; + + if (function->bounds_mode == _object_function_scale_to_fit_bounds) + { + output *= (function->upper_bound - function->lower_bound); + output += function->lower_bound; + + if (function->lower_bound + _real_epsilon >= output) + { + function_is_active = TEST_FLAG( + function->flags, + _object_function_does_not_deactivate_below_lower_bound_bit); + } + } + else + { + if (function->lower_bound + _real_epsilon >= output) + { + output = function->lower_bound; + function_is_active = TEST_FLAG( + function->flags, + _object_function_does_not_deactivate_below_lower_bound_bit); + } + + if (output > function->upper_bound) + output = function->upper_bound; + + if (function->bounds_mode == _object_function_clip_to_bounds_and_normalize) + { + output = (output - function->lower_bound) * function->runtime_reciprocal_bounds_range; + } + } + + if (function->turn_off_with_function_index != NONE && + !TEST_FLAG(object->object.functions_active_flags, function->turn_off_with_function_index)) + { + function_is_active = FALSE; + } + + *active = function_is_active; + return output; +} + static void object_compute_function_values( long object_index) { @@ -5194,112 +5432,20 @@ static void object_compute_function_values( for (function_index = 0; function_indexobject.functions, function_index, struct object_function_definition); - boolean function_is_active = TRUE; - real period = function->runtime_one_over_period; - - if (function->scale_period_by_function_index) - { - real function_value = OBJECT_INCOMING_FUNCTION_GET_VALUE(object, function->scale_period_by_function_index); - if (function_value>0.f) - { - period = period/function_value; - } - } - - value = periodic_function_evaluate(function->function_type, huh*period); - - if (function->scale_function_by_function_index) - { - value*= OBJECT_INCOMING_FUNCTION_GET_VALUE(object, function->scale_function_by_function_index); - } - - if (TEST_FLAG(function->flags, _object_function_invert_function_bit)) - { - value = 1.f-value; - } - - if (function->wobble_magnitude!=0.f) - { - real val = periodic_function_evaluate(function->wobble_function_type, huh*function->wobble_period); - value+= (2.f*function->wobble_magnitude * (val-0.5f)); - } - - if (function->square_wave_threshold!=0.f) - { - value = value>function->square_wave_threshold ? 1.f : 0.f ; - } - - if (function->step_count>1) - { - real floor_value = floor(function->step_count*value); - value = floor_value*function->runtime_reciprocal_step_count; - } - - if (function->runtime_reciprocal_sawtooth_count>0.f) - { - value = fmod(value, function->runtime_reciprocal_sawtooth_count); - } - - if (function->add_function_index) - { - value+= OBJECT_INCOMING_FUNCTION_GET_VALUE(object, function->add_function_index); - value = MIN(value, 1.f); - } - - if (function->scale_result_by_function_index) - { - value*= OBJECT_INCOMING_FUNCTION_GET_VALUE(object, function->scale_result_by_function_index); - } - - output = transition_function_evaluate(function->map_result_to_transition_function, value); - - if (function->scale_by>0.f) - { - output*= function->scale_by; - } - - if (function->bounds_mode==_object_function_scale_to_fit_bounds) - { - output*= (function->upper_bound-function->lower_bound); - output+= function->lower_bound; - - if (function->lower_bound+_real_epsilon>=output) - { - function_is_active = TEST_FLAG(function->flags, _object_function_does_not_deactivate_below_lower_bound_bit); - } - } - else - { - if (function->lower_bound+_real_epsilon>=output) - { - output = function->lower_bound; - function_is_active = TEST_FLAG(function->flags, _object_function_does_not_deactivate_below_lower_bound_bit); - } - - if (output>function->upper_bound) - { - output = function->upper_bound; - } - - if (function->bounds_mode==_object_function_clip_to_bounds_and_normalize) - { - output = (output-function->lower_bound)*function->runtime_reciprocal_bounds_range; - } - } - - if (function->turn_off_with_function_index!=NONE && - !TEST_FLAG(object->object.functions_active_flags, function->turn_off_with_function_index)) - { - function_is_active = FALSE; - } + boolean function_is_active; + real output = object_function_addition( + object, + function, + huh, + object->object.outgoing_function_values, + &function_is_active); + /* bit 1 is the additive function (the bounds-mode name shares its + value). It folds this tick onto the value already held. */ if (TEST_FLAG(function->flags, _object_function_clip_to_bounds_and_normalize)) { output = fmod(output+object->object.outgoing_function_values[function_index], 1.f); diff --git a/source/objects/objects.h b/source/objects/objects.h index 96dbee3f..e8afcc75 100644 --- a/source/objects/objects.h +++ b/source/objects/objects.h @@ -430,6 +430,11 @@ void object_start_interpolation(long object_index, short frame_count); void object_offset_interpolation(long object_index, real_vector3d *offset); void object_permute_region(long object_index, char *permutation_name, short desired_region_index, boolean active_flag); boolean object_get_function_value(long object_index, short function_index, real *value_reference); +/* port: the picture is drawn between ticks. While this is set, a function +read for drawing is the tick's value moved forward by the fraction of the +tick that has passed. */ +void object_functions_set_for_render(boolean for_render); +void object_function_values_for_render(long object_index, real values[NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS]); short objects_in_clusters_by_indices(unsigned long class_flags, short cluster_count, short const *cluster_indices, short maximum_object_count, long *object_indices); long object_index_from_name_index(short name_index); /* port: this object takes a scenario name nobody holds, the way a placed diff --git a/source/render/render.c b/source/render/render.c index ee4ad8cd..a86f7ded 100644 --- a/source/render/render.c +++ b/source/render/render.c @@ -325,6 +325,7 @@ static void render_window( render.local_player_index = local_player_index; render.camera = *camera; render.frustum = *frustum; + object_functions_set_for_render(TRUE); parameters.camera = *rasterizer_camera; parameters.frustum = *rasterizer_frustum; parameters.rasterizer_target = rasterizer_target; @@ -444,6 +445,7 @@ static void render_window( rasterizer_debug_draw(); rasterizer_window_end(); profile_render_window_end(); + object_functions_set_for_render(FALSE); return; } diff --git a/source/render/render_objects.c b/source/render/render_objects.c index d73d5163..212348c5 100644 --- a/source/render/render_objects.c +++ b/source/render/render_objects.c @@ -486,6 +486,13 @@ static void render_object_list( real_matrix4x3 const *node_matrices = legs ? first_person_legs_node_matrices(object_index, object_get_node_matrices(object_index)) : object_get_node_matrices(object_index); + /* port: the function values the picture shows + (object_function_values_for_render), kept in the rasterizer's memory + for the frame: a modifier's group, a queued transparent part and a + child that copies this modifier read them after this block is done, + and the overshield finds its own values by their address + (overshield_effect.c), so they are not copied again */ + real const *shown_functions = object->object.outgoing_function_values; if (!object_is_first_person_camera(object_index) || render.camera.mirrored || (legs && node_matrices)) { @@ -529,6 +536,17 @@ static void render_object_list( if (!data->shadow) { + /* port: the tick's functions, moved into this frame, so a + charge clicks with the picture instead of once a tick */ + { + real values[NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS]; + real *kept; + + object_function_values_for_render(object_index, values); + kept = rasterizer_memory_alloc(values, sizeof(values)); + if (kept) + shown_functions = kept; + } if (definition->object.modifier_shader.index != NONE) { model_effect.modifier_shader = shader_definition_get( @@ -546,8 +564,8 @@ static void render_object_list( (port/linux/game/overshield_effect.c) */ model_effect.modifier_animation.values = TEST_FLAG(_object_mask_unit, object->object.type) ? - overshield_effect_values(object_index, object->object.outgoing_function_values, FALSE) : - object->object.outgoing_function_values; + overshield_effect_values(object_index, shown_functions, FALSE) : + shown_functions; } else { @@ -629,7 +647,7 @@ static void render_object_list( node_matrices, object->object.region_permutations, object->object.outgoing_change_colors, - object->object.outgoing_function_values, + shown_functions, data->lighting, &object->object.bounding_sphere_center, object->object.bounding_sphere_radius, @@ -665,9 +683,13 @@ static void render_object_list( if (!data->shadow && !legs && object->object.first_widget_index != NONE) { struct render_animation animation; + real widget_functions[NUMBER_OF_OUTGOING_OBJECT_FUNCTIONS]; + /* port: the tick's functions, moved into this frame (the + widgets read them as they are drawn, here) */ + object_function_values_for_render(object_index, widget_functions); animation.colors = object->object.outgoing_change_colors; - animation.values = object->object.outgoing_function_values; + animation.values = widget_functions; widgets_render(object_index, data->lighting, &animation); }